diff options
author | Colin Cross <ccross@android.com> | 2018-02-28 16:19:41 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2018-02-28 16:21:03 -0800 |
commit | bb7dab15c8f2839694a4ced717ea2102e9a5b2a1 (patch) | |
tree | 01bd432e31d7cf56674aa9b4f2b00ed315386305 /darwin-x86 | |
parent | 9396a3bdcaea77fc7e633b79fad487f76954e90d (diff) | |
download | jdk8-bb7dab15c8f2839694a4ced717ea2102e9a5b2a1.tar.gz |
Switch to JDK build 1.8.0_152-android-4343112-1android-wear-p-preview-2android-p-preview-5android-p-preview-4android-p-preview-3android-p-preview-2android-p-preview-1android-o-mr1-iot-release-1.0.2android-o-mr1-iot-release-1.0.1android-o-mr1-iot-release-1.0.0android-o-mr1-iot-preview-8android-o-mr1-iot-preview-7o-mr1-iot-preview-8o-mr1-iot-preview-7
Test: m EXPERIMENTAL_USE_OPENJDK9=false checkbuild
Test: prebuilts/devtools/tools/ddms on mac
Change-Id: Ib6f865809430e56b788d6e0f4437fb8d603343d0
Diffstat (limited to 'darwin-x86')
266 files changed, 25388 insertions, 41 deletions
diff --git a/darwin-x86/bin/appletviewer b/darwin-x86/bin/appletviewer Binary files differindex 333753e..6725f56 100755 --- a/darwin-x86/bin/appletviewer +++ b/darwin-x86/bin/appletviewer diff --git a/darwin-x86/bin/extcheck b/darwin-x86/bin/extcheck Binary files differindex d18ef4e..9d25496 100755 --- a/darwin-x86/bin/extcheck +++ b/darwin-x86/bin/extcheck diff --git a/darwin-x86/bin/idlj b/darwin-x86/bin/idlj Binary files differindex 00b6703..a7df061 100755 --- a/darwin-x86/bin/idlj +++ b/darwin-x86/bin/idlj diff --git a/darwin-x86/bin/jar b/darwin-x86/bin/jar Binary files differindex f33de87..20975c8 100755 --- a/darwin-x86/bin/jar +++ b/darwin-x86/bin/jar diff --git a/darwin-x86/bin/jarsigner b/darwin-x86/bin/jarsigner Binary files differindex b057531..fe42a7d 100755 --- a/darwin-x86/bin/jarsigner +++ b/darwin-x86/bin/jarsigner diff --git a/darwin-x86/bin/java b/darwin-x86/bin/java Binary files differindex 8bfdf5a..886384d 100755 --- a/darwin-x86/bin/java +++ b/darwin-x86/bin/java diff --git a/darwin-x86/bin/javac b/darwin-x86/bin/javac Binary files differindex 11d387f..68fd891 100755 --- a/darwin-x86/bin/javac +++ b/darwin-x86/bin/javac diff --git a/darwin-x86/bin/javadoc b/darwin-x86/bin/javadoc Binary files differindex 9ed9959..4250d2d 100755 --- a/darwin-x86/bin/javadoc +++ b/darwin-x86/bin/javadoc diff --git a/darwin-x86/bin/javah b/darwin-x86/bin/javah Binary files differindex 0f9716e..ad8bf02 100755 --- a/darwin-x86/bin/javah +++ b/darwin-x86/bin/javah diff --git a/darwin-x86/bin/javap b/darwin-x86/bin/javap Binary files differindex 8e487bd..e734adc 100755 --- a/darwin-x86/bin/javap +++ b/darwin-x86/bin/javap diff --git a/darwin-x86/bin/jcmd b/darwin-x86/bin/jcmd Binary files differindex d142c68..2df1ed2 100755 --- a/darwin-x86/bin/jcmd +++ b/darwin-x86/bin/jcmd diff --git a/darwin-x86/bin/jconsole b/darwin-x86/bin/jconsole Binary files differindex cf99224..c52b4f4 100755 --- a/darwin-x86/bin/jconsole +++ b/darwin-x86/bin/jconsole diff --git a/darwin-x86/bin/jdb b/darwin-x86/bin/jdb Binary files differindex e15f0e6..10aac4e 100755 --- a/darwin-x86/bin/jdb +++ b/darwin-x86/bin/jdb diff --git a/darwin-x86/bin/jdeps b/darwin-x86/bin/jdeps Binary files differindex 8b3c622..27b85d5 100755 --- a/darwin-x86/bin/jdeps +++ b/darwin-x86/bin/jdeps diff --git a/darwin-x86/bin/jhat b/darwin-x86/bin/jhat Binary files differindex 10fb724..77f97ed 100755 --- a/darwin-x86/bin/jhat +++ b/darwin-x86/bin/jhat diff --git a/darwin-x86/bin/jinfo b/darwin-x86/bin/jinfo Binary files differindex 9565f4c..edb7e55 100755 --- a/darwin-x86/bin/jinfo +++ b/darwin-x86/bin/jinfo diff --git a/darwin-x86/bin/jjs b/darwin-x86/bin/jjs Binary files differindex 130e6c6..2fe6f47 100755 --- a/darwin-x86/bin/jjs +++ b/darwin-x86/bin/jjs diff --git a/darwin-x86/bin/jmap b/darwin-x86/bin/jmap Binary files differindex 7ac011e..8511322 100755 --- a/darwin-x86/bin/jmap +++ b/darwin-x86/bin/jmap diff --git a/darwin-x86/bin/jps b/darwin-x86/bin/jps Binary files differindex 3b31702..c2f4670 100755 --- a/darwin-x86/bin/jps +++ b/darwin-x86/bin/jps diff --git a/darwin-x86/bin/jrunscript b/darwin-x86/bin/jrunscript Binary files differindex 9de88fd..b6e7d97 100755 --- a/darwin-x86/bin/jrunscript +++ b/darwin-x86/bin/jrunscript diff --git a/darwin-x86/bin/jsadebugd b/darwin-x86/bin/jsadebugd Binary files differindex 365e384..a205ebe 100755 --- a/darwin-x86/bin/jsadebugd +++ b/darwin-x86/bin/jsadebugd diff --git a/darwin-x86/bin/jstack b/darwin-x86/bin/jstack Binary files differindex 94adb61..c7b9cad 100755 --- a/darwin-x86/bin/jstack +++ b/darwin-x86/bin/jstack diff --git a/darwin-x86/bin/jstat b/darwin-x86/bin/jstat Binary files differindex cdc3c01..9bda6dc 100755 --- a/darwin-x86/bin/jstat +++ b/darwin-x86/bin/jstat diff --git a/darwin-x86/bin/jstatd b/darwin-x86/bin/jstatd Binary files differindex ef65958..7fe1738 100755 --- a/darwin-x86/bin/jstatd +++ b/darwin-x86/bin/jstatd diff --git a/darwin-x86/bin/keytool b/darwin-x86/bin/keytool Binary files differindex 38423c4..f33144f 100755 --- a/darwin-x86/bin/keytool +++ b/darwin-x86/bin/keytool diff --git a/darwin-x86/bin/native2ascii b/darwin-x86/bin/native2ascii Binary files differindex ae36417..40a8c9d 100755 --- a/darwin-x86/bin/native2ascii +++ b/darwin-x86/bin/native2ascii diff --git a/darwin-x86/bin/orbd b/darwin-x86/bin/orbd Binary files differindex e1fcc76..f00cef6 100755 --- a/darwin-x86/bin/orbd +++ b/darwin-x86/bin/orbd diff --git a/darwin-x86/bin/pack200 b/darwin-x86/bin/pack200 Binary files differindex a537337..726cca5 100755 --- a/darwin-x86/bin/pack200 +++ b/darwin-x86/bin/pack200 diff --git a/darwin-x86/bin/policytool b/darwin-x86/bin/policytool Binary files differindex 5c6c1c9..7f23ef1 100755 --- a/darwin-x86/bin/policytool +++ b/darwin-x86/bin/policytool diff --git a/darwin-x86/bin/rmic b/darwin-x86/bin/rmic Binary files differindex c59f4f2..6af4cf0 100755 --- a/darwin-x86/bin/rmic +++ b/darwin-x86/bin/rmic diff --git a/darwin-x86/bin/rmid b/darwin-x86/bin/rmid Binary files differindex 629849e..b572dd0 100755 --- a/darwin-x86/bin/rmid +++ b/darwin-x86/bin/rmid diff --git a/darwin-x86/bin/rmiregistry b/darwin-x86/bin/rmiregistry Binary files differindex eb411de..78ebf2c 100755 --- a/darwin-x86/bin/rmiregistry +++ b/darwin-x86/bin/rmiregistry diff --git a/darwin-x86/bin/schemagen b/darwin-x86/bin/schemagen Binary files differindex a48aa45..2057dcd 100755 --- a/darwin-x86/bin/schemagen +++ b/darwin-x86/bin/schemagen diff --git a/darwin-x86/bin/serialver b/darwin-x86/bin/serialver Binary files differindex d3b80e1..f0f2b05 100755 --- a/darwin-x86/bin/serialver +++ b/darwin-x86/bin/serialver diff --git a/darwin-x86/bin/servertool b/darwin-x86/bin/servertool Binary files differindex af12e53..d273d86 100755 --- a/darwin-x86/bin/servertool +++ b/darwin-x86/bin/servertool diff --git a/darwin-x86/bin/tnameserv b/darwin-x86/bin/tnameserv Binary files differindex dc5af76..e516c42 100755 --- a/darwin-x86/bin/tnameserv +++ b/darwin-x86/bin/tnameserv diff --git a/darwin-x86/bin/unpack200 b/darwin-x86/bin/unpack200 Binary files differindex dca8c4b..e72457c 100755 --- a/darwin-x86/bin/unpack200 +++ b/darwin-x86/bin/unpack200 diff --git a/darwin-x86/bin/wsgen b/darwin-x86/bin/wsgen Binary files differindex f4fac59..7bf7c12 100755 --- a/darwin-x86/bin/wsgen +++ b/darwin-x86/bin/wsgen diff --git a/darwin-x86/bin/wsimport b/darwin-x86/bin/wsimport Binary files differindex 1d1a238..5c07119 100755 --- a/darwin-x86/bin/wsimport +++ b/darwin-x86/bin/wsimport diff --git a/darwin-x86/bin/xjc b/darwin-x86/bin/xjc Binary files differindex 04bcea0..ca92a4c 100755 --- a/darwin-x86/bin/xjc +++ b/darwin-x86/bin/xjc diff --git a/darwin-x86/jre/bin/java b/darwin-x86/jre/bin/java Binary files differindex 8bfdf5a..886384d 100755 --- a/darwin-x86/jre/bin/java +++ b/darwin-x86/jre/bin/java diff --git a/darwin-x86/jre/bin/jjs b/darwin-x86/jre/bin/jjs Binary files differindex 130e6c6..2fe6f47 100755 --- a/darwin-x86/jre/bin/jjs +++ b/darwin-x86/jre/bin/jjs diff --git a/darwin-x86/jre/bin/keytool b/darwin-x86/jre/bin/keytool Binary files differindex 38423c4..f33144f 100755 --- a/darwin-x86/jre/bin/keytool +++ b/darwin-x86/jre/bin/keytool diff --git a/darwin-x86/jre/bin/orbd b/darwin-x86/jre/bin/orbd Binary files differindex e1fcc76..f00cef6 100755 --- a/darwin-x86/jre/bin/orbd +++ b/darwin-x86/jre/bin/orbd diff --git a/darwin-x86/jre/bin/pack200 b/darwin-x86/jre/bin/pack200 Binary files differindex a537337..726cca5 100755 --- a/darwin-x86/jre/bin/pack200 +++ b/darwin-x86/jre/bin/pack200 diff --git a/darwin-x86/jre/bin/policytool b/darwin-x86/jre/bin/policytool Binary files differindex 5c6c1c9..7f23ef1 100755 --- a/darwin-x86/jre/bin/policytool +++ b/darwin-x86/jre/bin/policytool diff --git a/darwin-x86/jre/bin/rmid b/darwin-x86/jre/bin/rmid Binary files differindex 629849e..b572dd0 100755 --- a/darwin-x86/jre/bin/rmid +++ b/darwin-x86/jre/bin/rmid diff --git a/darwin-x86/jre/bin/rmiregistry b/darwin-x86/jre/bin/rmiregistry Binary files differindex eb411de..78ebf2c 100755 --- a/darwin-x86/jre/bin/rmiregistry +++ b/darwin-x86/jre/bin/rmiregistry diff --git a/darwin-x86/jre/bin/servertool b/darwin-x86/jre/bin/servertool Binary files differindex af12e53..d273d86 100755 --- a/darwin-x86/jre/bin/servertool +++ b/darwin-x86/jre/bin/servertool diff --git a/darwin-x86/jre/bin/tnameserv b/darwin-x86/jre/bin/tnameserv Binary files differindex dc5af76..e516c42 100755 --- a/darwin-x86/jre/bin/tnameserv +++ b/darwin-x86/jre/bin/tnameserv diff --git a/darwin-x86/jre/bin/unpack200 b/darwin-x86/jre/bin/unpack200 Binary files differindex dca8c4b..e72457c 100755 --- a/darwin-x86/jre/bin/unpack200 +++ b/darwin-x86/jre/bin/unpack200 diff --git a/darwin-x86/jre/lib/charsets.jar b/darwin-x86/jre/lib/charsets.jar Binary files differindex 14c7889..26c548c 100644 --- a/darwin-x86/jre/lib/charsets.jar +++ b/darwin-x86/jre/lib/charsets.jar diff --git a/darwin-x86/jre/lib/ext/nashorn.jar b/darwin-x86/jre/lib/ext/nashorn.jar Binary files differindex e735c69..ed912c4 100644 --- a/darwin-x86/jre/lib/ext/nashorn.jar +++ b/darwin-x86/jre/lib/ext/nashorn.jar diff --git a/darwin-x86/jre/lib/jce.jar b/darwin-x86/jre/lib/jce.jar Binary files differindex 7556a27..16eb259 100644 --- a/darwin-x86/jre/lib/jce.jar +++ b/darwin-x86/jre/lib/jce.jar diff --git a/darwin-x86/jre/lib/jli/libjli.dylib b/darwin-x86/jre/lib/jli/libjli.dylib Binary files differindex 131cec8..9c4e007 100755 --- a/darwin-x86/jre/lib/jli/libjli.dylib +++ b/darwin-x86/jre/lib/jli/libjli.dylib diff --git a/darwin-x86/jre/lib/jspawnhelper b/darwin-x86/jre/lib/jspawnhelper Binary files differindex 2607e9d..bc53767 100755 --- a/darwin-x86/jre/lib/jspawnhelper +++ b/darwin-x86/jre/lib/jspawnhelper diff --git a/darwin-x86/jre/lib/jsse.jar b/darwin-x86/jre/lib/jsse.jar Binary files differindex fd3bfcc..eb0a1b8 100644 --- a/darwin-x86/jre/lib/jsse.jar +++ b/darwin-x86/jre/lib/jsse.jar diff --git a/darwin-x86/jre/lib/libAppleScriptEngine.dylib b/darwin-x86/jre/lib/libAppleScriptEngine.dylib Binary files differindex 75e0809..600c948 100755 --- a/darwin-x86/jre/lib/libAppleScriptEngine.dylib +++ b/darwin-x86/jre/lib/libAppleScriptEngine.dylib diff --git a/darwin-x86/jre/lib/libattach.dylib b/darwin-x86/jre/lib/libattach.dylib Binary files differindex 4197c07..45fa97a 100755 --- a/darwin-x86/jre/lib/libattach.dylib +++ b/darwin-x86/jre/lib/libattach.dylib diff --git a/darwin-x86/jre/lib/libawt.dylib b/darwin-x86/jre/lib/libawt.dylib Binary files differindex 2a782d7..2b28a0d 100755 --- a/darwin-x86/jre/lib/libawt.dylib +++ b/darwin-x86/jre/lib/libawt.dylib diff --git a/darwin-x86/jre/lib/libawt_lwawt.dylib b/darwin-x86/jre/lib/libawt_lwawt.dylib Binary files differindex 637db99..a56c6e6 100755 --- a/darwin-x86/jre/lib/libawt_lwawt.dylib +++ b/darwin-x86/jre/lib/libawt_lwawt.dylib diff --git a/darwin-x86/jre/lib/libdt_socket.dylib b/darwin-x86/jre/lib/libdt_socket.dylib Binary files differindex 60f8995..9c01176 100755 --- a/darwin-x86/jre/lib/libdt_socket.dylib +++ b/darwin-x86/jre/lib/libdt_socket.dylib diff --git a/darwin-x86/jre/lib/libfontmanager.dylib b/darwin-x86/jre/lib/libfontmanager.dylib Binary files differindex e9ed3ce..707aacf 100755 --- a/darwin-x86/jre/lib/libfontmanager.dylib +++ b/darwin-x86/jre/lib/libfontmanager.dylib diff --git a/darwin-x86/jre/lib/libfreetype.dylib.6 b/darwin-x86/jre/lib/libfreetype.dylib.6 Binary files differindex b93137f..990c2ba 100755 --- a/darwin-x86/jre/lib/libfreetype.dylib.6 +++ b/darwin-x86/jre/lib/libfreetype.dylib.6 diff --git a/darwin-x86/jre/lib/libhprof.dylib b/darwin-x86/jre/lib/libhprof.dylib Binary files differindex 33c8f63..ccee50a 100755 --- a/darwin-x86/jre/lib/libhprof.dylib +++ b/darwin-x86/jre/lib/libhprof.dylib diff --git a/darwin-x86/jre/lib/libinstrument.dylib b/darwin-x86/jre/lib/libinstrument.dylib Binary files differindex 1c28e0b..87e5eda 100755 --- a/darwin-x86/jre/lib/libinstrument.dylib +++ b/darwin-x86/jre/lib/libinstrument.dylib diff --git a/darwin-x86/jre/lib/libj2gss.dylib b/darwin-x86/jre/lib/libj2gss.dylib Binary files differindex 13a0233..fcffdde 100755 --- a/darwin-x86/jre/lib/libj2gss.dylib +++ b/darwin-x86/jre/lib/libj2gss.dylib diff --git a/darwin-x86/jre/lib/libj2pcsc.dylib b/darwin-x86/jre/lib/libj2pcsc.dylib Binary files differindex 7b3cae9..856ecfc 100755 --- a/darwin-x86/jre/lib/libj2pcsc.dylib +++ b/darwin-x86/jre/lib/libj2pcsc.dylib diff --git a/darwin-x86/jre/lib/libj2pkcs11.dylib b/darwin-x86/jre/lib/libj2pkcs11.dylib Binary files differindex 2867d53..f7d5251 100755 --- a/darwin-x86/jre/lib/libj2pkcs11.dylib +++ b/darwin-x86/jre/lib/libj2pkcs11.dylib diff --git a/darwin-x86/jre/lib/libjaas_unix.dylib b/darwin-x86/jre/lib/libjaas_unix.dylib Binary files differindex 3b166d2..d17f676 100755 --- a/darwin-x86/jre/lib/libjaas_unix.dylib +++ b/darwin-x86/jre/lib/libjaas_unix.dylib diff --git a/darwin-x86/jre/lib/libjava.dylib b/darwin-x86/jre/lib/libjava.dylib Binary files differindex 0685268..b32cdff 100755 --- a/darwin-x86/jre/lib/libjava.dylib +++ b/darwin-x86/jre/lib/libjava.dylib diff --git a/darwin-x86/jre/lib/libjava_crw_demo.dylib b/darwin-x86/jre/lib/libjava_crw_demo.dylib Binary files differindex 5cada36..ac4ea80 100755 --- a/darwin-x86/jre/lib/libjava_crw_demo.dylib +++ b/darwin-x86/jre/lib/libjava_crw_demo.dylib diff --git a/darwin-x86/jre/lib/libjawt.dylib b/darwin-x86/jre/lib/libjawt.dylib Binary files differindex 5c10806..6aeb3fe 100755 --- a/darwin-x86/jre/lib/libjawt.dylib +++ b/darwin-x86/jre/lib/libjawt.dylib diff --git a/darwin-x86/jre/lib/libjdwp.dylib b/darwin-x86/jre/lib/libjdwp.dylib Binary files differindex a0ee225..24ccd78 100755 --- a/darwin-x86/jre/lib/libjdwp.dylib +++ b/darwin-x86/jre/lib/libjdwp.dylib diff --git a/darwin-x86/jre/lib/libjpeg.dylib b/darwin-x86/jre/lib/libjpeg.dylib Binary files differindex 1e4607c..fb53c86 100755 --- a/darwin-x86/jre/lib/libjpeg.dylib +++ b/darwin-x86/jre/lib/libjpeg.dylib diff --git a/darwin-x86/jre/lib/libjsdt.dylib b/darwin-x86/jre/lib/libjsdt.dylib Binary files differindex 65140d4..6db259c 100755 --- a/darwin-x86/jre/lib/libjsdt.dylib +++ b/darwin-x86/jre/lib/libjsdt.dylib diff --git a/darwin-x86/jre/lib/libjsig.dylib b/darwin-x86/jre/lib/libjsig.dylib Binary files differindex 7704f4f..4e3633c 100755 --- a/darwin-x86/jre/lib/libjsig.dylib +++ b/darwin-x86/jre/lib/libjsig.dylib diff --git a/darwin-x86/jre/lib/libjsound.dylib b/darwin-x86/jre/lib/libjsound.dylib Binary files differindex 5f0a769..2bdae90 100755 --- a/darwin-x86/jre/lib/libjsound.dylib +++ b/darwin-x86/jre/lib/libjsound.dylib diff --git a/darwin-x86/jre/lib/liblcms.dylib b/darwin-x86/jre/lib/liblcms.dylib Binary files differindex 2569f89..31fcea0 100755 --- a/darwin-x86/jre/lib/liblcms.dylib +++ b/darwin-x86/jre/lib/liblcms.dylib diff --git a/darwin-x86/jre/lib/libmanagement.dylib b/darwin-x86/jre/lib/libmanagement.dylib Binary files differindex 797b65b..6516eb7 100755 --- a/darwin-x86/jre/lib/libmanagement.dylib +++ b/darwin-x86/jre/lib/libmanagement.dylib diff --git a/darwin-x86/jre/lib/libmlib_image.dylib b/darwin-x86/jre/lib/libmlib_image.dylib Binary files differindex 54ce006..1a3e352 100755 --- a/darwin-x86/jre/lib/libmlib_image.dylib +++ b/darwin-x86/jre/lib/libmlib_image.dylib diff --git a/darwin-x86/jre/lib/libnet.dylib b/darwin-x86/jre/lib/libnet.dylib Binary files differindex b1edc51..6649bdb 100755 --- a/darwin-x86/jre/lib/libnet.dylib +++ b/darwin-x86/jre/lib/libnet.dylib diff --git a/darwin-x86/jre/lib/libnio.dylib b/darwin-x86/jre/lib/libnio.dylib Binary files differindex 11e30d2..9dd100a 100755 --- a/darwin-x86/jre/lib/libnio.dylib +++ b/darwin-x86/jre/lib/libnio.dylib diff --git a/darwin-x86/jre/lib/libnpt.dylib b/darwin-x86/jre/lib/libnpt.dylib Binary files differindex 49b08bf..5b05a4a 100755 --- a/darwin-x86/jre/lib/libnpt.dylib +++ b/darwin-x86/jre/lib/libnpt.dylib diff --git a/darwin-x86/jre/lib/libosx.dylib b/darwin-x86/jre/lib/libosx.dylib Binary files differindex bfe9849..1662548 100755 --- a/darwin-x86/jre/lib/libosx.dylib +++ b/darwin-x86/jre/lib/libosx.dylib diff --git a/darwin-x86/jre/lib/libosxapp.dylib b/darwin-x86/jre/lib/libosxapp.dylib Binary files differindex c31a2da..d177f70 100755 --- a/darwin-x86/jre/lib/libosxapp.dylib +++ b/darwin-x86/jre/lib/libosxapp.dylib diff --git a/darwin-x86/jre/lib/libosxkrb5.dylib b/darwin-x86/jre/lib/libosxkrb5.dylib Binary files differindex 6553679..04f22fb 100755 --- a/darwin-x86/jre/lib/libosxkrb5.dylib +++ b/darwin-x86/jre/lib/libosxkrb5.dylib diff --git a/darwin-x86/jre/lib/libosxui.dylib b/darwin-x86/jre/lib/libosxui.dylib Binary files differindex a359309..332a3d2 100755 --- a/darwin-x86/jre/lib/libosxui.dylib +++ b/darwin-x86/jre/lib/libosxui.dylib diff --git a/darwin-x86/jre/lib/libsaproc.dylib b/darwin-x86/jre/lib/libsaproc.dylib Binary files differindex df366ae..d86203e 100755 --- a/darwin-x86/jre/lib/libsaproc.dylib +++ b/darwin-x86/jre/lib/libsaproc.dylib diff --git a/darwin-x86/jre/lib/libsplashscreen.dylib b/darwin-x86/jre/lib/libsplashscreen.dylib Binary files differindex 6295ba0..3994d09 100755 --- a/darwin-x86/jre/lib/libsplashscreen.dylib +++ b/darwin-x86/jre/lib/libsplashscreen.dylib diff --git a/darwin-x86/jre/lib/libsunec.dylib b/darwin-x86/jre/lib/libsunec.dylib Binary files differindex fbf0453..16a9a6e 100755 --- a/darwin-x86/jre/lib/libsunec.dylib +++ b/darwin-x86/jre/lib/libsunec.dylib diff --git a/darwin-x86/jre/lib/libunpack.dylib b/darwin-x86/jre/lib/libunpack.dylib Binary files differindex b751801..06d4523 100755 --- a/darwin-x86/jre/lib/libunpack.dylib +++ b/darwin-x86/jre/lib/libunpack.dylib diff --git a/darwin-x86/jre/lib/libverify.dylib b/darwin-x86/jre/lib/libverify.dylib Binary files differindex fcd204c..ddc4e10 100755 --- a/darwin-x86/jre/lib/libverify.dylib +++ b/darwin-x86/jre/lib/libverify.dylib diff --git a/darwin-x86/jre/lib/libzip.dylib b/darwin-x86/jre/lib/libzip.dylib Binary files differindex c6a759e..1b0e053 100755 --- a/darwin-x86/jre/lib/libzip.dylib +++ b/darwin-x86/jre/lib/libzip.dylib diff --git a/darwin-x86/jre/lib/resources.jar b/darwin-x86/jre/lib/resources.jar Binary files differindex 36e7ed3..289cf9d 100644 --- a/darwin-x86/jre/lib/resources.jar +++ b/darwin-x86/jre/lib/resources.jar diff --git a/darwin-x86/jre/lib/rt.jar b/darwin-x86/jre/lib/rt.jar Binary files differindex 1b234fd..d7f6474 100644 --- a/darwin-x86/jre/lib/rt.jar +++ b/darwin-x86/jre/lib/rt.jar diff --git a/darwin-x86/jre/lib/security/java.security b/darwin-x86/jre/lib/security/java.security index 30ef845..2a08b6f 100644 --- a/darwin-x86/jre/lib/security/java.security +++ b/darwin-x86/jre/lib/security/java.security @@ -736,67 +736,70 @@ jdk.tls.legacyAlgorithms= \ # Cryptographic Jurisdiction Policy defaults # -# Due to the import control restrictions of some countries, the default -# JCE policy files allow for strong but "limited" cryptographic key -# lengths to be used. If your country's cryptographic regulations allow, -# the "unlimited" strength policy files can be used instead, which contain -# no restrictions on cryptographic strengths. +# Import and export control rules on cryptographic software vary from +# country to country. By default, the JDK provides two different sets of +# cryptographic policy files: # -# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY -# TO DETERMINE THE EXACT REQUIREMENTS. +# unlimited: These policy files contain no restrictions on cryptographic +# strengths or algorithms. # -# <java-home> (below) refers to the directory where the JRE was -# installed. It is determined based on whether you are running JCE -# on a JRE or a JRE contained within the Java Development Kit, or -# JDK(TM). The JDK contains the JRE, but at a different level in the -# file hierarchy. For example, if the JDK is installed in -# /home/user1/jdk1.8.0 on Unix or in C:\jdk1.8.0 on Windows, then -# <java-home> is: +# limited: These policy files contain more restricted cryptographic +# strengths, and are still available if your country or +# usage requires the traditional restrictive policy. # -# /home/user1/jdk1.8.0/jre [Unix] -# C:\jdk1.8.0\jre [Windows] +# The JDK JCE framework uses the unlimited policy files by default. +# However the user may explicitly choose a set either by defining the +# "crypto.policy" Security property or by installing valid JCE policy +# jar files into the traditional JDK installation location. To better +# support older JDK Update releases, the "crypto.policy" property is not +# defined by default. See below for more information. # -# If on the other hand the JRE is installed in /home/user1/jre1.8.0 -# on Unix or in C:\jre1.8.0 on Windows, and the JDK is not -# installed, then <java-home> is: +# The following logic determines which policy files are used: # -# /home/user1/jre1.8.0 [Unix] -# C:\jre1.8.0 [Windows] +# <java-home> refers to the directory where the JRE was +# installed and may be determined using the "java.home" +# System property. # -# On Windows, for each JDK installation, there may be additional -# JREs installed under the "Program Files" directory. Please make -# sure that you install the unlimited strength policy JAR files -# for all JREs that you plan to use. +# 1. If the Security property "crypto.policy" has been defined, +# then the following mechanism is used: # -# The policy files are jar files organized into subdirectories of +# The policy files are stored as jar files in subdirectories of # <java-home>/lib/security/policy. Each directory contains a complete # set of policy files. # -# The "crypto.policy" Security property controls the directory selection, -# and thus the effective cryptographic policy. +# The "crypto.policy" Security property controls the directory +# selection, and thus the effective cryptographic policy. # # The default set of directories is: # # limited | unlimited # -# however other directories can be created and configured. -# -# To support older JDK Update releases, the crypto.policy property -# is not defined by default. When the property is not defined, an -# update release binary aware of the new property will use the following -# logic to decide what crypto policy files get used : -# -# * If the US_export_policy.jar and local_policy.jar files are located -# in the (legacy) <java-home>/lib/security directory, then the rules -# embedded in those jar files will be used. This helps preserve compatibility +# 2. If the "crypto.policy" property is not set and the traditional +# US_export_policy.jar and local_policy.jar files +# (e.g. limited/unlimited) are found in the legacy +# <java-home>/lib/security directory, then the rules embedded within +# those jar files will be used. This helps preserve compatibility # for users upgrading from an older installation. # -# * If crypto.policy is not defined and no such jar files are present in -# the legacy locations, then the JDK will use the limited settings -# (equivalent to crypto.policy=limited) +# 3. If the jar files are not present in the legacy location +# and the "crypto.policy" Security property is not defined, +# then the JDK will use the unlimited settings (equivalent to +# crypto.policy=unlimited) # # Please see the JCA documentation for additional information on these # files and formats. +# +# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY +# TO DETERMINE THE EXACT REQUIREMENTS. +# +# Please note that the JCE for Java SE, including the JCE framework, +# cryptographic policy files, and standard JCE providers provided with +# the Java SE, have been reviewed and approved for export as mass market +# encryption item by the US Bureau of Industry and Security. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# #crypto.policy=unlimited # diff --git a/darwin-x86/jre/lib/server/libjsig.dylib b/darwin-x86/jre/lib/server/libjsig.dylib Binary files differindex 7704f4f..4e3633c 100755 --- a/darwin-x86/jre/lib/server/libjsig.dylib +++ b/darwin-x86/jre/lib/server/libjsig.dylib diff --git a/darwin-x86/jre/lib/server/libjvm.dylib b/darwin-x86/jre/lib/server/libjvm.dylib Binary files differindex 1da3832..03fc9e4 100755 --- a/darwin-x86/jre/lib/server/libjvm.dylib +++ b/darwin-x86/jre/lib/server/libjvm.dylib diff --git a/darwin-x86/lib/ct.sym b/darwin-x86/lib/ct.sym Binary files differindex a4a0e58..7791820 100644 --- a/darwin-x86/lib/ct.sym +++ b/darwin-x86/lib/ct.sym diff --git a/darwin-x86/lib/jconsole.jar b/darwin-x86/lib/jconsole.jar Binary files differindex a25d502..c301a7e 100644 --- a/darwin-x86/lib/jconsole.jar +++ b/darwin-x86/lib/jconsole.jar diff --git a/darwin-x86/lib/sa-jdi.jar b/darwin-x86/lib/sa-jdi.jar Binary files differindex 97ebf83..e91c217 100644 --- a/darwin-x86/lib/sa-jdi.jar +++ b/darwin-x86/lib/sa-jdi.jar diff --git a/darwin-x86/lib/tools.jar b/darwin-x86/lib/tools.jar Binary files differindex 462c900..e45b586 100644 --- a/darwin-x86/lib/tools.jar +++ b/darwin-x86/lib/tools.jar diff --git a/darwin-x86/sample/README b/darwin-x86/sample/README new file mode 100644 index 0000000..ae56b64 --- /dev/null +++ b/darwin-x86/sample/README @@ -0,0 +1,6 @@ +The source code provided with samples and demos for the JDK is meant +to illustrate the usage of a given feature or technique and has been +deliberately simplified. Additional steps required for a +production-quality application, such as security checks, input +validation, and proper error handling, might not be present in the +sample code. diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Device.java b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Device.java new file mode 100644 index 0000000..f4fd2c5 --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Device.java @@ -0,0 +1,66 @@ +package checker; + +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; + +/** + * Represents the device configuration. The values are loaded from an XML file by JAXB. + */ +@XmlRootElement +public class Device { + + @XmlElement() + private Map<Module, Integer> supportedModules = new EnumMap<>(Module.class); + + /** + * Returns map of supported modules. The map key is module. The map value is version. + * + * @return map of supported modules. + */ + public Map<Module, Integer> getSupportedModules() { + return Collections.unmodifiableMap(supportedModules); + } +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Kettle.xml b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Kettle.xml new file mode 100644 index 0000000..2e0357d --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Kettle.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ Copyright (c) 2014, 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.
+
+
+
+ This source code is provided to illustrate the usage of a given feature
+ or technique and has been deliberately simplified. Additional steps
+ required for a production-quality application, such as security checks,
+ input validation and proper error handling, might not be present in
+ this sample code.
+
+ -->
+
+<device>
+ <supportedModules>
+ <entry>
+ <key>DISPLAY</key>
+ <value>2</value>
+ </entry>
+ <entry>
+ <key>THERMOMETER</key>
+ <value>1</value>
+ </entry>
+ <entry>
+ <key>CLOCK</key>
+ <value>4</value>
+ </entry>
+ </supportedModules>
+</device>
\ No newline at end of file diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Module.java b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Module.java new file mode 100644 index 0000000..2b97b4e --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Module.java @@ -0,0 +1,49 @@ +package checker; + +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +/** + * Represents available modules. + */ +public enum Module { + + DISPLAY, CLOCK, THERMOMETER, HEATER, SPEAKER, GSM, LED; +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/PluginChecker.java b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/PluginChecker.java new file mode 100644 index 0000000..6db5bae --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/PluginChecker.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +package checker; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.xml.bind.JAXBContext; +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.bind.JAXBException; + +/** + * Reads the device configuration from the XML file specified by -Adevice=device.xml. + * For each class in a project, checks required modules. If the device doesn't have + * the required module, then a compilation error will be shown. + */ +@SupportedAnnotationTypes("checker.RequireContainer") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class PluginChecker extends javax.annotation.processing.AbstractProcessor { + + /** + * Name of the option to get the path to the xml with device configuration. + */ + public static final String DEVICE_OPTION = "device"; + private Device device; + + /** + * Only the device option is supported. + * + * {@inheritDoc} + */ + @Override + public Set<String> getSupportedOptions() { + return new HashSet<>(Arrays.asList(DEVICE_OPTION)); + } + + /** + * Initializes the processor by loading the device configuration. + * + * {@inheritDoc} + */ + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + try { + String deviceOption = processingEnv.getOptions().get(DEVICE_OPTION); + device = (Device) JAXBContext.newInstance(Device.class) + .createUnmarshaller().unmarshal(new File(deviceOption)); + } catch (JAXBException e) { + throw new RuntimeException( + "Please specify device by -Adevice=device.xml\n" + + e.toString(), e); + } + } + + /** + * Processes @Require annotations and checks that Device meets requirements. + * + * {@inheritDoc} + */ + @Override + public boolean process(Set<? extends TypeElement> annotations, + RoundEnvironment roundEnv) { + for (Element el : roundEnv.getElementsAnnotatedWith(RequireContainer.class)) { + for (Require req : el.getAnnotationsByType(Require.class)) { + //for every Require annotation checks if device has module of required version. + Integer version = device.getSupportedModules().get(req.value()); + + if (version == null + || version < req.minVersion() + || version > req.maxVersion()) { + //if module is optional then show only warning not error + if (req.optional()) { + processingEnv.getMessager() + .printMessage(Diagnostic.Kind.WARNING, + "Plugin [" + el + "] requires " + req + + "\n but device " + (version == null + ? "doesn't have such module." + + " This module is optional." + + " So plugin will work but miss" + + " some functionality" + : "has " + version + + " version of that module")); + } else { + processingEnv.getMessager() + .printMessage(Diagnostic.Kind.ERROR, + "Plugin [" + el + "] requires " + req + + "\n but device " + + (version == null + ? "doesn't have such module" + : "has " + version + + " version of that module")); + } + } + } + return true; + } + return false; + } +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Require.java b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Require.java new file mode 100644 index 0000000..6681c28 --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/Require.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +package checker; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates that a plug-in depends on a module. + */ +@Retention(RetentionPolicy.CLASS) +@Repeatable(RequireContainer.class) +public @interface Require { + + /** + * Returns the required module. + * + * @return required module. + */ + Module value(); + + /** + * Returns the minimum supported version of a module. + * + * @return minimum supported version of a module. + */ + int minVersion() default 1; + + /** + * Returns the maximum supported version of a module. + * + * @return maximum supported version of a module. + */ + int maxVersion() default Integer.MAX_VALUE; + + /** + * Returns true if a module is optional. A module is optional if a system + * works without that module but is missing some functionality. Returns false if a system + * won't work without the specified module. + * + * @return true if module is optional. False otherwise. + */ + boolean optional() default false; +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/RequireContainer.java b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/RequireContainer.java new file mode 100644 index 0000000..d18e0d5 --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/PluginChecker/src/checker/RequireContainer.java @@ -0,0 +1,51 @@ +package checker; + +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A container for the repeatable @Require annotation. + */ +@Retention(RetentionPolicy.CLASS) +public @interface RequireContainer { + + Require[] value(); +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/BoilerPlugin.java b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/BoilerPlugin.java new file mode 100644 index 0000000..3a9d842 --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/BoilerPlugin.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +package plugins; + +import checker.Module; +import checker.Require; + +/** + * BoilerPlugin provides support for boiling water and keeping water warm. + */ +@Require(value = Module.CLOCK, maxVersion = 3) +@Require(value = Module.THERMOMETER) +@Require(value = Module.HEATER) +@Require(value = Module.LED, optional = true) //will use if present +public class BoilerPlugin { + + /** + * Heats water up to 100 degrees Celsius. + */ + public void boil() { + boil(100); + } + + /** + * Heats water up to temperature. + * + * @param temperature - desired temperature of the water in the boiler + */ + public void boil(int temperature) { + /* + * Turn on heater and wait while temperature reaches desired temperature + * in Celsius. Finally, turn off heater. + * If present, the LED light changes color according to the temperature. + */ + } + + /** + * Keeps desired temperature. + * + * @param temperature - desired temperature of the water in the boiler + * @param seconds - period of time for checking temperature in seconds + */ + public void keepWarm(int temperature, int seconds) { + //Every n seconds check temperature and warm up, if necessary. + } + +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/ExtendedBoilerPlugin.java b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/ExtendedBoilerPlugin.java new file mode 100644 index 0000000..b7be610 --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/ExtendedBoilerPlugin.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +package plugins; + +import checker.Module; +import checker.Require; +import java.util.Calendar; + +/** + * Introduces new features for BoilerPlugin. Features are boiling water by an + * SMS and boiling water by date with notification by a phone call. + */ +@Require(value = Module.SPEAKER) +@Require(value = Module.GSM, minVersion = 3) +@Require(value = Module.DISPLAY) +public class ExtendedBoilerPlugin extends BoilerPlugin { + + /** + * Boils water at the appointed time and wakes you up by a ring and phone + * call. Shows "Good morning" and a quote of the day from the Internet on the + * display. + * + * @param calendar - date and time when water should be boiled + * @param phoneNumber - phone number to call + */ + public void boilAndWakeUp(Calendar calendar, int phoneNumber) { + //implementation + } + + /** + * Boils water at the appointed time by getting an SMS of fixed format. + * Sends an SMS on finish. + * + * @param sms - text of SMS + */ + public void boilBySMS(String sms) { + //implementation + } +} diff --git a/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/TimerPlugin.java b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/TimerPlugin.java new file mode 100644 index 0000000..678785c --- /dev/null +++ b/darwin-x86/sample/annotations/DependencyChecker/Plugins/src/plugins/TimerPlugin.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +package plugins; + +import checker.Module; +import checker.Require; + +/** + * Timer plug-in is used to support an alarm and a timer. It depends on Display and + * Clock modules. + */ +@Require(Module.DISPLAY) +@Require(value = Module.CLOCK, maxVersion = 3) +public class TimerPlugin { + + /** + * Sets timer. + * + * @param time - the remaining time. + */ + public void timer(long time) { + //start timer + //show the remaining time on display + } + + /** + * Sets alarm. + * + * @param time - the alarm time. + */ + public void alarm(long time) { + //start alarm + //show current time and alarm time on display + } +} diff --git a/darwin-x86/sample/annotations/Validator/src/PositiveIntegerSupplier.java b/darwin-x86/sample/annotations/Validator/src/PositiveIntegerSupplier.java new file mode 100644 index 0000000..0a14913 --- /dev/null +++ b/darwin-x86/sample/annotations/Validator/src/PositiveIntegerSupplier.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +import java.util.function.Supplier; + +/** + * Supplies a positive number. + */ +@Validate(value = Validator.INTEGER_NUMBER, + description = "It's not an Integer ") +@Validate(value = Validator.POSITIVE_NUMBER, + description = "It's not a positive Number") +public class PositiveIntegerSupplier implements Supplier<String> { + + /** + * Returns a string representation of a positive integer. + * + * @return string representation of a positive integer. + */ + @Override + public String get() { + return "20005"; //random number + } +} diff --git a/darwin-x86/sample/annotations/Validator/src/SupplierValidator.java b/darwin-x86/sample/annotations/Validator/src/SupplierValidator.java new file mode 100644 index 0000000..479ac86 --- /dev/null +++ b/darwin-x86/sample/annotations/Validator/src/SupplierValidator.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +import javax.xml.bind.ValidationException; +import java.util.function.Supplier; + +/** + * Validates the supplier. + */ +public class SupplierValidator { + + /** + * Validates the supplier. + * + * @param supplier - Supplier that needs to be validated. + * @return true if supplier has passed validation check. False otherwise. + */ + public static boolean validate(Supplier<?> supplier) { + for (Validate annotation + : supplier.getClass().getAnnotationsByType(Validate.class)) { + try { + annotation.value().validate(supplier); + } catch (ValidationException e) { + System.out.println(annotation.description()); + e.printStackTrace(); + return false; + } + } + return true; + } +} diff --git a/darwin-x86/sample/annotations/Validator/src/Validate.java b/darwin-x86/sample/annotations/Validator/src/Validate.java new file mode 100644 index 0000000..e0404ea --- /dev/null +++ b/darwin-x86/sample/annotations/Validator/src/Validate.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates that the class should be validated by the specified validator. + */ +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(ValidateContainer.class) +public @interface Validate { + + /** + * Returns the validator that should validate the annotated class. + * + * @return Validator that should validate annotated class. + */ + Validator value(); + + /** + * Returns text to describe the failure of the validation check. + * + * @return text to describe the failure of the validation check. + */ + String description() default ""; +} + +/** + * A container for the repeatable @Validate annotation. + * + * @author Andrey Nazarov + */ +@Retention(RetentionPolicy.RUNTIME) +@interface ValidateContainer { + + Validate[] value(); +} diff --git a/darwin-x86/sample/annotations/Validator/src/Validator.java b/darwin-x86/sample/annotations/Validator/src/Validator.java new file mode 100644 index 0000000..9e074f5 --- /dev/null +++ b/darwin-x86/sample/annotations/Validator/src/Validator.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ +import javax.xml.bind.ValidationException; +import java.util.function.Supplier; + +/** + * Enum of Validator implementations. + */ +public enum Validator { + + /** + * This validator checks that the string represents an integer. + */ + INTEGER_NUMBER { + /** + * Checks that the string represents an integer. + * + * @param string - a string supplier + * @throws ValidationException if the validation check fails + */ + @Override + void validate(Supplier<?> string) throws ValidationException { + try { + Integer.parseInt((String) string.get()); + } catch (NumberFormatException ex) { + throw new ValidationException("Error while validating " + + string.get()); + } + } + }, + /** + * This validator checks that the string represents a positive number. + */ + POSITIVE_NUMBER { + /** + * Checks that the string represents a positive number. + * + * @param string - an string supplier + * @throws ValidationException if the validation check fails + */ + @Override + void validate(Supplier<?> string) throws ValidationException { + try { + if (Double.compare(0.0, Double.parseDouble( + (String) string.get())) > 0) { + throw new Exception(); + } + } catch (Exception ex) { + throw new ValidationException("Error while validating " + + string.get()); + } + } + }; + + /** + * Checks that the supplier is valid. + * + * @param string - a string supplier + * @throws ValidationException if validation check fails + */ + abstract void validate(Supplier<?> string) throws ValidationException; + +} diff --git a/darwin-x86/sample/annotations/index.html b/darwin-x86/sample/annotations/index.html new file mode 100644 index 0000000..804c83d --- /dev/null +++ b/darwin-x86/sample/annotations/index.html @@ -0,0 +1,67 @@ +<!DOCTYPE html>
+<html>
+<head>
+ <title>Repeating Annotations Demo</title>
+</head>
+<body>
+<h2>Repeating Annotations Demo</h2>
+
+<p>
+ This demo shows how to use repeating annotations at runtime and at compile time.
+</p>
+
+<ul>
+ <li><h3>Dependency checker.</h3>
+
+ <p>
+ Shows how to define repeating annotations and process them at compile time.
+ The problem domain is some code that performs useful operations on hardware devices.
+ The code relies on "modules" to be present on the devices. Applicability of the code to a particular
+ device is checked while compiling the code for a particular device.
+ A set of modules provided by a device is listed in an xml file that turns red during the compilation
+ phase and is compared with the required module set specified by annotations.
+ For instance, there is kettle with hardware modules: thermometer, display, and clock.
+ There is also a boiler plug-in that requires clock, thermometer, heater, and optionally an LED light.
+
+ Build the PluginChecker annotation processor first.
+ Then, run javac with the annotation processor against plug-in sources using the following command: </p>
+
+ <code>javac -cp "PluginChecker.jar" -processor checker.PluginChecker -Adevice=Kettle.xml -proc:only <source
+ files></code>
+
+ <p>
+ where <code>PluginChecker.jar</code> - path to jar file that contains PluginChecker annotation processor
+ class. </br>
+ <code>Kettle.xml</code> - path to device descriptor Kettle.xml </br>
+ <code><source files></code> - source files in Plugins/src
+ </p>
+ For more information, see the source files.
+ </p>
+ <ul>
+ <li>Annotation processor sources: <a href="DependencyChecker/PluginChecker/src/">DependencyChecker/PluginChecker/src</a>
+ <li>Processing of repeating annotations can be found in <a href="DependencyChecker/PluginChecker/src/checker/PluginChecker.java">PluginChecker.java</a>
+ <li>Usage of repeating annotation is shown in modules sources.<a href="DependencyChecker/Plugins/src">DependencyChecker/Plugins/src</a>
+ </ul>
+
+ <li><h3>Validator.</h3>
+
+ <p>
+ Shows how to define repeating annotations and process them at runtime.
+ A problem domain is code that needs to validate provided Suppliers for conformance to some criteria.
+ The criteria are implemented by the Validator class which is applied by using annotations that are placed in
+ the code whenever validation is needed. For more information, see the
+ source files.
+ </p>
+
+ <p>
+ <ul>
+ <li>Usage of repeating annotation is described in <a href="Validator/src/PositiveIntegerSupplier.java">PositiveIntegerSupplier.java</a>
+ <li> Example of how to define a repeating annotation type can be found in
+ <a href="Validator/src/Validate.java">Validate.java</a>
+ <li> Usages of the new reflective methods can be found in <a href="Validator/src/SupplierValidator.java">SupplierValidator.java</a>
+ </ul>
+ </p>
+ Sources: <a href="Validator/src/">Validator/src/</a>
+</ul>
+</body>
+</html>
\ No newline at end of file diff --git a/darwin-x86/sample/dtrace/README.txt b/darwin-x86/sample/dtrace/README.txt new file mode 100644 index 0000000..c3d12b2 --- /dev/null +++ b/darwin-x86/sample/dtrace/README.txt @@ -0,0 +1,43 @@ +DTrace HotSpot probes samples +============================= + +This directory contains the list of D scripts which could be used to trace +Java application with help of Solaris(tm) 10 Dynamic Tracing (DTrace) +probes. + +The directory is organized as: + +* helpers/ + + This directory contains the auxiliary script to launch Java application + with D script to debug. See more comments in the scripts. + +* hotspot/ + + This directory contains D scripts which demonstrate usage of 'hotspot' + provider probes. + + +* hotspot_jni/ + + This directory contains D scripts which demonstrate usage of 'hotspot_jni' + provider probes. + + + +Requirements to run DTrace +========================== + +1. dtrace framework should be installed; (check if /usr/sbin/dtrace exists) + +2. the user should have the following rights: + dtrace_proc, dtrace_user, dtrace_kernel + + To give a user a privilege on login, insert a line into the + /etc/user_attr file of the form: + user-name::::defaultpriv=basic,dtrace_proc,dtrace_user,dtrace_kernel + + or + + To give a running process an DTrace privilege, use the ppriv(1) command: + # ppriv -s A+privilege process-ID diff --git a/darwin-x86/sample/dtrace/helpers/dtrace_helper.d b/darwin-x86/sample/dtrace/helpers/dtrace_helper.d new file mode 100644 index 0000000..896b175 --- /dev/null +++ b/darwin-x86/sample/dtrace/helpers/dtrace_helper.d @@ -0,0 +1,87 @@ +#!/usr/sbin/dtrace -s +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Description: + * dtrace -c option launches the command specified in the -c argument and + * starts tracing the process. Typically, you can run a D script and trace + * a Java application as follows: + * dscript.d -Zc "java HelloWorld" + * + * The -Z option is needed to permit probe descriptions that match zero + * probes because Hotspot probes definitions are located in libjvm.so which + * has not been yet loaded and thus can't be enabled until the application + * is started. + * + * Straightforward attempt to run D script may fail, e.g.: + * dscript.d -c "java HelloWorld" + * "probe description hotspotPID:::probename does not match any probes" + * + * This is because DTrace tries to enable probes before libjvm.so is loaded. + * The -Z option requires Solaris patch 118822-30 installed on your system. + * + * In case you don't have this Solaris patch use dtrace_helper.d script. + * This script waits until the Hotspot DTrace probes are loaded and then + * stops the Java process (passed as '-c' options). After the process is + * stopped, another D script (passed as first argument) is called to do real + * trace of Java process. + * + * Usage example: + * dtrace_helper.d -c "java ..." ../hotspot/class_loading_stat.d + */ + +#pragma D option quiet +#pragma D option destructive + + +pid$target::dlopen:entry +{ + self->filename = arg0; +} + + +pid$target::dlopen:return +/self->filename && basename(copyinstr(self->filename)) == "libjvm.so"/ +{ + printf(" loaded %s\n", basename(copyinstr(self->filename))); + self->filename = 0; + + stop(); + printf(" stopped java process with pid=%d \n", $target); + + printf(" run: %s -p %d &", $1, $target); + system("(%s -p %d) &", $1, $target); + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/README.txt b/darwin-x86/sample/dtrace/hotspot/README.txt new file mode 100644 index 0000000..b511b9c --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/README.txt @@ -0,0 +1,87 @@ +============================ +'hotspot' PROBES DESCRIPTION +============================ + +This directory contains D scripts which demonstrate usage of 'hotspot' provider probes. + +The 'hotspot' provider makes available probes that can be used to track the +lifespan of the VM, thread start and stop events, GC and memory pool +statistics, method compilations, and monitor activity. With a startup flag, +additional probes are enabled which can be used to monitor the running Java +program, such as method enter and return probes, and object allocations. All +of the hotspot probes originate in the VM library (libjvm.so), so they are +also provided from programs which embed the VM. + +Many of the probes in the provider have arguments that can be examined to +provide further details on the state of the VM. Many of these probes' +arguments are opaque IDs which can be used to link probe firings to each +other, however strings and other data are also provided. When string values +are provided, they are always present as a pair: a pointer to unterminated +modified UTF-8 data (see JVM spec: 4.4.7) , and a length value which +indicates the extent of that data. Because the string data (even when none +of the characters are outside the ASCII range) is not guaranteed to be +terminated by a NULL character, it is necessary to use the length-terminated +copyinstr() intrinsic to read the string data from the process. + +You can find more information about HotSpot probes here: +http://java.sun.com/javase/6/docs/technotes/guides/vm/dtrace.html + + +=========== +THE SCRIPTS +=========== + +The following scripts/samples which demonstrate 'hotspot' probes usage are +available: + +- class_loading_stat.d + The script collects statistics about loaded and unloaded Java classes and + dump current state to stdout every N seconds. + +- gc_time_stat.d + The script measures the duration of a time spent in GC. + The duration is measured for every memory pool every N seconds. + +- hotspot_calls_tree.d + The script prints calls tree of fired 'hotspot' probes. + +- method_compile_stat.d + The script prints statistics about N methods with largest/smallest + compilation time every M seconds. + +- method_invocation_stat.d + The script collects statistics about Java method invocations. + +- method_invocation_stat_filter.d + The script collects statistics about Java method invocations. + You can specify package, class or method name to trace. + +- method_invocation_tree.d + The script prints tree of Java and JNI method invocations. + +- monitors.d + The script traces monitor related probes. + +- object_allocation_stat.d + The script collects statistics about N object allocations every M seconds. + + +========== +HOW TO RUN +========== + +To run any D script from hotspot directory you can do either: + + # dscript.d -c "java ..." + + or if you don't have Solaris 10 patch which allows to specify probes that + don't yet exist ( Hotspot DTrace probes are defined in libjvm.so and as + result they could be not been yet loaded when you try to attach D script to + the Java process) do: + + # ../helpers/dtrace_helper.d -c "java ..." dscript.d + + or if your application is already running you can just simply attach + the D script like: + + # dscript.d -p JAVA_PID diff --git a/darwin-x86/sample/dtrace/hotspot/class_loading_stat.d b/darwin-x86/sample/dtrace/hotspot/class_loading_stat.d new file mode 100644 index 0000000..7197620 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/class_loading_stat.d @@ -0,0 +1,157 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. class_loading_stat.d -c "java ..." INTERVAL_SECS + * 2. class_loading_stat.d -p JAVA_PID INTERVAL_SECS + * + * This script collects statistics about loaded and unloaded Java classes + * and dump current state to stdout every INTERVAL_SECS seconds. If + * INTERVAL_SECS is not set then 10 seconds interval is used. + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option aggrate=100ms + + +self char *str_ptr; +self string class_name; +self string package_name; + +int INTERVAL_SECS; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot class loadin tracing"; + + INTERVAL_SECS = $1 ? $1 : 10; + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; + + LOADED_CLASSES_CNT = 0; + UNLOADED_CLASSES_CNT = 0; + + LINE_SEP = + "------------------------------------------------------------------------"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::class-loaded, hotspot:::class-unloaded probe arguments: + * arg0: char*, class name passed as mUTF8 string + * arg1: uintptr_t, class name length + * arg2: void*, class loader ID, which is unique identifier for + * a class loader in the VM. + * arg3: uintptr_t, class is shared or not + */ +hotspot$target:::class-loaded +{ + LOADED_CLASSES_CNT ++; + + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->class_name = (string) self->str_ptr; + + self->package_name = dirname(self->class_name); + + @classes_loaded[self->package_name] = count(); +} + +hotspot$target:::class-unloaded +{ + UNLOADED_CLASSES_CNT ++; + + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->class_name = (string) self->str_ptr; + + self->package_name = dirname(self->class_name); + + @classes_unloaded[self->package_name] = count(); +} + + +tick-1sec +/timestamp > SAMPLING_TIME/ +{ + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf("Loaded classes by package:\n"); + printa("%10@d %s\n", @classes_loaded); + + printf("\n"); + printf("Unloaded classes by package:\n"); + printa("%10@d %s\n", @classes_unloaded); + + printf("\n"); + printf("Number of loaded classes: %10d\n", LOADED_CLASSES_CNT); + printf("Number of unloaded classes: %10d\n", UNLOADED_CLASSES_CNT); + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; +} + + +:::END +{ + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf("Loaded classes by package:\n"); + printa("%10@d %s\n", @classes_loaded); + + printf("\n"); + printf("Unloaded classes by package:\n"); + printa("%10@d %s\n", @classes_unloaded); + + printf("\n"); + printf("Number of loaded classes: %10d\n", LOADED_CLASSES_CNT); + printf("Number of unloaded classes: %10d\n", UNLOADED_CLASSES_CNT); + + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/gc_time_stat.d b/darwin-x86/sample/dtrace/hotspot/gc_time_stat.d new file mode 100644 index 0000000..c35b87d --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/gc_time_stat.d @@ -0,0 +1,203 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. gc_time_stat.d -c "java ..." INTERVAL_SECS + * 2. gc_time_stat.d -p JAVA_PID INTERVAL_SECS + * + * This script measures the duration of a time spent in GC. The duration is + * measured for every memory pool every INTERVAL_SECS seconds. If + * INTERVAL_SECS is not set then 10 seconds interval is used. + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option aggrate=100ms + + +string TEST_NAME; +self char *str_ptr; +self string mgr_name; +self string pool_name; + +int INTERVAL_SECS; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot GC tracing"; + + START_TIME = timestamp; + gc_total_time = 0; + gc_total_count = 0; + + INTERVAL_SECS = $1 ? $1 : 10; + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; + + LINE_SEP = "--------------------------------------------------------"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + + +/* + * hotspot:::gc-begin + * arg0: uintptr_t, boolean value which indicates + * if this is to be a full GC or not + */ +hotspot$target:::gc-begin +{ + self->gc_ts = timestamp; + printf("\nGC started: %Y\n", walltimestamp); + printf("%20s | %-20s | %10s\n", "manager", "pool", "time (ms)"); + printf(" %s\n", LINE_SEP); +} + +hotspot$target:::gc-end +/self->gc_ts/ +{ + self->time = (timestamp - self->gc_ts) / 1000; + + printf(" %s\n", LINE_SEP); + printf(" %40s | %10d\n", "GC total", self->time); + + gc_total_time += self->time; + gc_total_count ++; + self->gc_ts = 0; +} + +/* + * hotspot:::mem-pool-gc-begin, hotspot:::mem-pool-gc-end + * arg0: char*, a pointer to mUTF-8 string data which contains the name + * of the manager which manages this memory pool + * arg1: uintptr_t, the length of the manager name (in bytes + * arg2: char*, a pointer to mUTF-8 string data which contains the name + * of the memory pool + * arg3: uintptr_t, the length of the memory pool name (in bytes) + * arg4: uintptr_t, the initial size of the memory pool (in bytes) + * arg5: uintptr_t, the amount of memory in use in the memory pool + * (in bytes) + * arg6: uintptr_t, the the number of committed pages in the memory pool + * arg7: uintptr_t, the the maximum size of the memory pool + */ +hotspot$target:::mem-pool-gc-begin +{ + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->mgr_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg2, arg3+1); + self->str_ptr[arg3] = '\0'; + self->pool_name = (string) self->str_ptr; + + self->mem_pool_ts[self->mgr_name, self->pool_name] = timestamp; +} + +hotspot$target:::mem-pool-gc-end +{ + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->mgr_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg2, arg3+1); + self->str_ptr[arg3] = '\0'; + self->pool_name = (string) self->str_ptr; + + self->time = + (timestamp - self->mem_pool_ts[self->mgr_name, self->pool_name]) / 1000; + + printf( + "%20s | %-20s | %10d\n", self->mgr_name, self->pool_name, self->time); + + @mem_pool_total_time[self->mgr_name, self->pool_name] = sum(self->time); + self->mem_pool_ts[self->mgr_name, self->pool_name] = 0; + + @mem_pool_count[self->mgr_name, self->pool_name] = count(); +} + +tick-1sec +/timestamp > SAMPLING_TIME/ +{ + trace_time = (timestamp - START_TIME) / 1000; + + printf(" %s\n", LINE_SEP); + printf("\nGC statistics, time: %Y\n\n", walltimestamp); + printf("%20s | %-20s | %10s\n", "manager", "pool", "total time"); + printf(" %s\n", LINE_SEP); + printa("%20s | %-20s | %10@d\n", @mem_pool_total_time); + printf(" %s\n", LINE_SEP); + printf(" %40s | %10d\n", "total", gc_total_time); + + printf("\n"); + printf("%20s | %-20s | %10s\n", "manager", "pool", "# of calls"); + printf(" %s\n", LINE_SEP); + printa("%20s | %-20s | %10@d\n", @mem_pool_count); + printf(" %s\n", LINE_SEP); + printf(" %40s | %10d\n", "total", gc_total_count); + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; +} + +:::END +{ + trace_time = (timestamp - START_TIME) / 1000; + + printf(" %s\n", LINE_SEP); + printf("\nGC statistics, time: %Y\n\n", walltimestamp); + printf("%20s | %-20s | %10s\n", "manager", "pool", "total time"); + printf(" %s\n", LINE_SEP); + printa("%20s | %-20s | %10@d\n", @mem_pool_total_time); + printf(" %s\n", LINE_SEP); + printf(" %40s | %10d\n", "total", gc_total_time); + + printf("\n"); + printf("%20s | %-20s | %10s\n", "manager", "pool", "# of calls"); + printf(" %s\n", LINE_SEP); + printa("%20s | %-20s | %10@d\n", @mem_pool_count); + printf(" %s\n", LINE_SEP); + printf(" %40s | %10d\n", "total", gc_total_count); + + + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/hotspot_calls_tree.d b/darwin-x86/sample/dtrace/hotspot/hotspot_calls_tree.d new file mode 100644 index 0000000..a5af496 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/hotspot_calls_tree.d @@ -0,0 +1,117 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. hotspot_calls_tree.d -c "java ..." + * 2. hotspot_calls_tree.d -p JAVA_PID + * + * This script prints calls tree of fired 'hotspot' probes. + * + * Notes: + * The script uses 'monitors' probes which are disabled by default since + * it incurs performance overhead to the application. To enable them, you + * need to turn on the ExtendedDTraceProbes VM option. You can either + * start the application with -XX:+ExtendedDTraceProbes option or use the + * jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option aggrate=100ms + +self int indent; +string PAUSE_AT_STARTUP_FILE; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot probes tracing"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); + + self->indent = 10; +} + +hotspot$target:::class-loaded, +hotspot$target:::class-unloaded, +hotspot$target:::compiled-method-load, +hotspot$target:::compiled-method-unload, +hotspot$target:::monitor-notify, +hotspot$target:::monitor-notifyAll +{ + printf("%d %*s <-> %s\n", curcpu->cpu_id, self->indent, "", probename); +} + +hotspot$target:::vm-init-begin, +hotspot$target:::gc-begin, +hotspot$target:::mem-pool-gc-begin, +hotspot$target:::thread-start, +hotspot$target:::method-compile-begin, +hotspot$target:::monitor-contended-enter, +hotspot$target:::monitor-wait +{ + self->indent ++; + printf("%d %*s -> %s\n", curcpu->cpu_id, self->indent, "", probename); +} + +hotspot$target:::vm-init-end, +hotspot$target:::vm-shutdown, +hotspot$target:::gc-end, +hotspot$target:::mem-pool-gc-end, +hotspot$target:::thread-stop, +hotspot$target:::method-compile-end, +hotspot$target:::monitor-contended-entered, +hotspot$target:::monitor-contended-exit, +hotspot$target:::monitor-waited +{ + printf("%d %*s <- %s\n", curcpu->cpu_id, self->indent, "", probename); + self->indent --; +} + +:::END +{ + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/method_compile_stat.d b/darwin-x86/sample/dtrace/hotspot/method_compile_stat.d new file mode 100644 index 0000000..0d3812e --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/method_compile_stat.d @@ -0,0 +1,274 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. method_compile_stat.d -c "java ..." TOP_RESULTS_COUNT INTERVAL_SECS + * 2. method_compile_stat.d -p JAVA_PID TOP_RESULTS_COUNT INTERVAL_SECS + * + * This script prints statistics about TOP_RESULTS_COUNT (default is 25) + * methods with largest/smallest compilation time every INTERVAL_SECS + * (default is 60) seconds. + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option aggrate=100ms + + +self char *str_ptr; +self string class_name; +self string method_name; +self string signature; + +int INTERVAL_SECS; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot methods compilation tracing"; + + TOP_RESULTS_COUNT = $1 ? $1 : 25; + INTERVAL_SECS = $2 ? $2 : 60; + + COMPILED_METHODS_COUNT = 0; + LOADED_METHODS_CNT = 0; + UNLOADED_METHODS_CNT = 0; + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; + + LINE_SEP = + "------------------------------------------------------------------------"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::method-compile-begin + * arg0: char*, a pointer to mUTF-8 string containing the name of + * the compiler + * arg1: uintptr_t, the length of the compiler name (in bytes) + * arg2: char*, a pointer to mUTF-8 string containing the class name of + * the method being compiled + * arg3: uintptr_t, the length of the class name (in bytes) + * arg4: char*, a pointer to mUTF-8 string containing the method name of + * the method being compiled + * arg5: uintptr_t, the length of the method name (in bytes) + * arg6: char*, a pointer to mUTF-8 string containing the signature of + * the method being compiled + * arg7: uintptr_t, the length of the signature(in bytes) + */ +hotspot$target:::method-compile-begin +{ + /*compiler_name, len, class_name, len, method_name, len, signature, len*/ + + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + compiler_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg2, arg3+1); + self->str_ptr[arg3] = '\0'; + self->class_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg4, arg5+1); + self->str_ptr[arg5] = '\0'; + self->method_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg6, arg7+1); + self->str_ptr[arg7] = '\0'; + self->signature = (string) self->str_ptr; + + self->ts[self->class_name, self->method_name, self->signature] = timestamp; +} + +/* + * hotspot:::method-compile-end + * arg0: char*, a pointer to mUTF-8 string containing the name of + * the compiler + * arg1: uintptr_t, the length of the compiler name (in bytes) + * arg2: char*, a pointer to mUTF-8 string containing the class name of + * the method being compiled + * arg3: uintptr_t, the length of the class name (in bytes) + * arg4: char*, a pointer to mUTF-8 string containing the method name of + * the method being compiled + * arg5: uintptr_t, the length of the method name (in bytes) + * arg6: char*, a pointer to mUTF-8 string containing the signature of + * the method being compiled + * arg7: uintptr_t, the length of the signature(in bytes) + * arg8: uintptr_t, boolean value which indicates if method + * has been compiled successfuly + */ +hotspot$target:::method-compile-end +{ + /* compiler_name, len, class_name, len, method_name, len, + signature, len, isSuccess */ + + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + compiler_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg2, arg3+1); + self->str_ptr[arg3] = '\0'; + self->class_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg4, arg5+1); + self->str_ptr[arg5] = '\0'; + self->method_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg6, arg7+1); + self->str_ptr[arg7] = '\0'; + self->signature = (string) self->str_ptr; +} + +/* + * Method was successfuly compiled + */ +hotspot$target:::method-compile-end +/arg8 && self->ts[self->class_name, self->method_name, self->signature]/ +{ + /* compiler_name, len, class_name, len, method_name, len, + signature, len, isSuccess */ + + COMPILED_METHODS_COUNT++; + + @compile_time_top[self->class_name, self->method_name, self->signature] = + avg((timestamp - + self->ts[self->class_name, self->method_name, self->signature]) / 1000); + + @compile_time_last[self->class_name, self->method_name, self->signature] = + avg((timestamp - + self->ts[self->class_name, self->method_name, self->signature]) / 1000); + + self->ts[self->class_name, self->method_name, self->signature] = 0; +} + +/* + * Method compilation was failed + */ +hotspot$target:::method-compile-end +/arg8 != 1 && self->ts[self->class_name, self->method_name, self->signature]/ +{ + /* compiler_name, len, class_name, len, method_name, len, + signature, len, isSuccess */ + + @fail_compile_count[self->class_name, + self->method_name, self->signature] = count(); +} + +hotspot$target:::compiled-method-load +{ + /* class_name, len, method_name, len, signature, len, code_address, size */ + + LOADED_METHODS_CNT ++; +} + +hotspot$target:::compiled-method-unload +{ + /* class_name, len, method_name, len, signature, len, code_address, size */ + + UNLOADED_METHODS_CNT ++; +} + + +tick-1sec +/timestamp > SAMPLING_TIME/ +{ + trunc(@compile_time_top, TOP_RESULTS_COUNT); + trunc(@compile_time_last, -TOP_RESULTS_COUNT); + + printf("\n"); + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf( + "\nTop %d methods with largest compilation time (in milleseconds):\n", + TOP_RESULTS_COUNT); + printa("%10@d %s::%s%s\n", @compile_time_top); + + printf( + "\nTop %d methods with smallest compilation time (in milleseconds):\n", + TOP_RESULTS_COUNT); + printa("%10@d %s::%s%s\n", @compile_time_last); + + printf("\n"); + printf("Compiled methods: %10d\n", COMPILED_METHODS_COUNT); + printf("Loaded compiled methods: %10d\n", LOADED_METHODS_CNT); + printf("Unoaded compiled methods: %10d\n", UNLOADED_METHODS_CNT); + + printf("\nFailed compilation:\n"); + printa("%10@d %s::%s%s\n", @fail_compile_count); + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; +} + +:::END +{ + trunc(@compile_time_top, TOP_RESULTS_COUNT); + trunc(@compile_time_last, -TOP_RESULTS_COUNT); + + printf("\n"); + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf( + "\nTop %d methods with largest compilation time (in milleseconds):\n", + TOP_RESULTS_COUNT); + printa("%10@d %s::%s%s\n", @compile_time_top); + + printf( + "\nTop %d methods with smallest compilation time (in milleseconds):\n", + TOP_RESULTS_COUNT); + printa("%10@d %s::%s%s\n", @compile_time_last); + + printf("\n"); + printf("Compiled methods: %10d\n", COMPILED_METHODS_COUNT); + printf("Loaded compiled methods: %10d\n", LOADED_METHODS_CNT); + printf("Unoaded compiled methods: %10d\n", UNLOADED_METHODS_CNT); + + printf("\nFailed compilations:\n"); + printa("%10@d %s::%s%s\n", @fail_compile_count); + + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/method_invocation_stat.d b/darwin-x86/sample/dtrace/hotspot/method_invocation_stat.d new file mode 100644 index 0000000..1b64b8b --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/method_invocation_stat.d @@ -0,0 +1,210 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. method_invocation_stat.d -c "java ..." + * 2. method_invocation_stat.d -p JAVA_PID + * + * This script collects statistics about Java method invocations. + * + * Notes: + * - These probes are disabled by default since it incurs performance + * overhead to the application. To trace the method-entry and + * method-exit probes, you need to turn on the ExtendedDTraceProbes VM + * option. + * You can either start the application with -XX:+ExtendedDTraceProbes + * option or use the jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self char *str_ptr; +self string class_name; +self string method_name; +self string signature; +self string package_name; +self string last_class_name; + +long long JAVA_CALLS; +long long JNI_CALLS; +long long SYS_CALLS; + +int SYS_DEEP; +long long LAST_SYS_TS; + +long long START_TIME; +long long JAVA_TIME; +long long RUN_TIME; +long long SYS_TIME; + +BEGIN +{ + SAMPLE_NAME = "hotspot method invocation tracing"; + + START_TIME = timestamp; + SYS_TIME = 0; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::method-entry, hotspot:::method-return probe arguments: + * arg0: uintptr_t, Java thread id + * arg1: char*, a pointer to mUTF-8 string containing the name of + * the class of the method being entered + * arg2: uintptr_t, the length of the class name (in bytes) + * arg3: char*, a pointer to mUTF-8 string data which contains the + * name of the method being entered + * arg4: uintptr_t, the length of the method name (in bytes) + * arg5: char*, a pointer to mUTF-8 string data which contains the + * signature of the method being entered + * arg6: uintptr_t, the length of the signature(in bytes) + */ +hotspot$target:::method-entry +{ + self->str_ptr = (char*) copyin(arg1, arg2+1); + self->str_ptr[arg2] = '\0'; + self->class_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg3, arg4+1); + self->str_ptr[arg4] = '\0'; + self->method_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg5, arg6+1); + self->str_ptr[arg6] = '\0'; + self->signature = (string) self->str_ptr; + + + self->package_name = dirname(self->class_name); + + JAVA_CALLS ++; + @method_calls[self->class_name, + self->method_name, self->signature] = count(); + @class_calls[self->class_name] = count(); + @package_calls[self->package_name] = count(); +} + + +hotspot_jni$target:::*-entry +{ + JNI_CALLS ++; + + @jni_calls[probename] = count(); +} + +syscall:::entry +/pid == $target && SYS_DEEP == 0/ +{ + LAST_SYS_TS = timestamp; +} + +syscall:::entry +/pid == $target/ +{ + SYS_DEEP ++; + @sys_calls[probefunc] = count(); + SYS_CALLS ++; +} + +syscall:::return +/pid == $target/ +{ + SYS_DEEP --; +} + +syscall:::return +/pid == $target && SYS_DEEP == 0/ +{ + SYS_TIME += (timestamp - LAST_SYS_TS); +} + + +:::END +{ + RUN_TIME = (timestamp - START_TIME); + JAVA_TIME = (RUN_TIME - SYS_TIME); + + printf("System calls:\n"); + printa("%10@d %s\n", @sys_calls); + printf("\n"); + + printf("JNI calls:\n"); + printa("%10@d %s\n", @jni_calls); + printf("\n"); + + printf("Top packages calls:\n"); + printa("%10@d %s\n", @package_calls); + printf("\n"); + + printf("Top class calls:\n"); + printa("%10@d %s\n", @class_calls); + printf("\n"); + + printf("Top method calls:\n"); + printa("%10@d %s:%s:%s\n", @method_calls); + printf("\n"); + + printf("=======================================\n"); + printf("JAVA_CALLS: %10d\n", JAVA_CALLS); + printf(" JNI_CALLS: %10d\n", JNI_CALLS); + printf(" SYS_CALLS: %10d\n", SYS_CALLS); + printf("\n"); + + printf("Run time: %15d\n", RUN_TIME); + printf("Syscall time: %15d\n", SYS_TIME); + printf("Java+JNI time: %15d\n", JAVA_TIME); + printf("\n"); +} + +:::END +{ + printf("\nEND %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/method_invocation_stat_filter.d b/darwin-x86/sample/dtrace/hotspot/method_invocation_stat_filter.d new file mode 100644 index 0000000..a36d365 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/method_invocation_stat_filter.d @@ -0,0 +1,204 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. method_invocation_stat_filter.d -c "java ..." p|c|m package|class_name|method_name + * 2. method_invocation_stat_filter.d -p JAVA_PID p|c|m package|class_name|method_name + * + * example: + * method_invocation_stat_filter.d -c "java -version" '"p"' '"sun/util"' + * + * This script collects statistics about Java method invocations. + * + * Notes: + * - These probes are disabled by default since it incurs performance + * overhead to the application. To trace the method-entry and + * method-exit probes, you need to turn on the ExtendedDTraceProbes VM + * option. + * You can either start the application with -XX:+ExtendedDTraceProbes + * option or use the jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self char *str_ptr; +self string class_name; +self string method_name; +self string signature; +self string package_name; +self string last_class_name; + +long long JAVA_CALLS; + +long long START_TIME; +long long JAVA_TIME; +long long RUN_TIME; + +string FILTER_TYPE; +string FILTER_VALUE; + + +:::BEGIN +{ + SAMPLE_NAME = "hotspot method invocation tracing"; + + START_TIME = timestamp; + + FILTER_TYPE = $1; + FILTER_VALUE = $2; + + START_TIME = timestamp; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::method-entry, hotspot:::method-return probe arguments: + * arg0: uintptr_t, Java thread id + * arg1: char*, a pointer to mUTF-8 string containing the name of + * the class of the method being entered + * arg2: uintptr_t, the length of the class name (in bytes) + * arg3: char*, a pointer to mUTF-8 string data which contains the + * name of the method being entered + * arg4: uintptr_t, the length of the method name (in bytes) + * arg5: char*, a pointer to mUTF-8 string data which contains the + * signature of the method being entered + * arg6: uintptr_t, the length of the signature(in bytes) + */ +hotspot$target:::method-entry +{ + self->str_ptr = (char*) copyin(arg1, arg2+1); + self->str_ptr[arg2] = '\0'; + self->class_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg3, arg4+1); + self->str_ptr[arg4] = '\0'; + self->method_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg5, arg6+1); + self->str_ptr[arg6] = '\0'; + self->signature = (string) self->str_ptr; + + + self->package_name = dirname(self->class_name); +} + +hotspot$target:::method-entry +/FILTER_TYPE == ""/ +{ + JAVA_CALLS ++; + @method_calls[self->class_name, + self->method_name, self->signature] = count(); + @class_calls[self->class_name] = count(); + @package_calls[self->package_name] = count(); +} + +hotspot$target:::method-entry +/FILTER_TYPE == "p" && self->package_name == FILTER_VALUE/ +{ + JAVA_CALLS ++; + @method_calls[self->class_name, + self->method_name, self->signature] = count(); + @class_calls[self->class_name] = count(); + @package_calls[self->package_name] = count(); +} + +hotspot$target:::method-entry +/FILTER_TYPE == "c" && self->class_name == FILTER_VALUE/ +{ + JAVA_CALLS ++; + @method_calls[self->class_name, + self->method_name, self->signature] = count(); + @class_calls[self->class_name] = count(); + @package_calls[self->package_name] = count(); +} + +hotspot$target:::method-entry +/FILTER_TYPE == "m" && self->method_name == FILTER_VALUE/ +{ + JAVA_CALLS ++; + @method_calls[self->class_name, + self->method_name, self->signature] = count(); + @class_calls[self->class_name] = count(); + @package_calls[self->package_name] = count(); +} + + +:::END +{ + RUN_TIME = (timestamp - START_TIME); + JAVA_TIME = RUN_TIME; + + printf("Top packages calls:\n"); + printa("%10@d %s\n", @package_calls); + printf("\n"); + + printf("Top class calls:\n"); + printa("%10@d %s\n", @class_calls); + printf("\n"); + + printf("Top method calls:\n"); + printa("%10@d %s:%s:%s\n", @method_calls); + printf("\n"); + + printf("=======================================\n"); + printf("JAVA_CALLS: %10d\n", JAVA_CALLS); + printf("\n"); + + printf("Run time: %15d\n", RUN_TIME); + printf("\n"); +} + +:::END +{ + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/method_invocation_tree.d b/darwin-x86/sample/dtrace/hotspot/method_invocation_tree.d new file mode 100644 index 0000000..d27fe27 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/method_invocation_tree.d @@ -0,0 +1,142 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. method_invocation_tree.d -c "java ..." + * 2. method_invocation_tree.d -p JAVA_PID + * + * This script prints tree of Java and JNI method invocations. + * + * Notes: + * - These probes are disabled by default since it incurs performance + * overhead to the application. To trace the method-entry and + * method-exit probes, you need to turn on the ExtendedDTraceProbes VM + * option. + * You can either start the application with -XX:+ExtendedDTraceProbes + * option or use the jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + +self char *str_ptr; +self string class_name; +self string method_name; +self string signature; + +self int indent; + +BEGIN +{ + SAMPLE_NAME = "hotspot method invocation tracing"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +hotspot$target:::* +/!self->indent/ +{ + self->indent = 0; +} + +/* + * hotspot:::method-entry, hotspot:::method-return probe arguments: + * arg0: uintptr_t, Java thread id + * arg1: char*, a pointer to mUTF-8 string containing the name of + * the class of the method being entered + * arg2: uintptr_t, the length of the class name (in bytes) + * arg3: char*, a pointer to mUTF-8 string data which contains the + * name of the method being entered + * arg4: uintptr_t, the length of the method name (in bytes) + * arg5: char*, a pointer to mUTF-8 string data which contains the + * signature of the method being entered + * arg6: uintptr_t, the length of the signature(in bytes) + */ + +hotspot$target:::method-return +{ + self->indent --; + METHOD_RETURN_CNT ++ +} + +hotspot$target:::method-entry +{ + self->indent ++; + METHOD_ENTRY_CNT ++; + + self->str_ptr = (char*) copyin(arg1, arg2+1); + self->str_ptr[arg2] = '\0'; + self->class_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg3, arg4+1); + self->str_ptr[arg4] = '\0'; + self->method_name = (string) self->str_ptr; + + self->str_ptr = (char*) copyin(arg5, arg6+1); + self->str_ptr[arg6] = '\0'; + self->signature = (string) self->str_ptr; + + printf("%-10u%*s%s:%s:%s\n", + tid, self->indent, "", self->class_name, + self->method_name, self->signature); + +} + +hotspot_jni$target:::*_entry +{ + printf("%-10u%*sJNI:%s\n", tid, self->indent+1, "", probename); +} + +:::END +{ + printf("METHOD_ENTRY_CNT: %10d\n", METHOD_ENTRY_CNT); + printf("METHOD_RETURN_CNT: %10d\n", METHOD_RETURN_CNT); + + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/monitors.d b/darwin-x86/sample/dtrace/hotspot/monitors.d new file mode 100644 index 0000000..fba030e --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/monitors.d @@ -0,0 +1,152 @@ +#!/usr/sbin/dtrace -Zs +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. monitors.d -c "java ..." + * 2. monitors.d -p JAVA_PID + * + * The script traces monitor related probes. + * + * Notes: + * - These probes are disabled by default since it incurs performance + * overhead to the application. To trace the monitor-* probes, you need + * to turn on the ExtendedDTraceProbes VM option. + * You can either start the application with -XX:+ExtendedDTraceProbes + * option or use the jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option aggrate=100ms + + +self string thread_name; +self char* str_ptr; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot monitors tracing"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::thread-start, hotspot:::thread-stop probe arguments: + * arg0: char*, thread name passed as mUTF8 string + * arg1: uintptr_t, thread name length + * arg2: uintptr_t, Java thread id + * arg3: uintptr_t, native/OS thread id + * arg4: uintptr_t, is a daemon or not + */ +hotspot$target:::thread-start +{ + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->thread_name = (string) self->str_ptr; + + printf("thread-start: id=%d, is_daemon=%d, name=%s, os_id=%d\n", + arg2, arg4, self->thread_name, arg3); + + threads[arg2] = self->thread_name; +} + + +hotspot$target:::thread-stop +{ + self->str_ptr = (char*) copyin(arg0, arg1+1); + self->str_ptr[arg1] = '\0'; + self->thread_name = (string) self->str_ptr; + + + printf("thread-stop: id=%d, is_daemon=%d, name=%s, os_id=%d\n", + arg2, arg4, self->thread_name, arg3); +} + +/* + * + * hotspot::monitor-contended-enter, hotspot::monitor-contended-entered + * + * arg0: uintptr_t, the Java thread identifier for the thread peforming + * the monitor operation + * arg1: uintptr_t, a unique, but opaque identifier for the specific + * monitor that the action is performed upon + * arg2: char*, a pointer to mUTF-8 string data which contains the + * name of the class of the object being acted upon + * arg3: uintptr_t, the length of the class name (in bytes) + */ + +hotspot$target:::monitor-contended-enter +{ + /* (uintptr_t thread_id, uintptr_t monitor_id, + char* obj_class_name, uintptr_t obj_class_name_len) */ + + self->str_ptr = (char*) copyin(arg2, arg3+1); + self->str_ptr[arg3] = '\0'; + self->class_name = (string) self->str_ptr; + + monitors[arg1] = self->class_name; + + monitors_enter[arg1] = arg0; + printf("%s: -> enter monitor (%d) %s\n", + threads[arg0], arg1, monitors[arg1]); +} + +hotspot$target:::monitor-contended-entered +{ + /* (uintptr_t thread_id, uintptr_t monitor_id, char* obj_class_name, + uintptr_t obj_class_name_len) */ + + monitors_entered[arg1] = arg0; + printf("%s: <- entered monitor (%d) %s\n", + threads[arg0], arg1, monitors[arg1]); +} + + +:::END +{ + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot/object_allocation_stat.d b/darwin-x86/sample/dtrace/hotspot/object_allocation_stat.d new file mode 100644 index 0000000..bfb8981 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot/object_allocation_stat.d @@ -0,0 +1,162 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. object_allocation_stat.d -c "java ..." TOP_RESULTS_COUNT INTERVAL_SECS + * 2. object_allocation_stat.d -p JAVA_PID TOP_RESULTS_COUNT INTERVAL_SECS + * + * This script collects statistics about TOP_RESULTS_COUNT (default is 25) + * object allocations every INTERVAL_SECS (default is 60) seconds. + * + * The results are displayed in ascending order which means that the highest + * allocated type is listed last. The script can be improved to sort the + * results in reverse order when DTrace supports it. + * + * Notes: + * - The object-alloc probe is disabled by default since it incurs + * performance overhead to the application. To trace object-alloc probe, + * you need to turn on the ExtendedDTraceProbes VM option. + * You can either start the application with -XX:+ExtendedDTraceProbes + * option or use the jinfo command to enable it at runtime as follows: + * + * jinfo -flag +ExtendedDTraceProbes <java_pid> + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self char *str_ptr; +self string class_name; + +long long ALLOCATED_OBJECTS_CNT; + +int INTERVAL_SECS; + +:::BEGIN +{ + SAMPLE_NAME = "hotspot object allocation tracing"; + + TOP_RESULTS_COUNT = $1 ? $1 : 25; + INTERVAL_SECS = $2 ? $2 : 60; + + ALLOCATED_OBJECTS_CNT = 0; + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; + + LINE_SEP = + "------------------------------------------------------------------------"; + + printf("BEGIN %s\n\n", SAMPLE_NAME); +} + +/* + * hotspot:::object-alloc probe arguments: + * arg0: uintptr_t, Java thread id + * arg1: char*, a pointer to mUTF-8 string containing the name of + * the class of the object being allocated + * arg2: uintptr_t, the length of the class name (in bytes) + * arg3: uintptr_t, the size of the object being allocated + */ +hotspot$target:::object-alloc +{ + ALLOCATED_OBJECTS_CNT ++; + + self->str_ptr = (char*) copyin(arg1, arg2+1); + self->str_ptr[arg2] = '\0'; + self->class_name = (string) self->str_ptr; + + + @allocs_count[self->class_name] = count(); + @allocs_size[self->class_name] = sum(arg3); +} + +tick-1sec +/timestamp > SAMPLING_TIME/ +{ + printf("\n"); + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf("\n"); + printf("Top %d allocations by size:\n", TOP_RESULTS_COUNT); + trunc(@allocs_size, TOP_RESULTS_COUNT); + printa("%10@d %s\n", @allocs_size); + + printf("\n"); + printf("Top %d allocations by count:\n", TOP_RESULTS_COUNT); + trunc(@allocs_count, TOP_RESULTS_COUNT); + printa("%10@d %s\n", @allocs_count); + + printf("\nTotal number of allocated objects: %d\n", ALLOCATED_OBJECTS_CNT); + + SAMPLING_TIME = timestamp + INTERVAL_SECS * 1000000000ull; +} + +:::END +{ + printf("\n"); + printf("%s\n", LINE_SEP); + printf("%Y\n", walltimestamp); + printf("%s\n", LINE_SEP); + + printf("\n"); + printf("Top %d allocations by size:\n", TOP_RESULTS_COUNT); + trunc(@allocs_size, TOP_RESULTS_COUNT); + printa("%10@d %s\n", @allocs_size); + + printf("\n"); + printf("Top %d allocations by count:\n", TOP_RESULTS_COUNT); + trunc(@allocs_count, TOP_RESULTS_COUNT); + printa("%10@d %s\n", @allocs_count); + + printf("\nTotal number of allocated objects: %d\n", ALLOCATED_OBJECTS_CNT); + + printf("\nEND of %s\n", SAMPLE_NAME); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection.d b/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection.d new file mode 100644 index 0000000..510784f --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection.d @@ -0,0 +1,136 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. CriticalSection.d -c "java ..." + * 2. CriticalSection.d -p JAVA_PID + * + * The script inspect a JNI application for Critical Section violations. + * + * Critical section is the space between calls to JNI methods: + * - GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical; or + * - GetStringCritical and ReleaseStringCritical. + * + * Inside a critical section, native code must not call other JNI functions, + * or any system call that may cause the current thread to block and wait + * for another Java thread. (For example, the current thread must not call + * read on a stream being written by another Java thread.) + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self int in_critical_section; +self string critical_section_name; + +int CRITICAL_SECTION_VIOLATION_CNT; + +:::BEGIN +{ + SAMPLE_NAME = "critical section violation checks"; + + printf("BEGIN %s\n", SAMPLE_NAME); +} + +/* + * Multiple pairs of GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical, + * GetStringCritical/ReleaseStringCritical may be nested + */ +hotspot_jni$target:::*_entry +/self->in_critical_section > 0 && + probename != "GetPrimitiveArrayCritical_entry" && + probename != "GetStringCritical_entry" && + probename != "ReleasePrimitiveArrayCritical_entry" && + probename != "ReleaseStringCritical_entry" && + probename != "GetPrimitiveArrayCritical_return" && + probename != "GetStringCritical_return" && + probename != "ReleasePrimitiveArrayCritical_return" && + probename != "ReleaseStringCritical_return"/ +{ + printf("\nJNI call %s made from JNI critical region '%s'\n", + probename, self->critical_section_name); + + printf("Jstack:\n"); + jstack(50, 500); + + CRITICAL_SECTION_VIOLATION_CNT ++; +} + +syscall:::entry +/pid == $target && self->in_critical_section > 0/ +{ + printf("\nSystem call %s made in JNI critical region '%s'\n", + probefunc, self->critical_section_name); + + printf("Jstack:\n"); + jstack(50, 500); + + CRITICAL_SECTION_VIOLATION_CNT ++; +} + +hotspot_jni$target:::ReleasePrimitiveArrayCritical_entry, +hotspot_jni$target:::ReleaseStringCritical_entry +/self->in_critical_section > 0/ +{ + self->in_critical_section --; +} + +hotspot_jni$target:::GetPrimitiveArrayCritical_return +{ + self->in_critical_section ++; + self->critical_section_name = "GetPrimitiveArrayCritical"; +} + +hotspot_jni$target:::GetStringCritical_return +{ + self->in_critical_section ++; + self->critical_section_name = "GetStringCritical"; +} + + +:::END +{ + printf("%d critical section violations have been discovered\n", + CRITICAL_SECTION_VIOLATION_CNT); + + printf("\nEND of %s\n", SAMPLE_NAME); +} diff --git a/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection_slow.d b/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection_slow.d new file mode 100644 index 0000000..a676aa3 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot_jni/CriticalSection_slow.d @@ -0,0 +1,178 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. CriticalSection_slow.d -c "java ..." + * 2. CriticalSection_slow.d -p JAVA_PID + * + * The script inspect a JNI application for Critical Section violations. + * + * Critical section is the space between calls to JNI methods: + * - GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical; or + * - GetStringCritical and ReleaseStringCritical. + * + * Inside a critical section, native code must not call other JNI functions, + * or any system call that may cause the current thread to block and wait + * for another Java thread. (For example, the current thread must not call + * read on a stream being written by another Java thread.) + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self int in_critical_section; +self string critical_section_name; + +self char *str_ptr; +self string class_name; +self string method_name; +self string signature; + +self int indent; +self int JAVA_STACK_DEEP; + +int CRITICAL_SECTION_VIOLATION_CNT; + +:::BEGIN +{ + SAMPLE_NAME = "critical section violation checks"; + + printf("BEGIN %s\n", SAMPLE_NAME); +} + +hotspot$target:::* +/!self->JAVA_STACK_DEEP/ +{ + self->JAVA_STACK_DEEP = 0; +} + + +hotspot$target:::method-return +/self->JAVA_STACK_DEEP > 0/ +{ + self->JAVA_STACK_DEEP --; +} + +hotspot$target:::method-entry +{ + self->JAVA_STACK_DEEP ++; + + self->str_ptr = (char*) copyin(arg1, arg2+1); + self->str_ptr[arg2] = '\0'; + self->method_name = strjoin( (string) self->str_ptr, ":"); + + self->str_ptr = (char*) copyin(arg3, arg4+1); + self->str_ptr[arg4] = '\0'; + self->method_name = strjoin(self->method_name, (string) self->str_ptr); + self->method_name = strjoin(self->method_name, ":"); + + self->str_ptr = (char*) copyin(arg5, arg6+1); + self->str_ptr[arg6] = '\0'; + self->method_name = strjoin(self->method_name, (string) self->str_ptr); + + self->JAVA_STACK[self->JAVA_STACK_DEEP] = self->method_name; + +/* printf("%-10u%*s%s\n", + * curcpu->cpu_id, self->indent, "", self->method_name); + */ +} + + +/* + * Multiple pairs of GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical, + * GetStringCritical/ReleaseStringCritical may be nested + */ +hotspot_jni$target:::*_entry +/self->in_critical_section > 0 && + probename != "GetPrimitiveArrayCritical_entry" && + probename != "GetStringCritical_entry" && + probename != "ReleasePrimitiveArrayCritical_entry" && + probename != "ReleaseStringCritical_entry" && + probename != "GetPrimitiveArrayCritical_return" && + probename != "GetStringCritical_return" && + probename != "ReleasePrimitiveArrayCritical_return" && + probename != "ReleaseStringCritical_return"/ +{ + printf("JNI call %s made from JNI critical region '%s' from %s\n", + probename, self->critical_section_name, + self->JAVA_STACK[self->JAVA_STACK_DEEP]); + + CRITICAL_SECTION_VIOLATION_CNT ++; +} + +syscall:::entry +/pid == $target && self->in_critical_section > 0/ +{ + printf("system call %s made in JNI critical region '%s' from %s\n", + probefunc, self->critical_section_name, + self->JAVA_STACK[self->JAVA_STACK_DEEP]); + + CRITICAL_SECTION_VIOLATION_CNT ++; +} + +hotspot_jni$target:::ReleasePrimitiveArrayCritical_entry, +hotspot_jni$target:::ReleaseStringCritical_entry +/self->in_critical_section > 0/ +{ + self->in_critical_section --; +} + +hotspot_jni$target:::GetPrimitiveArrayCritical_return +{ + self->in_critical_section ++; + self->critical_section_name = "GetPrimitiveArrayCritical"; +} + +hotspot_jni$target:::GetStringCritical_return +{ + self->in_critical_section ++; + self->critical_section_name = "GetStringCritical"; +} + + +:::END +{ + printf("%d critical section violations have been discovered\n", + CRITICAL_SECTION_VIOLATION_CNT); + + printf("\nEND of %s\n", SAMPLE_NAME); +} diff --git a/darwin-x86/sample/dtrace/hotspot_jni/README.txt b/darwin-x86/sample/dtrace/hotspot_jni/README.txt new file mode 100644 index 0000000..0c15a94 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot_jni/README.txt @@ -0,0 +1,64 @@ +================================ +'hotspot_jni' PROBES DESCRIPTION +================================ + +This directory contains D scripts which demonstrate usage of 'hotspot_jni' +provider probes. + +In order to call from native code to Java code, due to embedding of the VM +in an application or execution of native code within a Java application, the +native code must make a call through the JNI interface. The JNI interface +provides a number of methods for invoking Java code and examining the state +of the VM. DTrace probes are provided at the entry point and return point +for each of these methods. The probes are provided by the hotspot_jni +provider. The name of the probe is the name of the JNI method, appended with +"-entry" for entry probes, and "-return" for return probes. The arguments +available at each entry probe are the arguments that were provided to the +function (with the exception of the Invoke* methods, which omit the +arguments that are passed to the Java method). The return probes have the +return value of the method as an argument (if available). + +You can find more information about HotSpot probes here: +http://java.sun.com/javase/6/docs/technotes/guides/vm/dtrace.html + +=========== +THE SCRIPTS +=========== + +The following scripts/samples which demonstrate hotspot_jni probes usage are +available: + +- CriticalSection.d + Inspect a JNI application for Critical Section violations. + +- CriticalSection_slow.d + Do the same as CriticalSection.d but provide more debugging info. + +- hotspot_jni_calls_stat.d + This script collects statistics about how many times particular JNI method + has been called. + +- hotspot_jni_calls_tree.d + The script prints tree of JNI method calls. + +See more details in the scripts. + + +========== +HOW TO RUN +========== +To run any dscript from hotspot directory you can do either: + + # dscript.d -c "java ..." + + or if you don't have Solaris 10 patch which allows to specify probes that + don't yet exist ( Hotspot DTrace probes are defined in libjvm.so and as + result they could be not been yet loaded when you try to attach dscript to + the Java process) do: + + # ../helpers/dtrace_helper.d -c "java ..." dscript.d + + or if your application is already running you can just simply attach + the D script like: + + # dscript.d -p JAVA_PID diff --git a/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_stat.d b/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_stat.d new file mode 100644 index 0000000..8db9e16 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_stat.d @@ -0,0 +1,81 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. hotspot_jni_calls_stat.d -c "java ..." + * 2. hotspot_jni_calls_stat.d -p JAVA_PID + * + * This script collects statistics about how many times particular JNI + * method has been called. + * + */ + + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +:::BEGIN +{ + printf("BEGIN hotspot_jni tracing\n"); +} + + +hotspot_jni$target:::*-entry +{ + JNI_CALLS ++; + @jni_calls[probename] = count(); +} + +:::END +{ + printa("%10@d %s\n", @jni_calls); + printf("\n"); + printf("Total number of JNI calls: %d\n", JNI_CALLS); + + printf("\nEND hotspot_jni tracing.\n"); +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_tree.d b/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_tree.d new file mode 100644 index 0000000..7aeb208 --- /dev/null +++ b/darwin-x86/sample/dtrace/hotspot_jni/hotspot_jni_calls_tree.d @@ -0,0 +1,91 @@ +#!/usr/sbin/dtrace -Zs + +/* + * Copyright (c) 2006, 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. + */ + +/* +*/ + +/* + * Usage: + * 1. hotspot_jni_calls_tree.d -c "java ..." + * 2. hotspot_jni_calls_tree.d -p JAVA_PID + * + * The script prints tree of JNI method calls. + * + */ + +#pragma D option quiet +#pragma D option destructive +#pragma D option defaultargs +#pragma D option bufsize=16m +#pragma D option aggrate=100ms + + +self int indent; + +:::BEGIN +{ + printf("BEGIN hotspot_jni tracing\n"); +} + + +hotspot_jni$target:::* +/!self->indent/ +{ + self->indent = 11; +} + +hotspot_jni$target:::*-entry +{ + self->indent++; + printf("%d %*s -> %s\n", curcpu->cpu_id, self->indent, "", probename); +} + + +hotspot_jni$target:::*-return +{ + printf("%d %*s <- %s\n", curcpu->cpu_id, self->indent, "", probename); + self->indent--; +} + +:::END +{ + printf("\nEND hotspot_jni tracing.\n"); + +} + +syscall::rexit:entry, +syscall::exit:entry +/pid == $target/ +{ + exit(0); +} diff --git a/darwin-x86/sample/forkjoin/mergesort/MergeDemo.java b/darwin-x86/sample/forkjoin/mergesort/MergeDemo.java new file mode 100644 index 0000000..528f383 --- /dev/null +++ b/darwin-x86/sample/forkjoin/mergesort/MergeDemo.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.util.Arrays; +import java.util.Random; + +import static java.lang.Integer.parseInt; + +/** + * MergeExample is a class that runs a demo benchmark of the {@code ForkJoin} framework + * by benchmarking a {@link MergeSort} algorithm that is implemented using + * {@link java.util.concurrent.RecursiveAction}. + * The {@code ForkJoin} framework is setup with different parallelism levels + * and the sort is executed with arrays of different sizes to see the + * trade offs by using multiple threads for different sizes of the array. + */ +public class MergeDemo { + // Use a fixed seed to always get the same random values back + private final Random random = new Random(759123751834L); + private static final int ITERATIONS = 10; + + /** + * Represents the formula {@code f(n) = start + (step * n)} for n = 0 & n < iterations + */ + private static class Range { + private final int start; + private final int step; + private final int iterations; + + private Range(int start, int step, int iterations) { + this.start = start; + this.step = step; + this.iterations = iterations; + } + + /** + * Parses start, step and iterations from args + * @param args the string array containing the arguments + * @param start which element to start the start argument from + * @return the constructed range + */ + public static Range parse(String[] args, int start) { + if (args.length < start + 3) { + throw new IllegalArgumentException("Too few elements in array"); + } + return new Range(parseInt(args[start]), parseInt(args[start + 1]), parseInt(args[start + 2])); + } + + public int get(int iteration) { + return start + (step * iteration); + } + + public int getIterations() { + return iterations; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(start).append(" ").append(step).append(" ").append(iterations); + return builder.toString(); + } + } + + /** + * Wraps the different parameters that is used when running the MergeExample. + * {@code sizes} represents the different array sizes + * {@code parallelism} represents the different parallelism levels + */ + private static class Configuration { + private final Range sizes; + private final Range parallelism; + + private final static Configuration defaultConfig = new Configuration(new Range(20000, 20000, 10), + new Range(2, 2, 10)); + + private Configuration(Range sizes, Range parallelism) { + this.sizes = sizes; + this.parallelism = parallelism; + } + + /** + * Parses the arguments and attempts to create a configuration containing the + * parameters for creating the array sizes and parallelism sizes + * @param args the input arguments + * @return the configuration + */ + public static Configuration parse(String[] args) { + if (args.length == 0) { + return defaultConfig; + } else { + try { + if (args.length == 6) { + return new Configuration(Range.parse(args, 0), Range.parse(args, 3)); + } + } catch (NumberFormatException e) { + System.err.println("MergeExample: error: Argument was not a number."); + } + System.err.println("MergeExample <size start> <size step> <size steps> <parallel start> <parallel step>" + + " <parallel steps>"); + System.err.println("example: MergeExample 20000 10000 3 1 1 4"); + System.err.println("example: will run with arrays of sizes 20000, 30000, 40000" + + " and parallelism: 1, 2, 3, 4"); + return null; + } + } + + /** + * Creates an array for reporting the test result time in + * @return an array containing {@code sizes.iterations * parallelism.iterations} elements + */ + private long[][] createTimesArray() { + return new long[sizes.getIterations()][parallelism.getIterations()]; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(""); + if (this == defaultConfig) { + builder.append("Default configuration. "); + } + builder.append("Running with parameters: "); + builder.append(sizes); + builder.append(" "); + builder.append(parallelism); + return builder.toString(); + } + } + + /** + * Generates an array of {@code elements} random elements + * @param elements the number of elements requested in the array + * @return an array of {@code elements} random elements + */ + private int[] generateArray(int elements) { + int[] array = new int[elements]; + for (int i = 0; i < elements; ++i) { + array[i] = random.nextInt(); + } + return array; + } + + /** + * Runs the test + * @param config contains the settings for the test + */ + private void run(Configuration config) { + Range sizes = config.sizes; + Range parallelism = config.parallelism; + + // Run a couple of sorts to make the JIT compile / optimize the code + // which should produce somewhat more fair times + warmup(); + + long[][] times = config.createTimesArray(); + + for (int size = 0; size < sizes.getIterations(); size++) { + runForSize(parallelism, sizes.get(size), times, size); + } + + printResults(sizes, parallelism, times); + } + + /** + * Prints the results as a table + * @param sizes the different sizes of the arrays + * @param parallelism the different parallelism levels used + * @param times the median times for the different sizes / parallelism + */ + private void printResults(Range sizes, Range parallelism, long[][] times) { + System.out.println("Time in milliseconds. Y-axis: number of elements. X-axis parallelism used."); + long[] sums = new long[times[0].length]; + System.out.format("%8s ", ""); + for (int i = 0; i < times[0].length; i++) { + System.out.format("%4d ", parallelism.get(i)); + } + System.out.println(""); + for (int size = 0; size < sizes.getIterations(); size++) { + System.out.format("%8d: ", sizes.get(size)); + for (int i = 0; i < times[size].length; i++) { + sums[i] += times[size][i]; + System.out.format("%4d ", times[size][i]); + } + System.out.println(""); + } + System.out.format("%8s: ", "Total"); + for (long sum : sums) { + System.out.format("%4d ", sum); + } + System.out.println(""); + } + + private void runForSize(Range parallelism, int elements, long[][] times, int size) { + for (int step = 0; step < parallelism.getIterations(); step++) { + long time = runForParallelism(ITERATIONS, elements, parallelism.get(step)); + times[size][step] = time; + } + } + + /** + * Runs <i>iterations</i> number of test sorts of a random array of <i>element</i> length + * @param iterations number of iterations + * @param elements number of elements in the random array + * @param parallelism parallelism for the ForkJoin framework + * @return the median time of runs + */ + private long runForParallelism(int iterations, int elements, int parallelism) { + MergeSort mergeSort = new MergeSort(parallelism); + long[] times = new long[iterations]; + + for (int i = 0; i < iterations; i++) { + // Suggest the VM to run a garbage collection to reduce the risk of getting one + // while running the test run + System.gc(); + long start = System.currentTimeMillis(); + mergeSort.sort(generateArray(elements)); + times[i] = System.currentTimeMillis() - start; + } + + return medianValue(times); + } + + /** + * Calculates the median value of the array + * @param times array of times + * @return the median value + */ + private long medianValue(long[] times) { + if (times.length == 0) { + throw new IllegalArgumentException("Empty array"); + } + // Make a copy of times to avoid having side effects on the parameter value + Arrays.sort(times.clone()); + long median = times[times.length / 2]; + if (times.length > 1 && times.length % 2 != 0) { + median = (median + times[times.length / 2 + 1]) / 2; + } + return median; + } + + /** + * Generates 1000 arrays of 1000 elements and sorts them as a warmup + */ + private void warmup() { + MergeSort mergeSort = new MergeSort(Runtime.getRuntime().availableProcessors()); + for (int i = 0; i < 1000; i++) { + mergeSort.sort(generateArray(1000)); + } + } + + public static void main(String[] args) { + Configuration configuration = Configuration.parse(args); + if (configuration == null) { + System.exit(1); + } + System.out.println(configuration); + new MergeDemo().run(configuration); + } +} diff --git a/darwin-x86/sample/forkjoin/mergesort/MergeSort.java b/darwin-x86/sample/forkjoin/mergesort/MergeSort.java new file mode 100644 index 0000000..0ae48dc --- /dev/null +++ b/darwin-x86/sample/forkjoin/mergesort/MergeSort.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.util.Arrays; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveAction; + +/** + * A class for sorting an array of {@code ints} in parallel. + * A {@code ForkJoinPool} is used for the parallelism, using the merge sort + * algorithm the array is split into halves and a new sub task is created + * for each part. Each sub task is dispatched to the {@code ForkJoinPool} + * which will schedule the task to a {@code Thread}. + * This happens until the size of the array is at most 2 + * elements long. At this point the array is sorted using a simple compare + * and possibly a swap. The tasks then finish by using insert sort to + * merge the two just sorted arrays. + * + * The idea of this class is to demonstrate the usage of RecursiveAction not + * to implement the best possible parallel merge sort. This version creates + * a small array for each merge (creating a lot of objects), this could + * be avoided by keeping a single array. + */ +public class MergeSort { + private final ForkJoinPool pool; + + private static class MergeSortTask extends RecursiveAction { + private final int[] array; + private final int low; + private final int high; + private static final int THRESHOLD = 8; + + /** + * Creates a {@code MergeSortTask} containing the array and the bounds of the array + * + * @param array the array to sort + * @param low the lower element to start sorting at + * @param high the non-inclusive high element to sort to + */ + protected MergeSortTask(int[] array, int low, int high) { + this.array = array; + this.low = low; + this.high = high; + } + + @Override + protected void compute() { + if (high - low <= THRESHOLD) { + Arrays.sort(array, low, high); + } else { + int middle = low + ((high - low) >> 1); + // Execute the sub tasks and wait for them to finish + invokeAll(new MergeSortTask(array, low, middle), new MergeSortTask(array, middle, high)); + // Then merge the results + merge(middle); + } + } + + /** + * Merges the two sorted arrays this.low, middle - 1 and middle, this.high - 1 + * @param middle the index in the array where the second sorted list begins + */ + private void merge(int middle) { + if (array[middle - 1] < array[middle]) { + return; // the arrays are already correctly sorted, so we can skip the merge + } + int[] copy = new int[high - low]; + System.arraycopy(array, low, copy, 0, copy.length); + int copyLow = 0; + int copyHigh = high - low; + int copyMiddle = middle - low; + + for (int i = low, p = copyLow, q = copyMiddle; i < high; i++) { + if (q >= copyHigh || (p < copyMiddle && copy[p] < copy[q]) ) { + array[i] = copy[p++]; + } else { + array[i] = copy[q++]; + } + } + } + } + + /** + * Creates a {@code MergeSort} containing a ForkJoinPool with the indicated parallelism level + * @param parallelism the parallelism level used + */ + public MergeSort(int parallelism) { + pool = new ForkJoinPool(parallelism); + } + + /** + * Sorts all the elements of the given array using the ForkJoin framework + * @param array the array to sort + */ + public void sort(int[] array) { + ForkJoinTask<Void> job = pool.submit(new MergeSortTask(array, 0, array.length)); + job.join(); + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/build.properties b/darwin-x86/sample/jmx/jmx-scandir/build.properties new file mode 100644 index 0000000..cad4a6a --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/build.properties @@ -0,0 +1,58 @@ +# IMPORTANT NOTE +# +# If you made a private copy of this project you may have to update the +# nbjdk.home variable at the end of this file. +# +# To be able to run the test-suite, you will also have to set the +# variable: +# +# libs.junit.classpath=<junit.jar> +# + +main.dir=. + +src.dir=${main.dir}/src +test.src.dir=${main.dir}/test + +build.dir=build +classes.dir=${build.dir}/classes + +dist.dir=dist +jar=${dist.dir}/jmx-scandir.jar +javadoc.dir=${dist.dir}/javadoc + +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results + +build.sysclasspath=ignore +# E.g.: cp=lib/x.jar:lib/y.jar +cp= +extra.run.cp= + +# To be able to run the test-suite, set the following property: +# libs.junit.classpath=... + +javac.test.classpath=\ + ${classes.dir}:\ + ${libs.junit.classpath} + +main.agent.class=com.sun.jmx.examples.scandir.ScanDirAgent +main.client.class=com.sun.jmx.examples.scandir.ScanDirClient +main.class=${main.client.class} + +run.jvmargs=-Djava.util.logging.config.file=logging.properties +common.jvmargs=${run.jvmargs} -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword +client.jvmargs=${common.jvmargs} +agent.jvmargs=${common.jvmargs} -Dcom.sun.management.config.file=src/etc/management.properties -Dscandir.config.file=src/etc/testconfig.xml + +client.args=localhost 4545 + +run.cp=${cp}:${classes.dir}:${extra.run.cp} +run.test.classpath=${run.cp}:${build.test.classes.dir} + +debug=true +deprecation=false + +# Update this variable if need be to point to the JDK 6 location. +# +nbjdk.home=${basedir}/../../.. diff --git a/darwin-x86/sample/jmx/jmx-scandir/build.xml b/darwin-x86/sample/jmx/jmx-scandir/build.xml new file mode 100644 index 0000000..e54fcec --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/build.xml @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + + +<!-- + This is ant (http://ant.apache.org) build script to build the + "jmx-scandir" sample. Either this build.xml can be used standalone + with "ant" tool or can be opened as a project with NetBeans IDE + (http://www.netbeans.org). +--> + +<project name="jmx-scandir" default="jar" basedir="."> + + <import file="nbproject/jdk.xml"/> + + + <target name="-prop-init"> + <property file="user.build.properties"/> + <property file="build.properties"/> + </target> + + <target name="-init" depends="-prop-init,-jdk-init"/> + + <target name="compile" depends="-init" description="Compile main sources."> + <mkdir dir="${classes.dir}"/> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="${debug}" deprecation="${deprecation}"> + <classpath path="${cp}"/> + </javac> + <copy todir="${classes.dir}"> + <fileset dir="${src.dir}"/> + </copy> + </target> + + <target name="jar" depends="compile" description="Build JAR file for main sources."> + <mkdir dir="${dist.dir}" /> + <jar jarfile="${jar}" compress="true"> + <manifest> + <attribute name="Main-Class" value="${main.agent.class}"/> + </manifest> + <fileset dir="${classes.dir}"/> + </jar> + </target> + + <target name="run-client" depends="compile" description="Run client."> + <fail unless="main.client.class">Must set property 'main.client.class' (e.g. in build.properties)</fail> + <java classname="${main.client.class}" fork="true" failonerror="true"> + <classpath path="${run.cp}"/> + <jvmarg line="${client.jvmargs}" /> + <arg line="${client.args}" /> + </java> + </target> + + <target name="run-agent" depends="compile" description="Run agent."> + <fail unless="main.agent.class">Must set property 'main.agent.class' (e.g. in build.properties)</fail> + <java classname="${main.agent.class}" fork="true" failonerror="true"> + <classpath path="${run.cp}"/> + <jvmarg line="${agent.jvmargs}" /> + </java> + </target> + + <target name="run" depends="run-agent" description="Run agent." /> + + <target name="run-single" depends="-init,compile"> + <fail unless="run.class">Must select one file in the IDE or set run.class</fail> + <java classname="${run.class}" fork="true" failonerror="true"> + <classpath path="${run.cp}"/> + </java> + </target> + + <target name="javadoc" depends="-init" description="Build Javadoc."> + <mkdir dir="${javadoc.dir}"/> + <javadoc destdir="${javadoc.dir}"> + <classpath path="${cp}"/> + <sourcepath> + <pathelement location="${src.dir}"/> + </sourcepath> + <fileset dir="${src.dir}"/> + </javadoc> + </target> + + <target name="clean" depends="-init" description="Clean build products."> + <delete dir="${build.dir}"/> + <delete file="${jar}"/> + <delete dir="${dist.dir}"/> + </target> + + <target name="profile"> + <ant antfile="nbproject/netbeans-targets.xml" target="profile"/> + </target> + + <!-- JUnit targets --> + + <target name="compile-test" depends="-init,compile"> + <fail unless="libs.junit.classpath">Must set libs.junit.classpath variable to the JUnit classpath in the build.properties file.</fail> + <mkdir dir="${build.test.classes.dir}"/> + <javac srcdir="${test.src.dir}" destdir="${build.test.classes.dir}" debug="${debug}" classpath="${javac.test.classpath}"/> + <copy todir="${build.test.classes.dir}"> + <fileset dir="${test.src.dir}" excludes="**/*.java"/> + </copy> + </target> + + <target name="-do-test-run" depends="-init,compile-test"> + <mkdir dir="${build.test.results.dir}"/> + <junit showoutput="true" fork="true" dir="${basedir}" failureproperty="tests.failed" errorproperty="tests.failed"> + <batchtest todir="${build.test.results.dir}"> + <fileset dir="${test.src.dir}" includes="**/*Test.java"/> + </batchtest> + <classpath> + <path path="${run.test.classpath}"/> + </classpath> + <syspropertyset> + <propertyref prefix="test-sys-prop."/> + <mapper type="glob" from="test-sys-prop.*" to="*"/> + </syspropertyset> + <formatter type="brief" usefile="false"/> + <formatter type="xml"/> + <jvmarg line="${run.jvmargs}"/> + </junit> + <fail if="tests.failed">Some tests failed; see details above.</fail> + </target> + + <target name="test" depends="-init,compile-test,-do-test-run" description="Run unit tests."/> + + <target name="-do-test-run-single" depends="-init,compile-test"> + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail> + <junit showoutput="true" fork="true" dir="${basedir}" failureproperty="tests.failed" errorproperty="tests.failed"> + <batchtest todir="${build.test.results.dir}"> + <fileset dir="${test.src.dir}" includes="${test.includes}"/> + </batchtest> + <classpath> + <path path="${run.test.classpath}"/> + </classpath> + <syspropertyset> + <propertyref prefix="test-sys-prop."/> + <mapper type="glob" from="test-sys-prop.*" to="*"/> + </syspropertyset> + <formatter type="brief" usefile="false"/> + <formatter type="xml"/> + <jvmarg line="${run.jvmargs}"/> + </junit> + <fail if="tests.failed">Some tests failed; see details above.</fail> + </target> + + <target name="test-single" depends="-init,compile-test,-do-test-run-single" description="Run single unit test."/> +</project> diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-ant-run.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-ant-run.jpg Binary files differnew file mode 100644 index 0000000..6a58f0e --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-ant-run.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-java-jar.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-java-jar.jpg Binary files differnew file mode 100644 index 0000000..86add09 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local-java-jar.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local.jpg Binary files differnew file mode 100644 index 0000000..0259e96 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/connect-local.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection-failed.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection-failed.jpg Binary files differnew file mode 100644 index 0000000..001b0fa --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection-failed.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection.jpg Binary files differnew file mode 100644 index 0000000..90d07a0 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/remote-connection.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-config.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-config.jpg Binary files differnew file mode 100644 index 0000000..9e0a10c --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-config.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-result.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-result.jpg Binary files differnew file mode 100644 index 0000000..75e7baf --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-result.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-start.jpg b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-start.jpg Binary files differnew file mode 100644 index 0000000..5bceae5 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/docfiles/scandir-start.jpg diff --git a/darwin-x86/sample/jmx/jmx-scandir/index.html b/darwin-x86/sample/jmx/jmx-scandir/index.html new file mode 100644 index 0000000..4fd2ae6 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/index.html @@ -0,0 +1,2217 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> + <head> +<!-- + Copyright (c) 2006, 2013, 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. +--> + + <title>JMX(TM) "scandir" Example</title> + </head> + <body> + + <h1><center>Java<font size="-1"><sup>TM</sup></font> Management Extensions (JMX<font size="-1"><sup>TM</sup></font>) <i>scandir</i> Example</center></h1> + + <h2><a name="h2-Introduction">Introduction</a></h2> + <ul> + <p>The JMX <i>scandir</i> example is an application that + scans parts of a filesystem - e.g. a set of directories + used by a number of lab machines when running tests - in + order to clean up and optimize disk space by removing + obsolete files - e.g. files that are leaked by the test + suites running on those machines, like coredump files, or + temporary files that might remain after a test crash. + It could also serve as a basis for an application that + would monitor disk usage and suggest removal of old big + long-unaccessed files. + </p> + <p>The JMX <i>scandir</i> example does not however implement + the full fledged logic that such an application might + have. It implements a subset of this logic which is + sufficient to demonstrate common patterns and + solutions used when implementing a monitoring and + management interface for an application with JMX + Technology.</p> + <p>This example is an advanced JMX example, which presents + advanced JMX concepts. It is assumed that the reader is already + familiar with the JMX API. Newcomers to JMX Technology are + invited to have a look at the <a + href="http://java.sun.com/javase/6/docs/technotes/guides/jmx/" + >JMX API Overview, Tutorial and Examples</a> before going any further. + </p> + <p></p> + <hr> + <blockquote> + <u>Note:</u> This example was developed using <a + href="http://www.netbeans.org">NetBeans 5.0 IDE</a>. The instructions + given in this document to build, run, and test the example assume that + you have at your disposal: + <ul><li>either <a href="http://www.netbeans.org">NetBeans 5.0 IDE</a>,</li> + <li>or <a href="http://ant.apache.org/">Apache Ant 1.6.5</a> and + <a href="http://sourceforge.net/projects/junit/">JUnit 3.8.1 or + 3.8.2</a><br> + (JUnit is only needed to run the example's unit tests). + </li> + </ul> + <p><a name="setup">In order to build the example</a>, + <u>you may need to copy the jmx-scandir</u> + directory to somewhere where you have write permissions. + <br>In that case, you will need to update the <i>nbjdk.home</i> variable + in the copied <i><a href="build.properties">build.properties</a></i> + file located at the root of the copied project directory. + Please make sure that this variable points to the JDK 6 home directory. + </p> + <p>If you wish to run the testsuite from within the <a + href="http://www.netbeans.org">NetBeans IDE</a> you will also have + to set the <i>libs.junit.classpath</i> variable in + <a href="build.properties">build.properties</a>. + The <i>libs.junit.classpath</i> variable should point to your + <a href="http://sourceforge.net/projects/junit/">junit.jar</a>, + version 3.8.1 or 3.8.2. + </p> + </blockquote> + <hr> + <p></p> + <p><u>Table Of Contents:</u></p> + <p><center>[<a href="#h2-Generating">Generating the Java Documentation</a>] + [<a href="#h2-Overview">Overview of the <i>scandir</i> Example</a>] + [<a href="#h2-API-Doc">API Documentation and Sources</a>] + [<a href="#h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a>] + [<a href="#h2-Testing">Testing the <i>scandir</i> Example</a>] + [<a href="#h2-Running">Running the <i>scandir</i> Example</a>] + [<a href="#h2-Playing">Playing with JConsole</a>] + [<a href="#h2-Turning">Turning the example into a Secure JMX Application</a>] + [<a href="#h2-Connecting">Connecting to the Secure JMX Application</a>] + [<a href="#h2-Conclusion">Conclusion</a>] + [<a href="#h2-References">References</a>]</center></p> + + </ul> + <h2><a name="h2-Generating">Generating the Java Documentation</a></h2> + + <ul> + <p>Before reading further, you will need to generate the + Java Documentation for the example's sources.</p> + <p>In the example root directory (where the <code>build.xml</code> + file is located) run the following command: + <pre>ant javadoc</pre> + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE and generate the Javadoc from its <code>Build</code> + menu. + </p> + <p>If building the documentation fails, please make sure to read the + <a href="#setup">note</a> at the beginning of this document.</p> + </ul> + + <h2><a name="h2-Overview">Overview of the <i>scandir</i> Example</a></h2> + + <ul> + <p>The JMX <i>scandir</i> example is built around the + following MBeans:</p> + <ul> + <li>The first MBean we will present here is the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a>. <br>A + <code>DirectoryScannerMXBean</code> is an MBean that scans a + file system starting at a given root directory, and then looks + for files that match the given criteria. When such a file is + found, the <code>DirectoryScannerMXBean</code> takes the + action for which it was configured: emit a notification, + <i>and/or</i> log a <code>record</code> for this file, + <i>and/or</i> delete that file. The code that would actually + delete the file is commented out - so that nothing valuable is + lost if the example is run by mistake on the wrong set of + directories.<br> <code>DirectoryScannerMXBeans</code> are + created by the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> - see next item on the list, from its + configuration. + </li> + <li> + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> is the actual entry point of the + application. It reads the application's + configuration, and from that configuration, + will create a <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html" +title="The ResultLogManager is in charge of managing result logs" + >ResultLogManager</a> and some <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. + <br>The <code>ScanManagerMXBean</code> lets you start, stop, and + schedule directory scans. The + <code>ScanManagerMXBean</code> is a singleton + MBean: there can be at most one instance of such + an MBean registered in a given MBeanServer. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> is an MBean which is able to + load/save the configuration to/from an XML file. It + will also let you modify that configuration - by e.g. + creating new directory scanners in there. + The corresponding MBeans will be created later, only + when you later + ask the <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> to apply the + configuration again.<br> + The <code>ScanDirConfigMXBean</code> is created by the + <code>ScanManagerMXBean</code>, when the + <code>ScanManagerMXBean</code> is registered. + It is also possible to create an alternate + <code>ScanDirConfigMXBean</code>, and to switch the + <code>ScanDirConfigMXBean</code> to use one or the other + configuration. + <br>An example of XML configuration file is given + <a href="src/etc/testconfig.xml" + title="An Example Of Configuration" + >here</a>. Although you could edit such a file by + hand, it is easier to do it programmatically (or + with <a href="#JConsole">JConsole</a>) through + the <code>ScanDirConfigMXBean</code> interface. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> is in charge of managing result logs. + <br>Directory Scanners can be configured to log a + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/ResultRecord.html" +title="A ResultRecord contains information about a file matching the criteria of a Directory Scanner" + >ResultRecord</a> whenever they take action upon a file that + matches their criteria. The <code>ResultLogManagerMXBean</code> is + responsible for logging these result records. + The <code>ResultLogManagerMXBean</code> can be configured to log + such records to a flat file, or into a log held in memory, or + both. Both logs (file and memory) can be configured with a + maximum capacity. + <br>When the maximum capacity of the memory + log is reached, its first entry (i.e. its oldest entry) is + removed to make place for the latest one. + <br>When the maximum + capacity of the file log is reached, the file is + renamed by appending a tilde '~' to its name and a + new result log is created. + <br>The <code>ResultLogManagerMXBean</code> + will let you interactively clear these result logs, change their + capacity, and decide where (memory or file) to log. + The memory log is useful in that its content can be interactively + returned by the <code>ResultLogManagerMXBean</code>, while + the file log doesn't have this facility.<br> + The result logs are intended to be used by e.g. an offline + program that would take some actions on the files that + matched the scan criteria: + <br>The <i>scandir</i> application + could be configured to only produce logs (i.e. takes no + action but logging the matching files), and the real + action could be performed by another program or module (e.g. mail the result log to the engineer who + maintains the lab, or parse that log and delete all the + files listed there, or parse the log and prepare and send + a single mail to each owner of matching files, containing + the list of files they should consider deleting).<br> + The <code>ResultLogManagerMXBean</code> is a singleton + MBean created by the <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> + which reads and writes its configuration from the + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code>. + </li> + </ul> + <p>An application <code>main()</code> method is + provided in the <a + href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" + >ScanDirAgent</a> class. The <code>main()</code> simply registers + a <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> </code> in the platform MBeanServer, and + then waits for someone to call <code>close()</code> on the + <code>ScanManagerMXBean</code>. + </p> + <p>When the <code>ScanManagerMXBean</code> is registered, it + will create a default <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code> bound + to a default XML config file. + </p> + <p>The application's default XML config file is determined as + follows: + <ol> + <li>If the property <code>scandir.config.file</code> is + defined, the default application file will be the + file pointed to by this property. If that file + doesn't exist, it will be created when + <code>ScanDirConfigMXBean.save()</code> is + invoked. + </li> + <li>Otherwise the application config file is + assumed to be a file called <code>jmx-scandir.xml</code>, + located in the user's directory (as defined by + the System property <code>user.home</code>). + If that file doesn't exists, it will be created when + <code>ScanDirConfigMXBean.save()</code> is + invoked. + </li> + </ol> + <p>It is worth noting that this project is defined to + run with the following properties: + <pre>-Djava.util.logging.config.file=logging.properties</pre> + <pre>-Dscandir.config.file=src/etc/testconfig.xml</pre> + With <code>ScanDirAgent</code> defined as the project's + main class. Hence when you invoke from the NetBeans IDE + <i>Run Project</i> on the <i>jmx-scandir</i> project, + or <i>Run file</i> on the <code>ScanDirAgent</code>, the + application starts with the test configuration provided in + <a href="src/etc/testconfig.xml" + title="An Example Of Configuration" + >src/etc/testconfig.xml</a> + </p> + </ul> + <h2><a name="h2-API-Doc">API Documentation and Sources</a></h2> + <ul> + <p>Once generated, the Javadoc of example classes can + be found starting from <a href="dist/javadoc/index.html" + title="The API Documentation" + ><code>dist/javadoc/index.html</code></a>.</p> + <p>You can view the sources in the <a + href="src" + title="The Example Source Tree" + ><code>src</code></a> subdirectory.</p> + </ul> + <h2><a name="h2-Patterns">Patterns, Best Practices, and Common Pitfalls</a></h2> + <ul> + <p>This section discusses some common patterns and + design choices that this example demonstrates, and some pitfalls that + it avoids. + </ul> + <h3>MBeans or MXBeans?</h3> + <ul> + <p>What is an MXBean? MXBeans made their appearance in + J2SE 5.0 (Tiger), with the Management and Monitoring + API of the JVM. However, Java SE 6 is the first + Java SE release that contains a standard framework which + makes it possible to create and register your own MXBeans. + </p> + <p>MXBeans are a special kind of MBean, which once registered + in the MBeanServer, get automatically transformed into + OpenMBeans. From a developer point of view, nothing changes: + A Wombat MBean can become an MXBean simply by renaming + its <code>WombatMBean</code> interface into <code>WombatMXBean</code>.</p> + <p>Using MXBeans rather than plain Standard MBean brings its + own advantages:</p> + <ul> + <li> + Generic tools, like JConsole, will be able to + display and interact with your MXBeans nicely, even + if your MXBean interfaces reference custom types + - e.g. custom Java enums. This is because all the types + exposed by your MXBeans are converted to Open Types. + Just look at the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> with JConsole and you will + understand the benefits. + </li> + <li> + When writing a programmatic client, you can obtain + a proxy that implements the original MXBean interface, + and forget about the Open Type conversion. + The JUnit unit tests that come with this example + use this feature very widely. Have a look at them. + </li> + <li> + The MXBean framework also lets you nicely navigate + from one MXBean to another: your MXBeans can + have attributes and parameters which are proxies + to other MXBeans! We demonstrate this in the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> which exposes a list + of <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a></code> and points + towards a <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code>. + </li> + </ul> + <p>In short, MXBeans are so much easier to use that + this example doesn't even have a single regular + Standard MBean. + </p> + <p>See also <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html" +title="What is an MXBean?" + >What is an MXBean?</a> + and <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html" +title="Inter-MXBean references" + >Inter-MXBean References</a>. + </p> + <blockquote><u>Hint:</u> In order to simplify the task of coding a + JMX programmatic client, we recommend that getters, setters, and + operations defined in MBean and MXBean interfaces throw + <code>IOException</code>. Proxy objects will then be able + to rethrow directly any <code>IOException</code> received from + their underlying MBean Server connection, without wrapping + them into <code>UndeclaredThrowableExceptions</code>.<br> + Since the life cycle of the proxy object is not directly tied to + the life cycle of the MBean it proxies, you may also want to + have all methods in the MBean or MXBean interface throw + <code>InstanceNotFoundException</code> or more generally + <code>JMException</code>. + </blockquote> + </ul> + <h3>MBean Names - aka ObjectNames</h3> + <ul> + <p>As you must know if you've been studying JMX, MBeans are + named objects. The names of MBeans are represented by + instances of <code>ObjectName</code>. An ObjectName is + composed of a <i>domain</i>, followed by a colon ':', + followed by a comma-separated list of <i>key=value</i> + pairs.<br> + The ordering of the <i>key=value</i> pairs is not + important, but <code>ObjectNames</code> are case sensitive + (both keys and values are case sensitive) and <b>white space + is not ignored</b>.<br> + A common pitfall for JMX beginners is to inadvertently + insert white space after commas into an ObjectName, + and expect that two ObjectNames which differ only by such white + space will be considered identical. This is not the + case.<br> + As an example, the ObjectName '<b><code>D:k1=v1, k2=v2, k3=v3</code></b>' has + three keys, which are '<b><code>k1</code></b>', '<b><code> k2</code></b>', + and '<b><code> k3</code></b>': beware + of the space in the name of the second and third + keys!<br> + It is therefore a different ObjectName from + '<b><code>D:k1=v1,k2=v2,k3=v3</code></b>' (the keys are now + '<b><code>k1</code></b>', '<b><code>k2</code></b>', and + '<b><code>k3</code></b>'), but the same ObjectName as + '<b><code>D: k2=v2, k3=v3,k1=v1</code></b>', and yet different + from '<b><code>D:k2=v2, k3=v3, k1=v1</code></b>'! + <p>In this example, we are following the rules + for ObjectName suggested in the <a +href="http://java.sun.com/products/JavaManagement/best-practices.html" + >JMX Best Practices</a>:</p> + <ul> + <li>ObjectNames should be <a + href="http://java.sun.com/products/JavaManagement/best-practices.html#mozTocId654884" + >predictable</a> + </li> + <li>The domain part of our ObjectNames starts with a Java + package name + </li> + <li>Our ObjectNames contain a <code>type=</code> + key property. This property is different for every + object type in our domain. + </li> + <li>For every ObjectName with a given type, we have the same set of key + properties with the same syntax and semantics for their values - in + fact we only use an additional <code>name=</code> key. + </li> + <li>When there can only be one instance of a given type + there aren't any other key properties than <code>type=</code>. + The ObjectNames of the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, which are both singleton MBeans, are + composed in this way. + </li> + <li>When there can be several instances of a given type, + we differentiate them by further key properties. + To achieve this, we are using the most usual key property + in addition to <code>type=</code>: the <code>name=</code> key. + In this example, a key property list of the form + <code>type=X,name=Y</code> is always enough to uniquely name + an MBean. Tools like jconsole are usually aware + of the semantics of the <code>type=</code> key and + <code>name=</code> key, and are therefore able to + display this form of name in a way that + is easier to read than other name forms. + </li> + </ul> + <p>The rules listed above are implemented by a couple + of static helper functions in the <a +href="src/com/sun/jmx/examples/scandir/ScanManager.java" +title="ScanManager.java" + >ScanManager</a> class. See the code of the + <b><code>makeSingletonName</code></b> and + <b><code>makeMBeanName</code></b> methods. + </p> + </ul> + <h3>Inter MBean Navigation</h3> + <ul> + <p>One of the most common problems that needs to be solved + when designing a management interface with JMX is to + choose a representation for inter-MBean relationships.<br> + Prior to Java 6, there were basically three possible + choices:</p> + <ul> + <li><b>Make the relation appear in the ObjectName</b>. + For instance, if MBean B was contained in + MBean A, you could choose to name MBean B so + that its parent relationship with MBean A + appeared in its name. <br> + The obvious limitation of this solution is that + it only allows to model one such relation (an + MBean has only one name) and the relation must + be fixed - it cannot change during the life of + the MBean since the name of an MBean cannot + change.<br> + This scheme is therefore mostly used when + the application MBeans are modeling objects + which are conceptually contained within + each other in a tree-like structure. + <br>For instance, most MBean names defined by + <a href="http://jcp.org/en/jsr/detail?id=77" + >J2EE Management (JSR 77)</a> follow + this scheme. + </li> + <li><b>Design getters and setters (or operations) which + return <code>ObjectName</code> or + <code>ObjectName[]</code> values</b>. The ObjectNames + point to the MBeans which are related to that + object. For instance , <a + href="http://glassfish.dev.java.net/" + title="Open Source Java EE 5 Application Server" + >GlassFish</a> + defines MBeans which also use this pattern. + </li> + <li><b>Use the JMX RelationService</b>. The JMX RelationService + is quite powerful, but simple relationships often + do not justify that overhead. + </li> + </ul> + <p>In Java 6, these three possibilities still remain, but + the new MXBean framework brings up an interesting + alternative. Instead of returning an ObjectName or + an ObjectName array, <b>an MXBean can return a proxy</b> + to its related MXBeans. This is how we have chosen to + implement our inter MBean relationships in this + example: + <br>For instance the + <code>ScanManagerMXBean</code>/<code>DirectoryScannerMXBean</code> + relationship and the + <code>ScanManagerMXBean</code>/<code>ScanDirConfigMXBean</code> + relationships are implemented in this way. + <p> + The additional benefit, as compared to returning ObjectNames or + using the RelationService is that interface type of the MBeans + which are pointed to by the relationship becomes directly + apparent. The method: + <pre> + public Map<String,DirectoryScannerMXBean> getDirectoryScanners(); + </pre> + makes it immediately obvious that the MBeans to which we point are + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. It would have been much less obvious in prior + versions of Java SE, were the returned type would have had to be + <code>Map<String,ObjectName></code>, or + even worse just <code>Map</code>. + </p> + <p>However, it must be clear that the behaviour will be + quite different when an MXBean is returned as compared + to when a simple bean is returned. + </p> + <p>When an MXBean is returned, the remote client sees either + an ObjectName, if it is a generic client like jconsole, or + a proxy to a remote MXBean, if the client is working with the + MXBean interface. Invoking an operation on one of the + proxy returned by a method such as + <code>getDirectoryScanners</code> will cause the + MBean to be invoked on the remote server side. + </p> + <p>If <code>getDirectoryScanners</code> were + defined as: + <pre> + public Map<String,DirectoryScannerConfig> getDirectoryScanners(); + </pre> + then invoking a method on one of the returned objects + would have absolutely no effect on the remote + server side - because the returned objects in this + case would simply be a bunch of serialized data objects. + </p> + <p>It is worth noting that although an MXBean interface + can have getters and operations which return an MXBean + interface, a regular standard MBean shouldn't have + any getters or methods which return MBean interfaces or + MXBean interfaces. + </p> + <p>For more information see also <a +href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/intermxbean_ref.html" +title="Inter-MXBean references" + >Inter-MXBean References</a>. + </p> + </ul> + <h3>The MBeanRegistration interface, or how an MBean can + know or provide its own name</h3> + <ul> + <p> + Sometimes, an MBean needs to have a reference to the + MBeanServer in which it is registered, or needs to know + with which ObjectName it has been registered. + </p> + <p> + Sometimes also, an MBean may need to perform some + checks before being registered, or will need + to carry out some actions right after it has been + successfully registered in the MBeanServer. + </p> + <p> + Sometimes again, an MBean may need to perform some + checks, or some cleaning actions, just before, or + just after, it is unregistered. + </p> + <p> + When an MBean has such needs, the easiest solution + for it is to implement the <code>MBeanRegistration</code> + interface. + </p> + <p>The <code>MBeanRegistration</code> interface is a callback + interface which defines pre and post registration and + unregistration callbacks. + </p> + <p> + When an MBean implementing this interface is created + (with <code>createMBean</code>) or registered + (with <code>registerMBean</code>) in an MBeanServer, + the MBeanServer will call the <code>preRegister</code> + and <code>postRegister</code> method implemented by + the MBean. The <code>preRegister</code> method + has an <code>MBeanServer</code> and <code>ObjectName</code> + parameter, which are passed by the MBeanServer to the + MBean. The MBean can store the reference it is being passed + in a private instance variable for later use. + </p> + <p> + Most of the MXBeans we have defined in this example + implement the <code>MBeanRegistration</code> interface. The table + below show how our MBeans use this interface to control + their own names, make sanity checks, perform + initialization steps or cleanup actions. + </p> + <p><br><center> + <table border="1" cellpadding="4" cellspacing="2" + bgcolor="#eeeeee" width="95%"> + <thead> + <tr bgcolor="#cecece"> + <th width="20%">MBean Requirement</th> + <th>callback</th> + <th>use case example</th> + </tr> + </thead> + <tbody> + <tr> + <td bgcolor="#dedede">get a reference to the MBeanServer</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> needs a reference + to the MBeanServer in order to create and + register other MBeans, such as the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, and the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">reject registration if conditions are + not met. + </td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> will throw + an IllegalArgumentException in <code>preRegister</code> + if the ObjectName it is being passed is + illegal. Throwing an exception in + <code>preRegister</code> makes the registration fail. + </td> + </tr> + <tr> + <td bgcolor="#dedede">get my client-assigned MBean name</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> propagates the + value of the <code>name=</code> property of + the ObjectName it is given into its + ScanManagerConfig bean. + </td> + </tr> + <tr> + <td bgcolor="#dedede">provide my own default ObjectName if none + was given to the MBeanServer + </td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The name that is returned by <code>preRegister</code> + is the ObjectName with which the MBean will be + eventually registered. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> is able to suggest + a value for its own ObjectName if none was + provided. Similarly, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> + always returns its singleton ObjectName + defined by <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html#SCAN_MANAGER_NAME" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean.SCAN_MANAGER_NAME</a>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">perform initialization steps</td> + <td><code>preRegister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> uses <code>preRegister</code> + to initialize its internal ScanManagerConfig bean. + </td> + </tr> + <tr> + <td bgcolor="#dedede">perform initialization steps, once it is + known that the registration was successful. + </td> + <td><code>postRegister</code></td> + <td bgcolor="#fafafa">The <code>postRegister</code> method + can be used to implement + initialization steps that need to be done once it + is known that the registration was successful, or to + undo any action performed by <code>preRegister</code> once it + is known that registration was not successful. + The <code>postRegister</code> method has a Boolean parameter + which tells the MBean whether it was or wasn't + successfully registered in the MBeanServer. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses <code>postRegister</code> to create + and register other MBeans, such as the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> and the default + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a>. + Note that <code>postRegister</code> is not expected to throw any + exception. If an exception needs to be thrown, it should + be thrown in <code>preRegister</code>. + </td> + </tr> + <tr> + <td bgcolor="#dedede">check whether the MBean can be deregistered</td> + <td><code>preDeregister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses this method to verify + that its state allows it to be deregistered. + In particular, it will refuse to be deregistered + if it is in the RUNNING or SCHEDULED state. + If <code>preDeregister</code> throws an exception, the unregisterMBean + call will fail and the MBean will remain registered in + the MBeanServer. + Take particular care when implementing business logic + in this method: if the logic you implement has an + unfortunate bug which makes it always throw an + exception, you will never be able to unregister + that MBean. + </td> + </tr> + <tr> + <td bgcolor="#dedede">clean up resources, refusing to be deregistered if + it fails + </td> + <td><code>preDeregister</code></td> + <td bgcolor="#fafafa">The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses this method to unregister + all the other MBeans it has created and registered in the + MBeanServer. This includes the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a>, the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBeans</a> it has created, and the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a> it has created when + applying its configuration. + </td> + </tr> + <tr> + <td bgcolor="#dedede">clean up resources which need to be released in + a best-effort way, when it is known that the MBean is no + longer registered. + </td> + <td><code>postDeregister</code></td> + <td bgcolor="#fafafa"><code>postDeregister</code> is only called if the MBean was succesfully + unregistered. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses this method to cancel + its internal java.util.Timer. + </td> + </tr> + </tbody> + </table> + </center><br></p> + </ul> + <h3>The Singleton MBean Pattern</h3> + <ul> + <p> + A singleton MBean is an MBean which can only have one + instance registered in a given MBeanServer. <br> + A singleton MBean usually has a well-known name, + which can be defined as a constant. In that case, + clients no longer need to call <code>new ObjectName(...)</code> + and catch the declared <code>MalformedObjectNameException</code>. + </p> + <p>There are already quite a few examples of singleton + MBeans in the java.lang.management API. The + ThreadingMXBean, ClassLoadingMXBean, RuntimeMXBean, etc. + are all singleton MBeans. + </p> + <p>In this example, we have two singleton MBeans: + The <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a></code> and the + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code>. But in fact, + the only real singleton MBean is the + <code>ScanManagerMXBean</code>. The + <code>ResultLogManagerMXBean</code> just happens to + be a singleton MBean because it has a 1-1 relationship + with the <code>ScanManagerMXBean</code>. + </p> + <p>The <code>ScanManagerMXBean</code> implements the + singleton MBean pattern in this way: + </p> + <ul> + <li>The <code>ScanManagerMXBean</code> name has a single + key property: <code>type=ScanManagerMXBean</code>.</li> + <li>Its name is defined by an ObjectName constant called + <code>SCAN_MANAGER_NAME</code> in the <code>ScanManager</code> class</li> + <li>The <code>ScanManagerMXBean</code> enforces its status of + singleton MBean. It will refuse to be registered + with a name other than + the <code>SCAN_MANAGER_NAME</code>. You can therefore depend on + the fact that the <code>ScanManagerMXBean</code> will always + be registered with its singleton <code>SCAN_MANAGER_NAME</code> + (see <code>preRegister</code>) + </li> + <li>You are not obliged to provide a name when you + register the <code>ScanManagerMXBean</code>: if you pass null, + then the <code>ScanManager</code> will be registered with + its singleton <code>SCAN_MANAGER_NAME</code> + (see <code>preRegister</code>). + </li> + <li>The <code>ScanManager</code> class has a no-arg static + <code>register</code> method that will register + the singleton instance in the Platform MBeanServer. + This static <code>register</code> method returns + a proxy to the registered singleton. + </li> + <li>The <code>ScanManager</code> class has also a static + <code>register</code> method that will create + a singleton instance in a (possibly remote) + MBeanServerConnection - using + <code>createMBean</code>. + This static <code>register</code> method + also returns a proxy to the registered singleton. + </li> + <li>Only the MBeanServer has a reference to the + singleton instance. The singleton instance is + not returned to the caller, and not kept + in any other static data structure. + </li> + </ul> + <p> + On the other hand, the <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code> + has a much more relaxed implementation of the pattern: + <br>It simply provides its own singleton name if it is + registered with a null ObjectName, but will not enforce + the use of that name. + </p> + <p>Note that all singleton MBean names in this example + are created using the <code>ScanManager.makeSingletonName</code> + method, which implements the pattern for ObjectNames suggested + in the JMX Best Practices. + </p> + </ul> + <h3>Managing the Life Cycle of dependent MBeans</h3> + <ul> + <p>A common task that many JMX applications have + is to manage the life cycle of MBeans registered + in the MBeanServer.</p> + <p>In this example, we have decided to follow a simple + pattern:</p> + <ul> + <li>The application is initialized simply + by registering the singleton + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> in + the MBeanServer. + </li> + <li>The <code>ScanManagerMXBean</code> will then + in turn register any other MBean that the + application might need: + <ul> + <li>It creates and registers the singleton + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a></code> + </li> + <li>It creates and registers the default + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a></code> + which loads the initial configuration + </li> + <li>It creates as many + <code><a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBeans</a></code> as + needed when the configuration is applied + </li> + <li>It lets you create alternate + <code>ScanDirConfigMXBean</code>, to + which you can later switch in order + to apply a new alternate configuration. + </li> + </ul> + </li> + <li>When a new configuration is applied (or if the + current configuration is reapplied), the + <code>ScanManagerMXBean</code> will unregister + any <code>DirectoryScannerMXBeans</code> it has + previously registered, and will re-create + brand new <code>DirectoryScannerMXBeans</code> + from the applied configuration. + </li> + <li>When you unregister the <code>ScanManagerMXBean</code>, + it does all the cleanup for you, by unregistering + all the MBeans that it has created during the + course of the application. + </li> + </ul> + <p>The <code>ScanManagerMXBean</code> makes use of its + <code>MBeanRegistration</code> interface in order + to register the other MBeans it needs (see the + <code>ScanManager.postRegister</code> method) and to unregister + every MBean it has created (see the <code>ScanManager.preDeregister</code> + method). + </p> + <p>You will note that the <code>ScanManagerMXBean</code> + will only allow itself to be deregistered if it can be + closed - that is if there's no other action in + progress. + This is to make sure that the deregistration of + dependent MBeans will work smoothly. + <br> + The deregistration of related MBeans will happen + in the <code>ScanManager.preDeregister</code> + method. + <br> + If one of these MBeans could not be deregistered, + then the <code>ScanManagerMXBean</code> will throw + an exception, refusing to be deregistered. + <br>This leaves you a chance to try to deregister it + again later. Since the <code>ScanManagerMXBean</code> + has switched its state to CLOSED before starting + to unregister its dependent MBeans, it will refuse + any further actions, ensuring that e.g. nobody + can try to start it or schedule it while it + is in that partially-deregistered state. + </p> + <p>Handling the LifeCycle of all the application's + MBeans in a single MBean is usually a good design + pattern, especially if the application is a + module which is intended to share a JVM - or + an MBeanServer - with other modules. + </p> + <p>This is specially useful if the application needs to + be loaded and unloaded on demand: in that + case, simply registering or unregistering the top level + MBean (in our example the <code>ScanManagerMXBean</code>) does + the trick. + </p> + </ul> + <h3>Emitting Notifications</h3> + <ul> + <p>In order to emit notifications, an MBean must be + an instance of <code>NotificationEmitter</code>. + The <code>NotificationEmitter</code> interface defines methods + that the MBeanServer will call on the MBean in order + to register <code>NotificationListeners</code> with the MBean. + </p> + <p>It is worth noting that the MBean may not be + invoked each time a JMX client wants to register + a listener. For instance, the RMIConnectorServer + registers <i>only once</i> a single listener with each MBean + which is a <code>NotificationEmitter</code>. + In that specific case, the listener may even be registered + with the MBean before any client has actually subscribed + for notifications from that particular MBean. + </p> + <p>An MBean can therefore make no assumption about + which client or how many clients have registered for + notifications. + </p> + <p>It is also worth noting that the logic of the + methods defined in <code>NotificationEmitter</code> would not + be trivial to implement from scratch. Fortunately + the JMX API defines a helper class, called + <code>NotificationBroadcasterSupport</code>, which + provides an implementation for these methods. + </p> + <p>There are actually three ways for an MBean to + implement <code>NotificationEmitter</code>, of which only two + are recommended. + </p> + </ul> + + <h4>Extending NotificationBroadcasterSupport</h4> + <ul> + <p>This is the simplest way of coding an MBean which + is a <code>NotificationEmitter</code>: + </p> + <p>Simply extend <code>NotificationBroadcasterSupport</code>, + then override its <code>getNotificationInfo</code> method + which returns the <code>MBeanNotificationInfo[]</code> array + that should be included in your MBean's <code>MBeanInfo</code> + and that's it. + <br>You just need to call the <code>sendNotification</code> method + inherited from <code>NotificationBroadcasterSupport</code> whenever + your MBean needs to send a notification. + </p> + <p>In our example, both the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> extend + <code>NotificationBroadcasterSupport</code> in order + to send notifications. + </p> + </ul> + <h4>The Delegation Pattern: delegating to a + NotificationBroadcasterSupport delegate</h4> + <ul> + <p>There may be cases however where delegating to a + wrapped <code>NotificationBroadcasterSupport</code> + object may be preferred to extending + <code>NotificationBroadcasterSupport</code>. + </p> + <p>For instance, if your MBeans already derive from + some base class, extending <code>NotificationBroadcasterSupport</code> + might not be an option. + </p> + <p>Similarly, if you do not want to have the inherited + <code>public void sendNotification(Notification notification)</code> + method appear in the Javadoc of the concrete class of your + MBean, you may want to consider using the delegation + pattern instead of extending + <code>NotificationBroadcasterSupport</code> + </p> + <p>In our example both the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> use the delegation + pattern rather than extending + <code>NotificationBroadcasterSupport</code>. + In the end, choosing between one or the other method + is more a question of taste, although the delegation + pattern could be considered more flexible since it + doesn't require extending any given superclass. + </p> + <p>It may be also worth noting that some tools like + the JMX Module of <a +href="http://www.netbeans.org" + >NetBeans IDE</a>, will be able to + generate for you all the code that delegates to a + wrapped <code>NotificationBroadcasterSupport</code>. + </p> + </ul> + + <h4>Implementing NotificationEmitter from scratch</h4> + <ul> + <p>This is the last possibility for an MBean that + needs to send notifications: simply implement + <code>NotificationEmitter</code> from scratch. This is highly + discouraged since that logic is not trivial, and + already provided by + <code>NotificationBroadcasterSupport</code> anyway. + </p> + </ul> + + <h4>Beware of Synchronization Locks</h4> + <ul> + + <p>One thing you must keep in mind when sending + notifications is not to send them from within + a synchronized block, or while holding a lock on + some resource.</p> + <p>Indeed, what happens when you send a notification + may vary greatly depending on whether the client + which has registered for notifications has done + so through a <code>JMXConnector</code> (like the + <code>JMXRMIConnector</code>) + or through a direct reference to the MBeanServer + (by calling + <code>MBeanServer.addNotificationListener</code>). + </p> + <p>In this latter case, the listener will be invoked + synchronously in the same thread that your MBean is + using to send its notification. If by misfortune, the + code of that listener now re-enters your MBean through a + call that flows through a JMXConnector, a deadlock + could occur. It is therefore very important to release + any lock you may have before calling + <code>sendNotification</code>.</p> + <p>An easy way to do that is demonstrated in the + <code>ScanManager</code> class. The ScanManager + has an internal private queue of pending notifications. + When a notification needs to be sent (e.g. because the + ScanManager state is being switched), the notification + is simply prepared and put into the pending notification + queue. + The notification queue is then processed later on, + at the end of the method, when the processing is finally + completed and all the locks have been released. + <br>At this point the notification queue might already + have been emptied by another thread - in which case + the pending notifications will have already been + removed from the queue. Which thread actually gets + to send the notifications is of no importance. The + important point is that all the locks detained by + your MBean code in that thread were released before + the notification was sent. + </p> + <p>In our example the <code>ScanManager</code> class + ensures this by: + <ul> + <li>Only calling <code>sendNotification</code> + in its private <code>sendQueuedNotifications</code> + method. + </li> + <li>Only calling <code>sendQueuedNotifications</code> + when all locks have been released. + </li> + <li>Never calling a method that calls + <code>sendQueuedNotifications</code> from within + a synchronized block.</li> + </ul> + </p> + </ul> + + + + <h4>Don't subclass Notification</h4> + <ul> + <p>Another common best practice when you want + to improve interoperability is to use directly + the Notification base classes provided in the + JMX<sup>TM</sup> API. Do not create your own + subclasses of these standard classes. + </p> + <p>Indeed, if you code your own subclass, a generic + client, like jconsole, will not be able to receive + that notification unless it has that custom + subclass in its classpath. + </p> + <p> + If you want your application to be interoperable, it is + therefore preferable not to subclass any of the standard + Notification classes. You can define your own + Notification type string, and if you need to send + additional data, you can put a CompositeData, or a + HashMap of serializable standard types in the + Notification's user data fields. + </p> + <p>In this example, we are using directly the + standard notification classes: + <ul> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> both use directly + <code>AttributeChangeNotification</code> to notify + changes in their <code>State</code> attribute. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> + also uses the base <code>Notification</code> + class directly in order to notify whenever + it finds a matching file. + <br>In that case, we simply use the base + <code>Notification</code> + class with a new + <b><code>com.sun.jmx.examples.scandir.filematch</code></b> + type. + </li> + <li>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> and <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" +title="The ResultLogManagerMXBean is in charge of managing result logs" + >ResultLogManagerMXBean</a> also both use the base + <code>Notification</code> class. + </li> + </ul> + <p>Careful readers will have noted that the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" +title="A DirectoryScannerMXBean looks for file matching a given set of criteria, starting at a given root." + >DirectoryScannerMXBean</a> both use the + <code>AttributeChangeNotification</code> class + to notify about their state change, whereas the + <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> uses the base + <code>Notification</code> class. + </p> + <p>In fact, this is because the semantics of these + notifications is not exactly the same - although + both denote a state change: + <ul> + <p>In the case of <code>ScanManagerMXBean</code> + and <code>DirectoryScannerMXBean</code>, the + notification which is emitted is more about a + state transition, from one state to another. + For instance, going from <code>RUNNING</code> + to <code>STOPPED</code>, or from + <code>SCHEDULED</code> to <code>STOPPED</code>. + <br>In that case, the + <code>AttributeChangeNotification</code> was + more appropriate because it made it possible + to send the previous and the new value of the + state attribute, thus reflecting the whole + state transition. + </p> + <p>In the case of the <code>ScanDirConfigMXBean</code> + however, what is of interest is the state in + which the MBean has arrived. Using the base + <code>Notification</code> class with three different + notification type strings - + <b><code>com.sun.jmx.examples.scandir.config.loaded</code></b>, + <b><code>com.sun.jmx.examples.scandir.config.modified</code></b>, + and + <b><code>com.sun.jmx.examples.scandir.config.saved</code></b> - + was therefore closer to what we wanted to model. + </p> + </ul> + </p> + </ul> + + <h3>Configuration MBeans</h3> + <ul> + <p>A common practice when designing a management application is + to have an MBean, or a set of MBeans, dedicated to configuration. + Separating configuration from control and monitoring allows + more appropriate logic, and often simplifies the design and + implementation of the management interface. + </p> + <p> + In our example, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a> is dedicated to the application configuration. + </p> + <p>The <code>ScanDirConfigMXBean</code> will let you interactively + modify, save, or load the application configuration. The modifications + will not be taken into account until it is applied, by invoking + <code>applyConfiguration</code> on the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a>. + It is also possible to create many configurations, by creating as + many <code>ScanDirConfigMXBean</code>s, and then to choose and apply + one of these configurations by calling + <code>ScanManagerMXBean.setConfigurationMBean</code> and then + <code>ScanManagerMXBean.applyConfiguration</code>. + </p> + <p>In this way, all configurations aspects are gathered and concentrated + inside the <code>ScanDirConfigMXBean</code> instead of being scattered + throughout all the MBeans that compose the application. + </p> + <p>In order to save and store the application configuration data, the + <code>ScanDirConfigMXBean</code> uses a set of XML serializable Java beans + defined in the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/package-summary.html" +title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans" + >com.sun.jmx.examples.scandir.config</a> package. These beans are very + simple Java beans which have been lightly annotated for XML binding. + </p> + <p>It is worth noting that these same beans can also be handled by the + MXBean framework (our beans don't contain recursive data structures) and can + therefore be used directly as attributes and parameters of MXBeans, without + needing to be Java-serializable (the MXBean framework transform them in + CompositeData objects - which <b>are</b> serializable). + </p> + <p>The same <a +href="dist/javadoc/com/sun/jmx/examples/scandir/config/ScanManagerConfig.html" +title="The com.sun.jmx.examples.scandir.config package defines XML serializable beans" + >ScanManagerConfig</a> bean that we use to read from and write to the + XML configuration file is thus also used as attribute of the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" +title="The ScanDirConfigMXBean is in charge of the configuration" + >ScanDirConfigMXBean</a>. It is transformed into a <code>CompositeData</code> + by the MXBean framework, and can be easily introspected with + <a href="#JConsole">jconsole</a>. + </p> + </ul> + <h3>MBeans Must Be Thread-Safe</h3> + <ul> + <p>A question often asked by newcomers to JMX technology + is whether the MBeanServer is thread-safe. Well, the MBeanServer <b>is</b> + thread safe, but it doesn't put any locks on the MBeans it contains. The + MBeans can be concurrently accessed by multiple threads, and must therefore + take care of their own thread safety. + </p> + <p>In this example, we have been using two methods to ensure thread + safety for our MBeans: synchronized blocks, and semaphores. + </p> + <p>Using synchronized blocks is probably the most common and easiest way + to implement thread safety in Java. When dealing with MBeans though, here + are a couple of rules to keep in mind: + <ul> + <li>Don't send notifications from within a synchronized block: there's + no way to tell whether the listener's code will be executed in the + same thread or a different thread, and holding a lock in these + conditions is therefore dangerous, as it could lead to deadlocks.</li> + <li>Also avoid invoking another MBean from a synchronized block + unless you are completely in control of both MBeans, and you can + ascertain that it won't lead to any deadlock. Indeed, if you invoke an + MBean exposed by another application, it can be sometime hard to + know with certainty whether holding a lock while invoking that + MBean will have any side effect. Maybe that MBean will make + further calls to other MBeans which will in turn try to call + your MBean, or maybe it will emit a + notification, and we'll be back to the considerations just + above.</li> + </ul> + </p> + <p>Another means of implementing thread-safe code is to use semaphores. + The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> uses a semaphore called + <code>sequencer</code> to ensure + that critical code sections are not executed concurrently. In this + MBean, we use <code>Semaphore.tryAcquire</code> to lock the sequencer + semaphore before entering the critical section. If the + <code>Semaphore.tryAcquire</code> returns true then we enter the critical + section. If it returns false, we throw an IllegalStateException, stating + that we couldn't acquire the lock. The code looks like this: + <pre> + if (!sequencer.tryAcquire()) + throw new IllegalStateException("resource locked"); + try { + // critical code here ... + } finally { + // Always use try/finally to ensure that the semaphore + // will be released, even if exceptions or errors are raised! + sequencer.release(); + } + </pre> + </p> + <p>Using <code>Semaphore.tryAcquire</code> and throwing an exception if + the semaphore is already locked makes it safer to call other MBeans + from within the critical section: in potential deadlock situations + the calling code will get the <code>IllegalStateException</code> + instead of being blocked on the deadlocked lock. + </p> + <p>It is worth noting that each of these techniques has its own + advantages and disadvantages - which can make one of them more or less + appropriate depending on the inner logic of the MBean you're implementing. + </p> + <p>Careful readers will also have noted that we used + <code>IllegalStateException</code> directly, instead of defining + our own subclass of RuntimeException, which could have had a more + precise semantics. If you define a new exception for your JMX application, + you must keep in mind that your client will need to have the class + of your exception in its classpath to get that exception. + Otherwise your client will get a completely different exception, indicating a + deserialization issue. + </p> + </ul> + + <h3>Waiting for Notifications</h3> + <ul> + <p>Implementing code that needs to wait for notifications is sometimes + difficult. Because notifications are asynchronous, doing something + like: + <pre> + // register a notification listener + ... + // start a management action + ... + // wait for a notification + ... + // do something based on whether the expected notification + // is received + ... + </pre> + is not always trivial. However, there's a very easy way to do that: use + a blocking queue of notifications. + <pre> + final BlockingQueue<Notification> notifQueue = + new LinkedBlockingQueue<Notification>(); + + final NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + // Just put the received notification in the queue. + // It will be consumed later on. + // + notifQueue.put(notification); + } catch (InterruptedException ex) { + // OK + } + } + }; + + // register the listener - possibly also as a JMXConnectionNotification + // listener to get Notification Lost notification + ... + // start management action + ... + // wait for notification + while (expected notif not received and delay not expired) { + Notification n = notifQueue.poll(3,TimeUnit.SECONDS); + // if expected notif, do something + ... + } + // if expected notification not received do something else. + .... + </pre> + </p> + <p>You will note that this is a technique we've been using in the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" +title="The ScanDirAgent class defines a main method for the scandir application" + >ScanDirAgent</a> class and in the example unit tests. + </p> + </ul> + + <h3>Holding hard references to other MBeans: proxy or direct reference?</h3> + <ul> + <p>We have seen that MXBeans will let you return proxy references to other + MXBeans. But should that MXBean hold a direct reference to the MXBeans it + relates to, or would it be better for it to hold only a proxy? + </p> + <p> + As a general rule it is better when an MBean reference is + only held by the MBeanServer. It is a better design + to hold a reference to a proxy, rather than to hold + a hard reference to an MBean. However there are two cases + when holding a hard reference might be preferred: + <ol> + <li>When MBean A needs to call a method of method B which + is not part of its MBean interface</li> + <li>When the overhead of going through the MBeanServer + plus the MXBean framework is too great (frequently-called + method, with creation of OpenType)</li> + </ol> + However - holding a hard reference is only advisable + when both MBeans are created by the same piece of code, + and the application can ensure that the life cycle + of each MBean is consistent with regard to the other. + </p> + <p>In our example, the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> holds only proxy references to the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.html" + >ScanDirConfigMXBean</a> and the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.html" + >DirectoryScannerMXBeans</a>. <br> + However it holds a direct reference to the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManager.html" + >ResultLogManager</a>. This makes it possible to pass a direct + reference to the <code>DirectoryScannerMXBeans</code>, + which can then log their results + more efficiently, and would also make it possible to remove + the <code>log</code> method from the <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.html" + >ResultLogManagerMXBean</a> interface - leaving it in the + <code>ResultLogManager</code> class (possibly as a package method) + should we wish to do so. + </p> + + </ul> + + <h3>Agent Class</h3> + <ul> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirAgent.html" +title="The ScanDirAgent class defines a main method for the scandir application" + >ScanDirAgent</a> is the Agent class for the <i>scandir</i> application. + This class contains the <code>main</code> method to start a standalone + <i>scandir</i> application. + </p> + <p>The <code>main</code> method simply registers a <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a> in the platform MBeanServer, and then waits + for someone to call <code>ScanManagerMXBean.close</code>. + </p> + <p> + When the <code>ScanManagerMXBean</code> state is switched to + <code>ScanManagerMXBean.ScanState.CLOSED</code>, the + <code>ScanManagerMXBean</code> is unregistered, and the application + terminates (i.e. the main thread completes). + </p> + <p>Standalone JMX applications usually have an Agent class that contain + their <code>main</code> method, which performs all the MBean + registration steps. + However, it is usually not a bad idea if that class can + be easily turned into an MBean. Indeed, this will make your + application easier to integrate in an environment where it would + no longer be standalone and would no longer control the implementation + of <code>main</code>. In our example the Agent + class could be easily turned into an MBean, exposing its three + <code>init</code>, <code>waitForClose</code> and <code>cleanup</code> + method. However we didn't go as far as turning it into an MBean since + the application can be already easily started by registering an instance + of <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanManagerMXBean.html" +title="The ScanManagerMXBean is the main MBean of the scandir application" + >ScanManagerMXBean</a>. + </p> + </ul> + <h3>Secure Client Class</h3> + <ul> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" +title="The ScanDirClient class is a very short example of secure programmatic client" + >ScanDirClient</a> is an example class that shows how a + programmatic client can connect to a secured <i>scandir</i> application. + This class contains a <code>main</code> method which creates and + configures a <code>JMXConnector</code> client to connect with + a secured <i>scandir</i> daemon. This class will not work with + the default unsecured agent since it requires mutual authentication. + </p> + <p>How to secure a JMX <i>scandir</i> application and run + the secure <code>ScanDirClient</code> is discussed <a href="#secure" + >later</a> in this document. + </p> + <p>The <code>ScanDirClient</code> is not really part of the + application - and is given here only for the sake of + the example. + </p> + </ul> + + <h2><a name="h2-Testing">Testing the <i>scandir</i> Example</a></h2> + <ul> + <p>Make sure that you have access to junit.jar (either 3.8.1 or 3.8.2). + Make sure also that you have junit.jar in your + <code>CLASSPATH</code>.<br> + Then in the example root directory (where the <code>build.xml</code> + file is located) run the following command: + <pre>ant test -Dlibs.junit.classpath=<i><u>path to junit jar (either 3.8.1 or 3.8.2)</u></i></pre> + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE and test the jmx-scandir project from the + <code>Run</code> menu. + </p> + + </ul> + + <h2><a name="h2-Running">Running the <i>scandir</i> Example</a></h2> + <ul> + <p>In the example root directory (where the <code>build.xml</code> + file is located) run the following commands: + <pre>ant jar +ant run-single -Drun.class=com.sun.jmx.examples.scandir.ScanDirAgent -Djavac.includes=src</pre> + or simply <pre>ant run</pre> + </p> + + <p>This will run the example using the configuration + file provided in the src/etc directory. + </p> + <p>Alternatively you can open the jmx-scandir project with the + NetBeans IDE. You can run the example by + selecting the <code>ScanDirAgent</code> file + and run it with <code>Run File</code> in the + <code>Run</code> menu or simply + set the <i>jmx-scandir</i> project as main project and + select <code>Run Main Project</code> from the + main menu. Both targets will use the configuration + file provided in the src/etc directory. + </p> + <p>When the application is started, you can connect to + it with <a href="#JConsole">jconsole</a>. + </p> + <blockquote> + <u>Note:</u> You can also run the <i>scandir</i> + application directly from the <code>java</code> + command line. Make sure to build the project jar + first. + <br>On Unix systems: + <pre>ant jar +java -Djava.util.logging.config.file=logging.properties \ + -Dscandir.config.file=src/etc/testconfig.xml \ + -jar dist/jmx-scandir.jar</pre> + <br>On Windows systems: + <p><code>ant jar<br> +java -Djava.util.logging.config.file=logging.properties + -Dscandir.config.file=src\etc\testconfig.xml + -jar dist\jmx-scandir.jar</code></p> + </blockquote> + </ul> + + <h2><a name="h2-Playing">Playing with JConsole</a></h2> + <ul> + <p>Run the example as explained in the previous section, so + that it uses the provided <code>src/etc/testconfig.xml</code> + configuration file. Then start + jconsole. In the connection window choose the process that runs + <code>com.sun.jmx.examples.scandir.ScanDirAgent</code> or + <code>jmx-scandir.jar</code>. + </p> + <p><center> + <table border="0" cellpadding="2" cellspacing="2"> + <tr><td> + <a href="docfiles/connect-local-ant-run.jpg" + title="jconsole connection window - connect to local process" + ><img height="440" + src="docfiles/connect-local-ant-run.jpg" + alt="jconsole connection window - connect to local process" + /></a> + </td> + <td> + <a href="docfiles/connect-local-java-jar.jpg" + title="jconsole connection window - connect to local process" + ><img height="440" + src="docfiles/connect-local-java-jar.jpg" + alt="jconsole connection window - connect to local process" + /></a> + </td></tr></table> + </center> + </p> + <p>Open the MBeans tab, and look for the + <code>ScanDirConfigMXBean</code>. + Click on its <code>Attributes</code> node and double click on its + <code>Configuration</code> attribute, to look at + the loaded configuration - values in bold can + be expanded by a double-click. + </p> + <p><center><a href="docfiles/scandir-config.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-config.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>Now go to the <code>ScanManagerMXBean</code>, click on + its <code>Notifications</code> node, and subscribe + for notifications. Then click on the + <code>Operations</code> node and invoke the + <code>start()</code> operation: + </p> + <p><center><a href="docfiles/scandir-start.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-start.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>You can see that the notifications counter was + incremented by three: you have just scheduled, + run, and completed a batch of directory scans. + </p> + <p>Now go to the <code>ResultLogManagerMXBean</code>, + click on its <code>Attributes</code> node, and + expand its <code>MemoryLog</code> attribute: + </p> + <p><center><a href="docfiles/scandir-result.jpg" + title="jconsole MBean tab: ScanDirConfigMXBean" + ><img + src="docfiles/scandir-result.jpg" + alt="jconsole MBean tab: ScanDirConfigMXBean" + /></a></center> + </p> + <p>You can see that the directory scan results have + been logged.</p> + <p>To make the application terminate go back to the + <code>ScanManagerMXBean</code> and invoke + <code>close()</code>. The <code>ScanDirAgent</code> + will receive the notification, step out of + the application main thread, and the application + will terminate. + </p> + <p>This is of course a very limited scenario. Feel free + to improvise with all the features of the example, creating + a new configuration - + <code>ScanManagerMXBean.createOtherConfigurationMBean</code> - + adding multiple directory scanners to that configuration - + <code>ScanDirConfigMXBean.addDirectoryScanner</code> - + then switching the <code>ScanManagerMXBean</code> current + configuration by changing the value of the <i>ConfigurationMBean</i> + attribute - <code>ScanManagerMXBean.setConfigurationMBean</code> + - then applying the new configuration - + <code>ScanManagerMXBean.applyConfiguration(true)</code> - + then scheduling repeated directory scans every 10 seconds - + <code>ScanManagerMXBean.schedule(0,10000)</code> - + subscribing for notifications, etc... + </p> + </ul> + + <a name="secure"></a> + <h2><a name="h2-Turning">Turning the example into a Secure JMX Application</a></h2> + <ul> + <p>In this section, we will see how to configure and + start the <i>scandir</i> example so that the JVM agent + is bootstrapped with a secure JMXConnectorServer. Indeed, until + now we have only used the insecure local connection, + which can only be used as long as both the client and + the server run on the same machine. This section will + explain how to start the <code>ScanDirAgent</code> so + that a real secure RMIConnectorServer is started at bootstrap. + </p> + <p>To achieve this we will: <a href="#management.properties" + >provide our own management.properties</a>, <a + href="#password-access">create our own password and access files</a>, + <a href="#keystore-truststore">provide a keystore and truststore</a>, + <a href="#start-secure-agent">start the ScanDirAgent with the + appropriate system properties</a>. + </ul> + <h3>Configuring the JVM Agent for Secure Remote Connection</h3> + <ul> + <p>The easiest way to <a name="management.properties">configure the + JVM Agent</a> for Secure Remote + Connection is to use your own <a + href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#properties" + title="This page describes the properties you can put in your management.properties file" + >management.properties</a> file. + In this example, we have copied the default + <code>$JRE/lib/management/management.properties</code> + file to the example's <code>src/etc</code> directory and + modified it in <a href="src/etc/management.properties" + title="our modified management.properties" + >this way</a>: + <ul> + <li>We have set the RMI port to <u>4545</u> - this is just a + random port number we have picked up. Feel free to use your + own value suited to your environment. + <pre># For setting the JMX RMI agent port use the following line +com.sun.management.jmxremote.port=<b>4545</b></pre> + </li> + <li>We have <u>switched on</u> SSL <u>mutual authentication</u> + <pre># For RMI monitoring with SSL client authentication use the following line +com.sun.management.jmxremote.ssl.<b>need.client.auth</b>=<b>true</b></pre> + </li> + <li>We have also <u>secured the RMI Registry</u> with SSL + <pre># For using an SSL/TLS <b>protected</b> RMI Registry use the following line +com.sun.management.jmxremote.<b>registry.ssl</b>=<b>true</b></pre> + </li> + <li>We have provided <a + href="src/etc/password.properties">our own password file</a> + <pre># For a non-default password file location use the following line +com.sun.management.jmxremote.password.file=<i>src/etc/password.properties</i></pre> + </li> + <li>We have provided <a + href="src/etc/access.properties">our own access file</a> + <pre># For a non-default password file location use the following line +com.sun.management.jmxremote.access.file=<i>src/etc/access.properties</i></pre> + </li> + </ul> + <p>You will note that we haven't provided any value + for the other security properties, like + <code>com.sun.management.jmxremote.authenticate=true</code>, + because these properties already default to a value + which enables security by default. + Note however that protecting the RMI Registry with SSL + improves the application security, but only as long as + mutual authentication is also switched on. Otherwise, just + anybody would be able to connect to the registry and + get the RMIServer stub. + </p> + <p>We do recommend that you <u>use the most secure configuration + when you deploy a JMX agent</u> - which means <u>switching on + SSL protection for the RMI registry</u> <b>and</b> <u>requiring + mutual authentication</u>, as we show in this example. + </p> + <p>We will use the <code>com.sun.management.config.file</code> + system property to pass our <a + href="src/etc/management.properties">management.properties</a> + file to the <code>ScanDirAgent</code>. + </p> + </ul> + + <h3>Creating a password and access file</h3> + <ul> + <p>As explained above, we have created our own + <a href="src/etc/password.properties">password file</a> + and <a href="src/etc/access.properties">access file</a> + for <a name="password-access">access control and authorization</a>. + </p> + <p>In the password file, we have defined two logins: + <i>guest</i> and <i>admin</i>. The password for + <i>guest</i> is <i>guestpasswd</i> and the password + for <i>admin</i> is <i>adminpasswd</i>. + </p> + <p>In the access file, we have mapped these two logins + to access rights: the <i>admin</i> login has <i>read-write</i> + access, while the <i>guest</i> login only has <i>read-only</i>. + </p> + <p>Before starting the <code>ScanDirAgent</code>, you will + need to restrict access permission to the password file, + in such a way that nobody but you can read it. Otherwise, the + JVM Agent will refuse to start the JMXConnectorServer, as it will + fear that security can be compromised if other parties can + have read access to the password file. How to restrict + read access to the password file is explained in detail + <a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#PasswordAccessFiles" + title="Using Password and Access Files" + >here</a>. + </p> + <p>As we have seen above, the location + of our access and password files is configured in our own <a + href="src/etc/management.properties">management.properties</a> + file. + </p> + </ul> + <h3>Keystore and Truststore</h3> + <ul> + <p>Using SSL with mutual authentication means that both + client and server will need a <a name="keystore-truststore" + >keystore and a truststore</a> + to store their own certificates, and the certificates of + the parties they trust. Usually, client and server will + have their own keystore and truststore. + </p> + <p>For the sake of simplicity - and to get you started + without the tedious necessity of creating your own keystore + and truststore, we are providing a dummy keystore and + truststore, containing a certificate self-signed by duke. + The password for our keystore is <i>password</i>, and the + password for our truststore is <i>trustword</i>. + We suggest that you first get the example running with the + keystore and truststore we are providing before attempting + to use your own keystore and truststore. + </p> + <p>A secure application will obviously need to use its own + keystore and truststore, <b><u>and should not rely on the keystore + and truststore we are providing here!</u></b> + </p> + <p>How to create your own keystore and truststore, is explained + in <a +href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled" +title="Monitoring and Management Using JMX" + >here</a>. + As shown <a href="#start-secure-agent">later</a>, + we will need to use <a + href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#SSL_enabled" + >system properties</a> to pass our truststore + and keystore to the <code>ScanDirAgent</code>. + </p> + </ul> + <h3>Starting a Secure <i>scandir</i> agent</h3> + <ul> + <p>To start a <a name="start-secure-agent" + >secure <i>scandir</i> agent</a>, go to the + <i>scandir</i> example root directory and type the + following command:</p> + <p>On Unix Systems: +<pre>ant jar +java \ + -Djava.util.logging.config.file=logging.properties \ + -Djavax.net.ssl.keyStore=keystore \ + -Djavax.net.ssl.keyStorePassword=password \ + -Djavax.net.ssl.trustStore=truststore \ + -Djavax.net.ssl.trustStorePassword=trustword \ + -Dcom.sun.management.config.file=src/etc/management.properties \ + -Dscandir.config.file=src/etc/testconfig.xml \ + -jar dist/jmx-scandir.jar</pre> + </p> + <p>On Windows Systems: +<p><code>ant jar<br> +java + -Djava.util.logging.config.file=logging.properties + -Djavax.net.ssl.keyStore=keystore + -Djavax.net.ssl.keyStorePassword=password + -Djavax.net.ssl.trustStore=truststore + -Djavax.net.ssl.trustStorePassword=trustword + -Dcom.sun.management.config.file=src\etc\management.properties + -Dscandir.config.file=src\etc\testconfig.xml + -jar dist\jmx-scandir.jar</code></p> + </p> + <p>If you start jconsole now, you will see that you + are still able to connect to the agent using the + local connection. However, if you try to connect + through the remote connector, using + <a href="docfiles/remote-connection.jpg">localhost:4545</a>, + the connection will <a href="docfiles/remote-connection-failed.jpg" + >fail</a>, even if you provide a correct login/password + pair. Indeed, since the JMXConnectorServer is now protected with SSL, + jconsole must also be configured with the appropriate SSL parameters + so that it can authenticate the server and get authenticated by the + server too as the SSL configuration of the server requires mutual + authentication. + </p> + <p>The next section will discuss how to connect to the + secure agent. + </p> + </ul> + + <h2><a name="h2-Connecting">Connecting to the Secure JMX Application</a></h2> + <ul> + <p>We will now see how to connect to the secure agent, + using jconsole, and using a programmatic client. + </p> + </ul> + + <h3>Using jconsole to connect to the secure agent</h3> + <ul> + <p>The only special thing you need to do in order to + be able to connect to your secure agent with + jconsole, is to give it a keystore (containing + its client certificate) and a truststore (containing + the certificates of the servers it can trust). + In our example, we use the same keystore/truststore + pair on the client and server side - but this is + not what a real application would do. + Indeed a real application would have different + certificates for the client and the server, and + thus use different keystores (and probably truststores). + More information on SSL authentication can be obtained from the <a + href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks" + title="How SSL Works" + >Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>. + </p> + <p>To start jconsole with our provided keystore and + truststore, go to the scandir example root directory and + type in the following command: + <p><code>jconsole + -J-Djava.util.logging.config.file=logging.properties + -J-Djavax.net.ssl.keyStore=keystore + -J-Djavax.net.ssl.keyStorePassword=password + -J-Djavax.net.ssl.trustStore=truststore + -J-Djavax.net.ssl.trustStorePassword=trustword</code></p> + </p> + <p>The <code>-J-Djava.util.logging.config.file=logging.properties</code> + flag is not mandatory, but passing a <code>logging.properties</code> + may help you debug connection problems if anything goes wrong. + </p> + <p>In jconsole connection window, choose to connect to a + remote process, using the address <i>localhost:4545</i> + and the guest login: + </p> + <p><center><a href="docfiles/remote-connection.jpg" + ><img src="docfiles/remote-connection.jpg" + alt="jconsole connection window"/></a></center> + </p> + <p>You will see that the agent will let view all the + MBeans and their attributes, but will reject any + attribute modification or remote method invocation. + </p> + <hr> + <p><u>Note:</u> if jconsole fails to connect and show + you <a href="docfiles/remote-connection-failed.jpg">this screen</a> + you have probably misspelled some of the properties on jconsole + command line, or you didn't start jconsole from the + scandir example root directory where our <code>truststore</code> + and <code>keystore</code> files are located. This article - <a + href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole" + title="Troubleshooting connection problems in JConsole" + >Troubleshooting connection problems in JConsole</a> - may help + you figure out what is going wrong. + </p> + <hr> + </ul> + + <h3>Writing a programmatic client to connect to the secure agent</h3> + <ul> + <p> + In this section we will show the steps involved in writing + a programmatic client that will connect to our secure agent. + </p> + <p>The <a +href="dist/javadoc/com/sun/jmx/examples/scandir/ScanDirClient.html" +title="The ScanDirClient class is a very short example of secure programmatic client" + >ScanDirClient</a> is an example class that shows how a + programmatic client can connect to a secured <i>scandir</i> application. + This class contains a <code>main</code> method which creates and + configures a <code>JMXConnector</code> client to connect with + the secured <i>scandir</i> agent. + </p> + <p>The secure client differs only from a non secure client in + so far as it needs to use SSL RMI Factories and credentials to + connect to the secure agent. The steps required mainly involve: + <ul> + <li>Creating an empty environment map: + <pre> + // Create an environment map to hold connection properties + // like credentials etc... We will later pass this map + // to the JMX Connector. + // + System.out.println("\nInitialize the environment map"); + final Map<String,Object> env = new HashMap<String,Object>(); + </pre> + </li> + <li>Putting the client's credentials in that map: + <i>(here the client will log in as <b>guest</b>)</i> + <pre> + // Provide the credentials required by the server + // to successfully perform user authentication + // + final String[] credentials = new String[] { "guest" , "guestpasswd" }; + env.put("jmx.remote.credentials", credentials); + </pre> + </li> + <li>Providing an <code>SslRMIClientSocketFactory</code> to interact + with the secure RMI Registry: + <pre> + // Provide the SSL/TLS-based RMI Client Socket Factory required + // by the JNDI/RMI Registry Service Provider to communicate with + // the SSL/TLS-protected RMI Registry + // + env.put("com.sun.jndi.rmi.factory.socket", + new SslRMIClientSocketFactory()); + </pre> + </li> + <li>Creating a JMXConnector and connecting with the + secure server: + <pre> + // Create the RMI connector client and + // connect it to the secure RMI connector server. + // args[0] is the server's host - localhost + // args[1] is the secure server port - 4545 + // + System.out.println("\nCreate the RMI connector client and " + + "connect it to the RMI connector server"); + final JMXServiceURL url = new JMXServiceURL( + "service:jmx:rmi:///jndi/rmi://"+args[0]+":"+args[1]+ + "/jmxrmi"); + final JMXConnector jmxc = JMXConnectorFactory.connect(url, env); + </pre> + </li> + </ul> + <p>For this to work, we also need to start the <code>ScanDirClient</code> + with the appropriate system properties that will point to our + <code>keystore</code> and <code>truststore</code>. To start the secure + client, go to the <i>scandir</i> example root directory and type + the following command: + <p><code>ant jar<br> +java + -Djava.util.logging.config.file=logging.properties + -Djavax.net.ssl.keyStore=keystore + -Djavax.net.ssl.keyStorePassword=password + -Djavax.net.ssl.trustStore=truststore + -Djavax.net.ssl.trustStorePassword=trustword + -classpath dist/jmx-scandir.jar + com.sun.jmx.examples.scandir.ScanDirClient localhost 4545 + </code></p> + </p> + <p>You should be seeing this trace: +<center><table width="90%" border="0" bgcolor="#eeeeee"> +<tr><td> +<pre> +Initialize the environment map + +Create the RMI connector client and connect it to the RMI connector server +Connecting to: service:jmx:rmi:///jndi/rmi://localhost:4545/jmxrmi + +Get the MBeanServerConnection + +Get ScanDirConfigMXBean from ScanManagerMXBean + +Get 'Configuration' attribute on ScanDirConfigMXBean + +Configuration: + +<ScanManager xmlns="jmx:com.sun.jmx.examples.scandir.config" name="testconfig"> + <InitialResultLogConfig> + <LogFileMaxRecords>2048</LogFileMaxRecords> + <LogFileName>build/scandir.log</LogFileName> + <MemoryMaxRecords>128</MemoryMaxRecords> + </InitialResultLogConfig> + <DirectoryScannerList> + <DirectoryScanner name="scan-build"> + <Actions>NOTIFY LOGRESULT</Actions> + <ExcludeFiles/> + <IncludeFiles> + <FileFilter> + <FilePattern>.*\.class</FilePattern> + <SizeExceedsMaxBytes>4096</SizeExceedsMaxBytes> + </FileFilter> + </IncludeFiles> + <RootDirectory>build</RootDirectory> + </DirectoryScanner> + </DirectoryScannerList> +</ScanManager> + +Invoke 'close' on ScanManagerMXBean + +Got expected security exception: java.lang.SecurityException: Access denied! +Invalid access level for requested MBeanServer operation. + +Close the connection to the server + +Bye! Bye! +</pre> +</td></tr></table></center> + <p>If the <code>ScanDirClient</code> fails to connect with + the secure agent, then this article - <a + href="http://blogs.sun.com/roller/page/jmxetc?entry=troubleshooting_connection_problems_in_jconsole" + title="Troubleshooting connection problems in JConsole" + >Troubleshooting connection problems in JConsole</a> - may help + you figure out what is going wrong. Indeed the connection steps + performed by the <code>ScanDirClient</code> are very similar to + those performed by <code>jconsole</code>, and the problems you + could encounter are identical. Just remember that + <code>jconsole</code> needs the extra <code>-J</code> flag to pass + system properties to the VM, which is not needed with regular + <code>java</code> launcher invocations. + </p> + </ul> + + <h2><a name="h2-Conclusion">Conclusion</a></h2> + <ul> + <p> + In this document, we have presented an advanced + JMX example, and shown how to run a secure + JMX agent in a production environment. + We have also shown how to connect to such a + secure agent with both jconsole and a programmatic + client. We have also discuss various JMX + design-patterns and best practices. + Readers who would wish to learn more about JMX, and + Monitoring and Management of the JVM, are invited + to follow the links given in reference below. + </p> + </ul> + <h2><a name="h2-References">References</a></h2> + <ol> + <li><a href="http://java.sun.com/products/JavaManagement/best-practices.html" + >JMX Best Practices</a>: This document describes best practices that + have been identified for modeling using the JMX API. </li> + <li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html" + >Monitoring and Management Using JMX</a>: How to enable, configure, and + connect to the JVM JMX agent.</li> + <li><a name="JConsole"><a +href="http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html" +>Using JConsole</a>: JConsole is a JMX-Compliant monitoring tool which allows + you to interact graphically with your own MBeans. + </li> + <li><a href="http://java.sun.com/javase/6/docs/technotes/guides/management/" + >Monitoring and Management for the Java Platform</a>: The Java Platform + Standard Edition (Java SE) 6 provides comprehensive monitoring and + management support for the Java platform. </li> + <li><a href="http://java.sun.com/products/JavaManagement/community/jmx_blogs.html" + >List of JMX-related Blogs</a>: This page provides links to the + different web logs written by members of the Sun team working on the + JMX API.</li> + <li><a + href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks" + title="The JSSE Reference Guide" + >Java<sup>TM</sup> Secure Socket Extension (JSSE) Reference Guide</a>: + comprehensive documentation about the Java<sup>TM</sup> Secure Socket + Extension (JSSE) + </li> + <li><a href="http://java.sun.com/javase/6/docs/" + >Java SE 6 Documentation Index</a>: This document covers the + Java<sup>TM</sup> Platform, Standard Edition 6 JDK.</li> + </ol> + <p> + <hr> + <p> + </body> +</html> diff --git a/darwin-x86/sample/jmx/jmx-scandir/keystore b/darwin-x86/sample/jmx/jmx-scandir/keystore Binary files differnew file mode 100644 index 0000000..05f5356 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/keystore diff --git a/darwin-x86/sample/jmx/jmx-scandir/logging.properties b/darwin-x86/sample/jmx/jmx-scandir/logging.properties new file mode 100644 index 0000000..1714bee --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/logging.properties @@ -0,0 +1,17 @@ +handlers= java.util.logging.ConsoleHandler + +.level=INFO + + +java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +java.util.logging.ConsoleHandler.level = FINEST +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + +javax.management.level=INFO +com.sun.jmx.level=INFO +com.sun.jmx.examples.level=FINE + diff --git a/darwin-x86/sample/jmx/jmx-scandir/manifest.mf b/darwin-x86/sample/jmx/jmx-scandir/manifest.mf new file mode 100644 index 0000000..328e8e5 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/darwin-x86/sample/jmx/jmx-scandir/nbproject/file-targets.xml b/darwin-x86/sample/jmx/jmx-scandir/nbproject/file-targets.xml new file mode 100644 index 0000000..42da880 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/nbproject/file-targets.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project basedir=".." name="jmx-scandir/file"> + + <import file="../build.xml"/> + + <target name="compile-selected" depends="-init"> + <fail unless="includes">Must set property 'includes'</fail> + <mkdir dir="${classes.dir}"/> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="${debug}" deprecation="${deprecation}" includes="${includes}"> + <classpath path="${cp}"/> + </javac> + </target> + +</project> diff --git a/darwin-x86/sample/jmx/jmx-scandir/nbproject/jdk.xml b/darwin-x86/sample/jmx/jmx-scandir/nbproject/jdk.xml new file mode 100644 index 0000000..2b85b77 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/nbproject/jdk.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project name="jdk" basedir="."> + + <target name="-jdk-preinit"> + <condition property=".exe" value=".exe"> + <os family="windows"/> + </condition> + <property name=".exe" value=""/> + <property name="nbjdk.javac" value="${nbjdk.home}/bin/javac${.exe}"/> + <property name="nbjdk.java" value="${nbjdk.home}/bin/java${.exe}"/> + <property name="nbjdk.javadoc" value="${nbjdk.home}/bin/javadoc${.exe}"/> + <property name="nbjdk.appletviewer" value="${nbjdk.home}/bin/appletviewer${.exe}"/> + <property name="nbjdk.bootclasspath" value="${nbjdk.home}/jre/lib/rt.jar"/> + </target> + + <target name="-jdk-presetdef-basic" depends="-jdk-preinit" unless="nbjdk.presetdef.basic.done"> + <macrodef name="javac-presetdef"> + <attribute name="javacval"/> + <sequential> + <presetdef name="javac"> + <javac fork="yes" executable="@{javacval}"/> + </presetdef> + </sequential> + </macrodef> + <javac-presetdef javacval="${nbjdk.javac}"/> + <macrodef name="java-presetdef"> + <attribute name="javaval"/> + <sequential> + <presetdef name="java"> + <java fork="yes" jvm="@{javaval}"/> + </presetdef> + </sequential> + </macrodef> + <java-presetdef javaval="${nbjdk.java}"/> + <macrodef name="javadoc-presetdef"> + <attribute name="javadocval"/> + <sequential> + <presetdef name="javadoc"> + <javadoc executable="@{javadocval}"/> + </presetdef> + </sequential> + </macrodef> + <javadoc-presetdef javadocval="${nbjdk.javadoc}"/> + <property name="nbjdk.presetdef.basic.done" value="true"/> + </target> + + <target name="-jdk-presetdef-nbjpdastart" depends="-jdk-preinit" unless="nbjdk.presetdef.nbjpdastart.done"> + <macrodef name="nbjpdastart-presetdef"> + <attribute name="bootcpval"/> + <sequential> + <presetdef name="nbjpdastart"> + <nbjpdastart> + <bootclasspath> + <path path="@{bootcpval}"/> + </bootclasspath> + </nbjpdastart> + </presetdef> + </sequential> + </macrodef> + <nbjpdastart-presetdef bootcpval="${nbjdk.bootclasspath}"/> + <property name="nbjdk.presetdef.nbjpdastart.done" value="true"/> + </target> + + <target name="-jdk-init" depends="-jdk-preinit,-jdk-presetdef-basic"/> + +</project> diff --git a/darwin-x86/sample/jmx/jmx-scandir/nbproject/netbeans-targets.xml b/darwin-x86/sample/jmx/jmx-scandir/nbproject/netbeans-targets.xml new file mode 100644 index 0000000..facdb4e --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/nbproject/netbeans-targets.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project basedir=".." name="jmx-scandir/NB"> + + <import file="../build.xml"/> + + <target name="debug" depends="compile,-jdk-presetdef-nbjpdastart"> + <nbjpdastart addressproperty="jpda.address" name="jmx-scandir" transport="dt_socket"> + <classpath path="${run.cp}"/> + </nbjpdastart> + <java classname="${main.client.class}" failonerror="true" fork="true"> + <classpath path="${run.cp}"/> + <jvmarg value="-Xdebug"/> + <jvmarg value="-Xnoagent"/> + <jvmarg value="-Djava.compiler=none"/> + <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> + <arg line="${client.args}" /> + </java> + </target> + + <target name="debug-fix" depends="-init"> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="true" deprecation="${deprecation}"> + <classpath path="${cp}"/> + <include name="${class}.java"/> + </javac> + <nbjpdareload> + <fileset dir="${classes.dir}"> + <include name="${class}.class"/> + </fileset> + </nbjpdareload> + </target> + + <target name="show-info" depends="-init"> + <nbbrowse file="${main.dir}/index.html"/> + </target> + + <target name="show-javadoc" depends="javadoc"> + <nbbrowse file="${javadoc.dir}/index.html"/> + </target> + + <target name="profile" depends="compile"> + <nbprofiledirect> + <classpath path="${run.cp}"/> + </nbprofiledirect> + <property environment="env"/> + <java classname="${main.client.class}" fork="true" failonerror="true" dir="${profiler.session.working.dir}" jvm="${profiler.info.jvm}"> + <classpath path="${run.cp}"/> + <jvmarg value="${profiler.info.jvmargs.agent}"/> + <jvmarg line="${profiler.info.jvmargs}"/> + <arg line="localhost 4545" /> + <env key="LD_LIBRARY_PATH" path="${profiler.info.agentpath}:${env.LD_LIBRARY_PATH}"/> + <env key="Path" path="${profiler.info.agentpath}:${env.Path}"/> + </java> + </target> + +</project> diff --git a/darwin-x86/sample/jmx/jmx-scandir/nbproject/project.xml b/darwin-x86/sample/jmx/jmx-scandir/nbproject/project.xml new file mode 100644 index 0000000..a988de6 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/nbproject/project.xml @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project xmlns="http://www.netbeans.org/ns/project/1"> + <type>org.netbeans.modules.ant.freeform</type> + <configuration> + <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1"> + <name>jmx-scandir</name> + <properties> + <property-file>user.build.properties</property-file> + <property-file>build.properties</property-file> + <property name="nbjdk.bootclasspath">${nbjdk.home}/jre/lib/rt.jar</property> + </properties> + <folders> + <source-folder> + <label>JDK Demo</label> + <location>${main.dir}</location> + </source-folder> + <source-folder> + <label>Sources</label> + <type>java</type> + <location>${src.dir}</location> + </source-folder> + <source-folder> + <label>test</label> + <type>java</type> + <location>test</location> + </source-folder> + </folders> + <ide-actions> + <action name="build"> + <target>jar</target> + </action> + <action name="clean"> + <target>clean</target> + </action> + <action name="rebuild"> + <target>clean</target> + <target>jar</target> + </action> + <action name="run"> + <target>run</target> + </action> + <action name="ReadMe"> + <script>nbproject/netbeans-targets.xml</script> + <target>show-info</target> + </action> + <action name="javadoc"> + <script>nbproject/netbeans-targets.xml</script> + <target>show-javadoc</target> + </action> + <action name="debug"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug</target> + </action> + <action name="compile.single"> + <script>nbproject/file-targets.xml</script> + <target>compile-selected</target> + <context> + <property>includes</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>relative-path</format> + <arity> + <separated-files>,</separated-files> + </arity> + </context> + </action> + <action name="run.single"> + <target>run</target> + <context> + <property>main.class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>java-name</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + <action name="debug.single"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug</target> + <context> + <property>main.class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>java-name</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + <action name="debug.fix"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug-fix</target> + <context> + <property>class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>relative-path-noext</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + <action name="test"> + <target>test</target> + </action> + </ide-actions> + <export> + <type>folder</type> + <location>${classes.dir}</location> + <build-target>jar</build-target> + </export> + <export> + <type>jar</type> + <location>${jar}</location> + <build-target>jar</build-target> + </export> + <export> + <type>folder</type> + <location>${build.test.classes.dir}</location> + <build-target>jar</build-target> + </export> + <view> + <items> + <source-folder style="packages"> + <label>Sources</label> + <location>${src.dir}</location> + </source-folder> + <source-folder style="packages"> + <label>test</label> + <location>test</location> + </source-folder> + <source-file> + <location>${main.dir}/index.html</location> + </source-file> + </items> + <context-menu> + <ide-action name="ReadMe"/> + <ide-action name="build"/> + <ide-action name="clean"/> + <ide-action name="rebuild"/> + <ide-action name="javadoc"/> + <ide-action name="debug"/> + <!-- ide-action name="test"/ --> + <separator/> + <action> + <label>Run Agent</label> + <target>run-agent</target> + </action> + <action> + <label>Run Client</label> + <target>run-client</target> + </action> + </context-menu> + </view> + <subprojects/> + </general-data> + <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2"> + <compilation-unit> + <package-root>${src.dir}</package-root> + <classpath mode="compile">${cp}</classpath> + <classpath mode="execute">${run.cp}</classpath> + <classpath mode="boot">${nbjdk.bootclasspath}</classpath> + <built-to>${classes.dir}</built-to> + <built-to>${jar}</built-to> + <javadoc-built-to>${javadoc.dir}</javadoc-built-to> + <source-level>1.5</source-level> + </compilation-unit> + <compilation-unit> + <package-root>test</package-root> + <unit-tests/> + <built-to>${build.test.classes.dir}</built-to> + <source-level>1.5</source-level> + </compilation-unit> + </java-data> + </configuration> +</project> diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScanner.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScanner.java new file mode 100644 index 0000000..0ff58a2 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScanner.java @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import static com.sun.jmx.examples.scandir.ScanManager.getNextSeqNumber; +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; +import static com.sun.jmx.examples.scandir.config.DirectoryScannerConfig.Action.*; +import com.sun.jmx.examples.scandir.config.XmlConfigUtils; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig.Action; +import com.sun.jmx.examples.scandir.config.ResultRecord; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.AttributeChangeNotification; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * A <code>DirectoryScanner</code> is an MBean that + * scans a file system starting at a given root directory, + * and then looks for files that match a given criteria. + * <p> + * When such a file is found, the <code>DirectoryScanner</code> takes + * the action for which it was configured: emit a notification, + * <i>and or</i> log a {@link + * com.sun.jmx.examples.scandir.config.ResultRecord} for this file, + * <i>and or</i> delete that file. + * </p> + * <p> + * The code that would actually delete the file is commented out - so that + * nothing valuable is lost if this example is run by mistake on the wrong + * set of directories.<br> + * Logged results are logged by sending them to the {@link ResultLogManager}. + * </p> + * <p> + * <code>DirectoryScannerMXBeans</code> are created, initialized, and + * registered by the {@link ScanManagerMXBean}. + * The {@link ScanManagerMXBean} will also schedule and run them in + * background by calling their {@link #scan} method. + * </p> + * <p>Client code is not expected to create or register directly any such + * MBean. Instead, clients are expected to modify the configuration, using + * the {@link ScanDirConfigMXBean}, and then apply it, using the {@link + * ScanManagerMXBean}. Instances of <code>DirectoryScannerMXBeans</code> + * will then be created and registered (or unregistered and garbage collected) + * as a side effect of applying that configuration. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class DirectoryScanner implements + DirectoryScannerMXBean, NotificationEmitter { + + /** + * The type for <i>com.sun.jmx.examples.scandir.filematch</i> notifications. + * Notifications of this type will be emitted whenever a file that + * matches this {@code DirectoryScanner} criteria is found, but only if + * this {@code DirectoryScanner} was configured to {@link + * Action#NOTIFY notify} for matching files. + **/ + public static final String FILE_MATCHES_NOTIFICATION = + "com.sun.jmx.examples.scandir.filematch"; + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(DirectoryScanner.class.getName()); + + // Attribute : State + // + private volatile ScanState state = STOPPED; + + // The DirectoryScanner delegates the implementation of + // the NotificationEmitter interface to a wrapped instance + // of NotificationBroadcasterSupport. + // + private final NotificationBroadcasterSupport broadcaster; + + // The root directory at which this DirectoryScanner will start + // scanning. Constructed from config.getRootDirectory(). + // + private final File rootFile; + + // This DirectoryScanner config - this is a constant which is + // provided at construction time by the {@link ScanManager}. + // + private final DirectoryScannerConfig config; + + // The set of actions for which this DirectoryScanner is configured. + // Constructed from config.getActions() + // + final Set<Action> actions; + + // The ResultLogManager that this DirectoryScanner will use to log + // info. This is a hard reference to another MBean, provided + // at construction time by the ScanManager. + // The ScanManager makes sure that the life cycle of these two MBeans + // is consistent. + // + final ResultLogManager logManager; + + /** + * Constructs a new {@code DirectoryScanner}. + * <p>This constructor is + * package protected, and this MBean cannot be created by a remote + * client, because it needs a reference to the {@link ResultLogManager}, + * which cannot be provided from remote. + * </p> + * <p>This is a conscious design choice: {@code DirectoryScanner} MBeans + * are expected to be completely managed (created, registered, unregistered) + * by the {@link ScanManager} which does provide this reference. + * </p> + * + * @param config This {@code DirectoryScanner} configuration. + * @param logManager The info log manager with which to log the info + * records. + * @throws IllegalArgumentException if one of the parameter is null, or if + * the provided {@code config} doesn't have its {@code name} set, + * or if the {@link DirectoryScannerConfig#getRootDirectory + * root directory} provided in the {@code config} is not acceptable + * (not provided or not found or not readable, etc...). + **/ + public DirectoryScanner(DirectoryScannerConfig config, + ResultLogManager logManager) + throws IllegalArgumentException { + if (logManager == null) + throw new IllegalArgumentException("log=null"); + if (config == null) + throw new IllegalArgumentException("config=null"); + if (config.getName() == null) + throw new IllegalArgumentException("config.name=null"); + + broadcaster = new NotificationBroadcasterSupport(); + + // Clone the config: ensure data encapsulation. + // + this.config = XmlConfigUtils.xmlClone(config); + + // Checks that the provided root directory is valid. + // Throws IllegalArgumentException if it isn't. + // + rootFile = validateRoot(config.getRootDirectory()); + + // Initialize the Set<Action> for which this DirectoryScanner + // is configured. + // + if (config.getActions() == null) + actions = Collections.emptySet(); + else + actions = EnumSet.copyOf(Arrays.asList(config.getActions())); + this.logManager = logManager; + } + + // see DirectoryScannerMXBean + public void stop() { + // switch state to stop and send AttributeValueChangeNotification + setStateAndNotify(STOPPED); + } + + // see DirectoryScannerMXBean + public String getRootDirectory() { + return rootFile.getAbsolutePath(); + } + + + // see DirectoryScannerMXBean + public ScanState getState() { + return state; + } + + // see DirectoryScannerMXBean + public DirectoryScannerConfig getConfiguration() { + return config; + } + + // see DirectoryScannerMXBean + public String getCurrentScanInfo() { + final ScanTask currentOrLastTask = currentTask; + if (currentOrLastTask == null) return "Never Run"; + return currentOrLastTask.getScanInfo(); + } + + // This variable points to the current (or latest) scan. + // + private volatile ScanTask currentTask = null; + + // see DirectoryScannerMXBean + public void scan() { + final ScanTask task; + + synchronized (this) { + final LinkedList<File> list; + switch (state) { + case RUNNING: + case SCHEDULED: + throw new IllegalStateException(state.toString()); + case STOPPED: + case COMPLETED: + // only accept to scan if state is STOPPED or COMPLETED. + list = new LinkedList<File>(); + list.add(rootFile); + break; + default: + throw new IllegalStateException(String.valueOf(state)); + } + + // Create a new ScanTask object for our root directory file. + // + currentTask = task = new ScanTask(list,this); + + // transient state... will be switched to RUNNING when + // task.execute() is called. This code could in fact be modified + // to use java.util.concurent.Future and, to push the task to + // an executor. We would then need to wait for the task to + // complete before returning. However, this wouldn't buy us + // anything - since this method should wait for the task to + // finish anyway: so why would we do it? + // As it stands, we simply call task.execute() in the current + // thread - brave and fearless readers may want to attempt the + // modification ;-) + // + setStateAndNotify(SCHEDULED); + } + task.execute(); + } + + // This method is invoked to carry out the configured actions on a + // matching file. + // Do not call this method from within synchronized() { } as this + // method may send notifications! + // + void actOn(File file) { + + // Which action were actually taken + // + final Set<Action> taken = new HashSet<Action>(); + boolean logresult = false; + + // Check out which actions are configured and carry them out. + // + for (Action action : actions) { + switch (action) { + case DELETE: + if (deleteFile(file)) { + // Delete succeeded: add DELETE to the set of + // actions carried out. + taken.add(DELETE); + } + break; + case NOTIFY: + if (notifyMatch(file)) { + // Notify succeeded: add NOTIFY to the set of + // actions carried out. + taken.add(NOTIFY); + } + break; + case LOGRESULT: + // LOGRESULT was configured - log actions carried out. + // => we must execute this action as the last action. + // simply set logresult=true for now. We will do + // the logging later + logresult = true; + break; + default: + LOG.fine("Failed to execute action: " +action + + " - action not supported"); + break; + } + } + + // Now is time for logging: + if (logresult) { + taken.add(LOGRESULT); + if (!logResult(file,taken.toArray(new Action[taken.size()]))) + taken.remove(LOGRESULT); // just for the last trace below... + } + + LOG.finest("File processed: "+taken+" - "+file.getAbsolutePath()); + } + + // Deletes a matching file. + private boolean deleteFile(File file) { + try { + // file.delete() is commented so that we don't do anything + // bad if the example is mistakenly run on the wrong set of + // directories. + // + /* file.delete(); */ + System.out.println("DELETE not implemented for safety reasons."); + return true; + } catch (Exception x) { + LOG.fine("Failed to delete: "+file.getAbsolutePath()); + } + return false; + } + + // Notifies of a matching file. + private boolean notifyMatch(File file) { + try { + final Notification n = + new Notification(FILE_MATCHES_NOTIFICATION,this, + getNextSeqNumber(), + file.getAbsolutePath()); + + // This method *is not* called from any synchronized block, so + // we can happily call broadcaster.sendNotification() here. + // Note that verifying whether a method is called from within + // a synchronized block demends a thoroughful code reading, + // examining each of the 'parent' methods in turn. + // + broadcaster.sendNotification(n); + return true; + } catch (Exception x) { + LOG.fine("Failed to notify: "+file.getAbsolutePath()); + } + return false; + } + + // Logs a result with the ResultLogManager + private boolean logResult(File file,Action[] actions) { + try { + logManager.log(new ResultRecord(config, actions,file)); + return true; + } catch (Exception x) { + LOG.fine("Failed to log: "+file.getAbsolutePath()); + } + return false; + } + + + // Contextual object used to store info about current + // (or last) scan. + // + private static class ScanTask { + + // List of Files that remain to scan. + // When files are discovered they are added to the list. + // When they are being handled, they are removed from the list. + // When the list is empty, the scanning is finished. + // + private final LinkedList<File> list; + private final DirectoryScanner scan; + + // Some statistics... + // + private volatile long scanned=0; + private volatile long matching=0; + + private volatile String info="Not started"; + + ScanTask(LinkedList<File> list, DirectoryScanner scan) { + this.list = list; this.scan = scan; + } + + public void execute() { + scan(list); + } + + private void scan(LinkedList<File> list) { + scan.scan(this,list); + } + + public String getScanInfo() { + return info+" - ["+scanned+" scanned, "+matching+" matching]"; + } + } + + // The actual scan logic. Switches state to RUNNING, + // and scan the list of given dirs. + // The list is a live object which is updated by this method. + // This would allow us to implement methods like "pause" and "resume", + // since all the info needed to resume would be in the list. + // + private void scan(ScanTask task, LinkedList<File> list) { + setStateAndNotify(RUNNING); + task.info = "In Progress"; + try { + + // The FileFilter will tell us which files match and which don't. + // + final FileFilter filter = config.buildFileFilter(); + + // We have two condition to end the loop: either the list is + // empty, meaning there's nothing more to scan, or the state of + // the DirectoryScanner was asynchronously switched to STOPPED by + // another thread, e.g. because someone called "stop" on the + // ScanManagerMXBean + // + while (!list.isEmpty() && state == RUNNING) { + + // Get and remove the first element in the list. + // + final File current = list.poll(); + + // Increment number of file scanned. + task.scanned++; + + // If 'current' is a file, it's already been matched by our + // file filter (see below): act on it. + // Note that for the first iteration of this loop, there will + // be one single file in the list: the root directory for this + // scanner. + // + if (current.isFile()) { + task.matching++; + actOn(current); + } + + // If 'current' is a directory, then + // find files and directories that match the file filter + // in this directory + // + if (current.isDirectory()) { + + // Gets matching files and directories + final File[] content = current.listFiles(filter); + if (content == null) continue; + + // Adds all matching file to the list. + list.addAll(0,Arrays.asList(content)); + } + } + + // The loop terminated. If the list is empty, then we have + // completed our task. If not, then somebody must have called + // stop() on this directory scanner. + // + if (list.isEmpty()) { + task.info = "Successfully Completed"; + setStateAndNotify(COMPLETED); + } + } catch (Exception x) { + // We got an exception: stop the scan + // + task.info = "Failed: "+x; + if (LOG.isLoggable(Level.FINEST)) + LOG.log(Level.FINEST,"scan task failed: "+x,x); + else if (LOG.isLoggable(Level.FINE)) + LOG.log(Level.FINE,"scan task failed: "+x); + setStateAndNotify(STOPPED); + } catch (Error e) { + // We got an Error: + // Should not happen unless we ran out of memory or + // whatever - don't even try to notify, but + // stop the scan anyway! + // + state=STOPPED; + task.info = "Error: "+e; + + // rethrow error. + // + throw e; + } + } + + /** + * MBeanNotification support - delegates to broadcaster. + */ + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws IllegalArgumentException { + broadcaster.addNotificationListener(listener, filter, handback); + } + + // Switch this object state to the desired value an send + // a notification. Don't call this method from within a + // synchronized block! + // + private final void setStateAndNotify(ScanState desired) { + final ScanState old = state; + if (old == desired) return; + state = desired; + final AttributeChangeNotification n = + new AttributeChangeNotification(this, + getNextSeqNumber(),System.currentTimeMillis(), + "state change","State",ScanState.class.getName(), + String.valueOf(old),String.valueOf(desired)); + broadcaster.sendNotification(n); + } + + + /** + * The {@link DirectoryScannerMXBean} may send two types of + * notifications: filematch, and state attribute changed. + **/ + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + new MBeanNotificationInfo( + new String[] {FILE_MATCHES_NOTIFICATION}, + Notification.class.getName(), + "Emitted when a file that matches the scan criteria is found" + ), + new MBeanNotificationInfo( + new String[] {AttributeChangeNotification.ATTRIBUTE_CHANGE}, + AttributeChangeNotification.class.getName(), + "Emitted when the State attribute changes" + ) + }; + } + + /** + * MBeanNotification support - delegates to broadcaster. + */ + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + /** + * MBeanNotification support - delegates to broadcaster. + */ + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener, filter, handback); + } + + // Validates the given root directory, returns a File object for + // that directory. + // Throws IllegalArgumentException if the given root is not + // acceptable. + // + private static File validateRoot(String root) { + if (root == null) + throw new IllegalArgumentException("no root specified"); + if (root.length() == 0) + throw new IllegalArgumentException("specified root \"\" is invalid"); + final File f = new File(root); + if (!f.canRead()) + throw new IllegalArgumentException("can't read "+root); + if (!f.isDirectory()) + throw new IllegalArgumentException("no such directory: "+root); + return f; + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.java new file mode 100644 index 0000000..2ca3548 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/DirectoryScannerMXBean.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import java.io.IOException; +import javax.management.InstanceNotFoundException; + +/** + * A <code>DirectoryScannerMXBean</code> is an MBean that + * scans a file system starting at a given root directory, + * and then looks for files that match a given criteria. + * <p> + * When such a file is found, the <code>DirectoryScannerMXBean</code> takes + * the actions for which it was configured: see {@link #scan scan()}. + * <p> + * <code>DirectoryScannerMXBeans</code> are created, initialized, and + * registered by the {@link ScanManagerMXBean}. + * The {@link ScanManagerMXBean} will also schedule and run them in + * background by calling their {@link #scan} method. + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public interface DirectoryScannerMXBean { + /** + * Get The {@link DirectoryScanner} state. + * @return the current state of the <code>DirectoryScanner</code>. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public ScanState getState() + throws IOException, InstanceNotFoundException; + + /** + * Stops the current scan if {@link ScanState#RUNNING running}. + * After this method completes the state of the application will + * be {@link ScanState#STOPPED STOPPED}. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void stop() + throws IOException, InstanceNotFoundException; + + /** + * Scans the file system starting at the specified {@link #getRootDirectory + * root directory}. + * <p>If a file that matches this <code>DirectoryScannerMXBean</code> + * {@link #getConfiguration} criteria is found, + * the <code>DirectoryScannerMXBean</code> takes the {@link + * DirectoryScannerConfig#getActions() actions} for which + * it was {@link #getConfiguration configured}: emit a notification, + * <i>and or</i> log a {@link + * com.sun.jmx.examples.scandir.config.ResultRecord} for this file, + * <i>and or</i> delete that file. + * </p> + * <p> + * The code that would actually delete the file is commented out - so that + * nothing valuable is lost if this example is run by mistake on the wrong + * set of directories. + * </p> + * <p>This method returns only when the directory scan is completed, or + * if it was {@link #stop stopped} by another thread. + * </p> + * @throws IllegalStateException if already {@link ScanState#RUNNING} + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void scan() + throws IOException, InstanceNotFoundException; + + /** + * Gets the root directory at which this <code>DirectoryScannerMXBean</code> + * will start scanning the file system. + * <p> + * This is a shortcut to {@link #getConfiguration + * getConfiguration()}.{@link + * DirectoryScannerConfig#getRootDirectory + * getRootDirectory()}. + * </p> + * @return This <code>DirectoryScannerMXBean</code> root directory. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public String getRootDirectory() + throws IOException, InstanceNotFoundException; + + /** + * The configuration data from which this {@link DirectoryScanner} was + * created. + * <p> + * You cannot change this configuration here. You can however + * {@link ScanDirConfigMXBean#setConfiguration modify} the + * {@link ScanDirConfigMXBean} configuration, and ask the + * {@link ScanManagerMXBean} to {@link ScanManagerMXBean#applyConfiguration + * apply} it. This will get all <code>DirectoryScannerMXBean</code> + * replaced by new MBeans created from the modified configuration. + * </p> + * + * @return This <code>DirectoryScannerMXBean</code> configuration data. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public DirectoryScannerConfig getConfiguration() + throws IOException, InstanceNotFoundException; + + /** + * A short string describing what's happening in current/latest scan. + * @return a short info string. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public String getCurrentScanInfo() + throws IOException, InstanceNotFoundException; +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManager.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManager.java new file mode 100644 index 0000000..a0a4bb9 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManager.java @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import static com.sun.jmx.examples.scandir.ScanManager.getNextSeqNumber; +import com.sun.jmx.examples.scandir.config.ResultLogConfig; +import com.sun.jmx.examples.scandir.config.XmlConfigUtils; +import com.sun.jmx.examples.scandir.config.ResultRecord; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Logger; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.ObjectName; +import javax.xml.bind.JAXBException; + +/** + * The <code>ResultLogManager</code> is in charge of managing result logs. + * {@link DirectoryScanner DirectoryScanners} can be configured to log a + * {@link ResultRecord} whenever they take action upon a file that + * matches their set of matching criteria. + * The <code>ResultLogManagerMXBean</code> is responsible for storing these + * results in its result logs. + * <p>The <code>ResultLogManagerMXBean</code> can be configured to log + * these records to a flat file, or into a log held in memory, or both. + * Both logs (file and memory) can be configured with a maximum capacity. + * <br>When the maximum capacity of the memory log is reached - its first + * entry (i.e. its eldest entry) is removed to make place for the latest. + * <br>When the maximum capacity of the file log is reached, the file is + * renamed by appending a tilde '~' to its name and a new result log is created. + * + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class ResultLogManager extends NotificationBroadcasterSupport + implements ResultLogManagerMXBean, MBeanRegistration { + + /** + * The default singleton name of the {@link ResultLogManagerMXBean}. + **/ + public static final ObjectName RESULT_LOG_MANAGER_NAME = + ScanManager.makeSingletonName(ResultLogManagerMXBean.class); + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(ResultLogManager.class.getName()); + + // The memory log + // + private final List<ResultRecord> memoryLog; + + // Whether the memory log capacity was reached. In that case every + // new entry triggers the deletion of the eldest one. + // + private volatile boolean memCapacityReached = false; + + // The maximum number of record that the memory log can + // contain. + // + private volatile int memCapacity; + + // The maximum number of record that the ResultLogManager can + // log in the log file before creating a new file. + // + private volatile long fileCapacity; + + // The current log file. + // + private volatile File logFile; + + // The OutputStream of the current log file. + // + private volatile OutputStream logStream = null; + + // number of record that this object has logged in the log file + // since the log file was created. Creating a new file or clearing + // the log file reset this value to '0' + // + private volatile long logCount = 0; + + // The ResultLogManager config - modified whenever + // ScanManager.applyConfiguration is called. + // + private volatile ResultLogConfig config; + + /** + * Create a new ResultLogManagerMXBean. This constructor is package + * protected: only the {@link ScanManager} can create a + * <code>ResultLogManager</code>. + **/ + ResultLogManager() { + // Instantiate the memory log - override the add() method so that + // it removes the head of the list when the maximum capacity is + // reached. Note that add() is the only method we will be calling, + // otherwise we would have to override all the other flavors + // of adding methods. Note also that this implies that the memoryLog + // will *always* remain encapsulated in this object and is *never* + // handed over (otherwise we wouldn't be able to ensure that + // add() is the only method ever called to add a record). + // + memoryLog = + Collections.synchronizedList(new LinkedList<ResultRecord>() { + public synchronized boolean add(ResultRecord e) { + final int max = getMemoryLogCapacity(); + while (max > 0 && size() >= max) { + memCapacityReached = true; + removeFirst(); + } + return super.add(e); + } + }); + + // default memory capacity + memCapacity = 2048; + + // default file capacity: 0 means infinite ;-) + fileCapacity = 0; + + // by default logging to file is disabled. + logFile = null; + + // Until the ScanManager apply a new configuration, we're going to + // work with a default ResultLogConfig object. + config = new ResultLogConfig(); + config.setMemoryMaxRecords(memCapacity); + config.setLogFileName(getLogFileName(false)); + config.setLogFileMaxRecords(fileCapacity); + } + + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. + * <p>If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server.</p> + * <p>The {@code ResultLogManager} uses this method to supply its own + * default singleton ObjectName (if <var>name</var> parameter is null). + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. This name is null if the + * name parameter to one of the createMBean or registerMBean methods in + * the MBeanServer interface is null. In that case, this method must + * return a non-null ObjectName for the new MBean. + * @return The name under which the MBean is to be registered. This value + * must not be null. If the name parameter is not null, it will usually + * but not necessarily be the returned value. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) + name = RESULT_LOG_MANAGER_NAME; + objectName = name; + mbeanServer = server; + return name; + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * <p>This implementation does nothing.</p> + * @param registrationDone Indicates whether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + public void postRegister(Boolean registrationDone) { + // Don't need to do anything here. + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * <p>This implementation does nothing.</p> + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public void preDeregister() throws Exception { + // Don't need to do anything here. + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + * <p>Closes the log file stream, if it is still open.</p> + */ + public void postDeregister() { + try { + if (logStream != null) { + synchronized(this) { + logStream.flush(); + logStream.close(); + logFile = null; + logStream = null; + } + } + } catch (Exception x) { + LOG.finest("Failed to close log properly: "+x); + } + } + + /** + * Create a new empty log file from the given basename, renaming + * previously existing file by appending '~' to its name. + **/ + private File createNewLogFile(String basename) throws IOException { + return XmlConfigUtils.createNewXmlFile(basename); + } + + /** + * Check whether a new log file should be created. + * If a new file needs to be created, creates it, renaming + * previously existing file by appending '~' to its name. + * Also reset the log count and file capacity. + * Sends a notification indicating that the log file was changed. + * Returns the new log stream; + * Creation of a new file can be forced by passing force=true. + **/ + private OutputStream checkLogFile(String basename, long maxRecords, + boolean force) + throws IOException { + final OutputStream newStream; + synchronized(this) { + if ((force==false) && (logCount < maxRecords)) + return logStream; + final OutputStream oldStream = logStream; + + // First close the stream. On some platforms you cannot rename + // a file that has open streams... + // + if (oldStream != null) { + oldStream.flush(); + oldStream.close(); + } + final File newFile = (basename==null)?null:createNewLogFile(basename); + + newStream = (newFile==null)?null:new FileOutputStream(newFile,true); + logStream = newStream; + logFile = newFile; + fileCapacity = maxRecords; + logCount = 0; + } + sendNotification(new Notification(LOG_FILE_CHANGED,objectName, + getNextSeqNumber(), + basename)); + return newStream; + } + + // see ResultLogManagerMXBean + public void log(ResultRecord record) + throws IOException { + if (memCapacity > 0) logToMemory(record); + if (logFile != null) logToFile(record); + } + + // see ResultLogManagerMXBean + public ResultRecord[] getMemoryLog() { + return memoryLog.toArray(new ResultRecord[0]); + } + + // see ResultLogManagerMXBean + public int getMemoryLogCapacity() { + return memCapacity; + } + + // see ResultLogManagerMXBean + public void setMemoryLogCapacity(int maxRecords) { + synchronized(this) { + memCapacity = maxRecords; + if (memoryLog.size() < memCapacity) + memCapacityReached = false; + config.setMemoryMaxRecords(maxRecords); + } + } + + // see ResultLogManagerMXBean + public void setLogFileCapacity(long maxRecords) + throws IOException { + synchronized (this) { + fileCapacity = maxRecords; + config.setLogFileMaxRecords(maxRecords); + } + checkLogFile(getLogFileName(),fileCapacity,false); + } + + // see ResultLogManagerMXBean + public long getLogFileCapacity() { + return fileCapacity; + } + + // see ResultLogManagerMXBean + public long getLoggedCount() { + return logCount; + } + + // see ResultLogManagerMXBean + public void newLogFile(String logname, long maxRecord) + throws IOException { + checkLogFile(logname,maxRecord,true); + config.setLogFileName(getLogFileName(false)); + config.setLogFileMaxRecords(getLogFileCapacity()); + } + + // see ResultLogManagerMXBean + public String getLogFileName() { + return getLogFileName(true); + } + + // see ResultLogManagerMXBean + public void clearLogs() throws IOException { + clearMemoryLog(); + clearLogFile(); + } + + // Clear the memory log, sends a notification indicating that + // the memory log was cleared. + // + private void clearMemoryLog()throws IOException { + synchronized(this) { + memoryLog.clear(); + memCapacityReached = false; + } + sendNotification(new Notification(MEMORY_LOG_CLEARED, + objectName, + getNextSeqNumber(),"memory log cleared")); + } + + // Clears the log file. + // + private void clearLogFile() throws IOException { + // simply force the creation of a new log file. + checkLogFile(getLogFileName(),fileCapacity,true); + } + + // Log a record to the memory log. Send a notification if the + // maximum capacity of the memory log is reached. + // + private void logToMemory(ResultRecord record) { + + final boolean before = memCapacityReached; + final boolean after; + synchronized(this) { + memoryLog.add(record); + after = memCapacityReached; + } + if (before==false && after==true) + sendNotification(new Notification(MEMORY_LOG_MAX_CAPACITY, + objectName, + getNextSeqNumber(),"memory log capacity reached")); + } + + + // Log a record to the memory log. Send a notification if the + // maximum capacity of the memory log is reached. + // + private void logToFile(ResultRecord record) throws IOException { + final String basename; + final long maxRecords; + synchronized (this) { + if (logFile == null) return; + basename = getLogFileName(false); + maxRecords = fileCapacity; + } + + // Get the stream into which we should log. + final OutputStream stream = + checkLogFile(basename,maxRecords,false); + + // logging to file now disabled - too bad. + if (stream == null) return; + + synchronized (this) { + try { + XmlConfigUtils.write(record,stream,true); + stream.flush(); + // don't increment logCount if we were not logging in logStream. + if (stream == logStream) logCount++; + } catch (JAXBException x) { + final IllegalArgumentException iae = + new IllegalArgumentException("bad record",x); + LOG.finest("Failed to log record: "+x); + throw iae; + } + } + } + + /** + * The notification type which indicates that the log file was switched: + * <i>com.sun.jmx.examples.scandir.log.file.switched</i>. + * The message contains the name of the new file (or null if log to file + * is now disabled). + **/ + public final static String LOG_FILE_CHANGED = + "com.sun.jmx.examples.scandir.log.file.switched"; + + /** + * The notification type which indicates that the memory log capacity has + * been reached: + * <i>com.sun.jmx.examples.scandir.log.memory.full</i>. + **/ + public final static String MEMORY_LOG_MAX_CAPACITY = + "com.sun.jmx.examples.scandir.log.memory.full"; + + /** + * The notification type which indicates that the memory log was + * cleared: + * <i>com.sun.jmx.examples.scandir.log.memory.cleared</i>. + **/ + public final static String MEMORY_LOG_CLEARED = + "com.sun.jmx.examples.scandir.log.memory.cleared"; + + /** + * This MBean emits three kind of notifications: + * <pre> + * <i>com.sun.jmx.examples.scandir.log.file.switched</i> + * <i>com.sun.jmx.examples.scandir.log.memory.full</i> + * <i>com.sun.jmx.examples.scandir.log.memory.cleared</i> + * </pre> + **/ + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] { + LOG_FILE_CHANGED}, + Notification.class.getName(), + "Emitted when the log file is switched") + , + new MBeanNotificationInfo(new String[] { + MEMORY_LOG_MAX_CAPACITY}, + Notification.class.getName(), + "Emitted when the memory log capacity is reached") + , + new MBeanNotificationInfo(new String[] { + MEMORY_LOG_CLEARED}, + Notification.class.getName(), + "Emitted when the memory log is cleared") + }; + } + + // Return the name of the log file, or null if logging to file is + // disabled. + private String getLogFileName(boolean absolute) { + synchronized (this) { + if (logFile == null) return null; + if (absolute) return logFile.getAbsolutePath(); + return logFile.getPath(); + } + } + + // This method is be called by the ScanManagerMXBean when a configuration + // is applied. + // + void setConfig(ResultLogConfig logConfigBean) throws IOException { + if (logConfigBean == null) + throw new IllegalArgumentException("logConfigBean is null"); + synchronized (this) { + config = logConfigBean; + setMemoryLogCapacity(config.getMemoryMaxRecords()); + } + final String filename = config.getLogFileName(); + final String logname = getLogFileName(false); + if ((filename != null && !filename.equals(logname)) + || (filename == null && logname != null)) { + newLogFile(config.getLogFileName(), + config.getLogFileMaxRecords()); + } else { + setLogFileCapacity(config.getLogFileMaxRecords()); + } + } + + // This method is called by the ScanManagerMXBean when + // applyCurrentResultLogConfig() is called. + // + ResultLogConfig getConfig() { + return config; + } + + + // Set by preRegister(). + private MBeanServer mbeanServer; + private ObjectName objectName; + + + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.java new file mode 100644 index 0000000..eb1f0f6 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ResultLogManagerMXBean.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.config.ResultRecord; +import java.io.IOException; +import javax.management.InstanceNotFoundException; + +/** + * The <code>ResultLogManagerMXBean</code> is in charge of managing result logs. + * {@link DirectoryScanner DirectoryScanners} can be configured to log a + * {@link ResultRecord} whenever they take action upon a file that + * matches their set of matching criteria. + * The <code>ResultLogManagerMXBean</code> is responsible for storing these + * results in its result logs. + * <p>The <code>ResultLogManagerMXBean</code> + * will let you interactively clear these result logs, change their + * capacity, and decide where (memory or file or both) the + * {@link ResultRecord ResultRecords} should be stored. + * <p>The memory log is useful in so far that its content can be interactively + * returned by the <code>ResultLogManagerMXBean</code>. + * The file log doesn't have this facility. + * <p>The result logs are intended to be used by e.g. an offline program that + * would take some actions on the files that were matched by the scanners + * criteria: + * <p>The <i>scandir</i> application could be configured to only produce logs + * (i.e. takes no action but logging the matching files), and the real + * action (e.g. mail the result log to the engineer which maintains the lab, + * or parse the log and prepare and send a single mail to the matching + * files owners, containing the list of file he/she should consider deleting) + * could be performed by such another program/module. + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public interface ResultLogManagerMXBean { + + /** + * Creates a new log file in which to store results. + * <p>When this method is called, the {@link ResultLogManager} will stop + * logging in its current log file and use the new specified file instead. + * If that file already exists, it will be renamed by appending a '~' to + * its name, and a new empty file with the name specified by + * <var>basename</var> will be created. + * </p> + * <p>Calling this method has no side effect on the {@link + * com.sun.jmx.examples.scandir.config.ScanManagerConfig#getInitialResultLogConfig + * InitialResultLogConfig} held in the {@link ScanDirConfigMXBean} + * configuration. To apply these new values to the + * {@link ScanDirConfigMXBean} + * configuration, you must call {@link + * ScanManagerMXBean#applyCurrentResultLogConfig + * ScanManagerMXBean.applyCurrentResultLogConfig}. + *<p> + * @param basename The name of the new log file. This will be the + * new name returned by {@link #getLogFileName}. + * @param maxRecord maximum number of records to log in the specified file + * before creating a new file. <var>maxRecord</var> will be the + * new value returned by {@link #getLogFileCapacity}. + * When that maximum number of + * records is reached the {@link ResultLogManager} will rename + * the file by appending a '~' to its name, and a new empty + * log file will be created. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void newLogFile(String basename, long maxRecord) + throws IOException, InstanceNotFoundException; + + /** + * Logs a result record to the active result logs (memory,file,both,or none) + * depending on how this MBean is currently configured. + * @see #getLogFileName() + * @see #getMemoryLogCapacity() + * @param record The result record to log. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + */ + public void log(ResultRecord record) + throws IOException, InstanceNotFoundException; + + /** + * Gets the name of the current result log file. + * <p><code>null</code> means that no log file is configured: logging + * to file is disabled. + * </p> + * @return The name of the current result log file, or <code>null</code> + * if logging to file is disabled. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public String getLogFileName() + throws IOException, InstanceNotFoundException; + + /** + * Gets the whole content of the memory log. This cannot exceed + * {@link #getMemoryLogCapacity} records. + * + * @return the whole content of the memory log. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public ResultRecord[] getMemoryLog() + throws IOException, InstanceNotFoundException; + + /** + * Gets the maximum number of records that can be logged in the + * memory log. + * <p> + * A non positive value - <code>0</code> or negative - means that + * logging in memory is disabled. + * </p> + * <p>The memory log is a FIFO: when its maximum capacity is reached, its + * head element is removed to make place for a new element at its tail. + * </p> + * @return The maximum number of records that can be logged in the + * memory log. A value {@code <= 0} means that logging in memory is + * disabled. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public int getMemoryLogCapacity() + throws IOException, InstanceNotFoundException; + + /** + * Sets the maximum number of records that can be logged in the + * memory log. + * <p>The memory log is a FIFO: when its maximum capacity is reached, its + * head element is removed to make place for a new element at its tail. + * </p> + * @param size The maximum number of result records that can be logged in the memory log. <p> + * A non positive value - <code>0</code> or negative - means that + * logging in memory is disabled. It will also have the side + * effect of clearing the memory log. + * </p> + * + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + */ + public void setMemoryLogCapacity(int size) + throws IOException, InstanceNotFoundException; + + /** + * Sets the maximum number of records that can be logged in the result log + * file. + * <p>When that maximum number of + * records is reached the {@link ResultLogManager} will rename + * the result log file by appending a '~' to its name, and a new empty + * log file will be created. + * </p> + * <p>If logging to file is disabled calling this method + * is irrelevant. + * </p> + * @param maxRecord maximum number of records to log in the result log file. + * @see #getLogFileName() + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void setLogFileCapacity(long maxRecord) + throws IOException, InstanceNotFoundException; + + /** + * Gets the maximum number of records that can be logged in the result log + * file. + * <p>When that maximum number of + * records is reached the {@link ResultLogManager} will rename + * the result log file by appending a '~' to its name, and a new empty + * log file will be created. + * </p> + * @see #getLogFileName() + * @return The maximum number of records that can be logged in the result + * log file. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public long getLogFileCapacity() + throws IOException, InstanceNotFoundException; + + /** + * Gets The number of records that have been logged in the + * current result log file. This will always be less than + * {@link #getLogFileCapacity()}. + * @return The number of records in the + * current result log file. + * + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public long getLoggedCount() + throws IOException, InstanceNotFoundException; + + /** + * Clears the memory log and result log file. + * + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void clearLogs() + throws IOException, InstanceNotFoundException; +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirAgent.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirAgent.java new file mode 100644 index 0000000..f4bf1b6 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirAgent.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.management.JMException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; + +/** + * <p> + * The <code>ScanDirAgent</code> is the Agent class for the <i>scandir</i> + * application. + * This class contains the {@link #main} method to start a standalone + * <i>scandir</i> application. + * </p> + * <p> + * The {@link #main main()} method simply registers a {@link + * ScanManagerMXBean} in the platform MBeanServer - see {@link #init init}, + * and then waits for someone to call {@link ScanManagerMXBean#close close} + * on that MBean. + * </p> + * <p> + * When the {@link ScanManagerMXBean} state is switched to {@link + * ScanManagerMXBean.ScanState#CLOSED CLOSED}, {@link #cleanup cleanup} is + * called, the {@link ScanManagerMXBean} is unregistered, and the application + * terminates (i.e. the main thread completes). + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + **/ +public class ScanDirAgent { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(ScanDirAgent.class.getName()); + + // Proxy to the ScanManagerMXBean - created by init(); + // + private volatile ScanManagerMXBean proxy = null; + + // A queue to put received Notifications. + // + private final BlockingQueue<Notification> queue; + + // A listener that will put notifications into the queue. + // + private final NotificationListener listener; + + /** + * Creates a new instance of ScanDirAgent + * You will need to call {@link #init()} later on in order to initialize + * the application. + * @see #main + **/ + public ScanDirAgent() { + // Initialize the notification queue + queue = new LinkedBlockingQueue<Notification>(); + + // Creates the listener. + listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + // Just put the received notification in the queue. + // It will be consumed later on by 'waitForClose()' + // + LOG.finer("Queuing received notification "+notification); + queue.put(notification); + } catch (InterruptedException ex) { + // OK + } + } + }; + } + + /** + * Initialize the application by registering a ScanManagerMXBean in + * the platform MBeanServer + * @throws java.io.IOException Registration failed for communication-related reasons. + * @throws javax.management.JMException Registration failed for JMX-related reasons. + */ + public void init() throws IOException, JMException { + + // Registers the ScanManagerMXBean singleton in the + // platform MBeanServer + // + proxy = ScanManager.register(); + + // Registers a NotificationListener with the ScanManagerMXBean in + // order to receive state changed notifications. + // + ((NotificationEmitter)proxy).addNotificationListener(listener,null,null); + } + + /** + * Cleanup after close: unregister the ScanManagerMXBean singleton. + * @throws java.io.IOException Cleanup failed for communication-related reasons. + * @throws javax.management.JMException Cleanup failed for JMX-related reasons. + */ + public void cleanup() throws IOException, JMException { + try { + ((NotificationEmitter)proxy). + removeNotificationListener(listener,null,null); + } finally { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } + } + + /** + * Wait for someone to call 'close()' on the ScanManagerMXBean singleton. + * Every time its state changes, the ScanManagerMXBean emits a notification. + * We don't rely on the notification content (if we were using a remote + * connection, we could miss some notifications) - we simply use the + * state change notifications to react more quickly to state changes. + * We do so simply by polling the {@link BlockingQueue} in which our + * listener is pushing notifications, and checking the ScanManagerMXBean + * state every time that a notification is received. + * <p> + * We can do so because we know that once the ScanManagerMXBean state is + * switched to 'CLOSED', it will remain 'CLOSED' whatsoever. <br> + * Therefore we don't need to concern ourselves with the possibility of + * missing the window in which the ScanManagerMXBean state's will be + * CLOSED, because that particular window stays opened forever. + * <p> + * Had we wanted to wait for 'RUNNING', we would have needed to apply + * a different strategy - e.g. by taking into account the actual content + * of the state changed notifications we received. + * @throws java.io.IOException wait failed - a communication problem occurred. + * @throws javax.management.JMException wait failed - the MBeanServer threw an exception. + */ + public void waitForClose() throws IOException, JMException { + + // Wait until state is closed + while(proxy.getState() != ScanState.CLOSED ) { + try { + // Wake up at least every 30 seconds - if we missed a + // notification - we will at least get a chance to + // call getState(). 30 seconds is obviously quite + // arbitrary - if this were a real daemon - id'be tempted + // to wait 30 minutes - knowing that any incoming + // notification will wake me up anyway. + // Note: we simply use the state change notifications to + // react more quickly to state changes: see javadoc above. + // + queue.poll(30,TimeUnit.SECONDS); + } catch (InterruptedException ex) { + // OK + } + } + } + + /** + * The agent's main: {@link #init registers} a {@link ScanManagerMXBean}, + * {@link #waitForClose waits} until its state is {@link + * ScanManagerMXBean.ScanState#CLOSED CLOSED}, {@link #cleanup cleanup} + * and exits. + * @param args the command line arguments - ignored + * @throws java.io.IOException A communication problem occurred. + * @throws javax.management.JMException A JMX problem occurred. + */ + public static void main(String[] args) + throws IOException, JMException { + System.out.println("Initializing ScanManager..."); + final ScanDirAgent agent = new ScanDirAgent(); + agent.init(); + try { + System.out.println("Waiting for ScanManager to close..."); + agent.waitForClose(); + } finally { + System.out.println("Cleaning up..."); + agent.cleanup(); + } + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirClient.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirClient.java new file mode 100644 index 0000000..442a607 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirClient.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.rmi.ssl.SslRMIClientSocketFactory; + +/** + * The ScanDirClient class is a very simple programmatic client example + * which is able to connect to a secured JMX <i>scandir</i> application. + * <p>The program initialize the connection environment map with the + * appropriate properties and credentials, and then connects to the + * secure JMX <i>scandir</i> daemon.</p> + * <p>It gets the application's current configuration and prints it on + * its <code>System.out</code>.</p> + * <p>The {@link #main main} method takes two arguments: the host on which + * the server is running (localhost), and the port number + * that was configured to start the server RMI Connector (4545). + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + **/ +public class ScanDirClient { + + // This class has only a main. + private ScanDirClient() { } + + /** + * The usage string for the ScanDirClient. + */ + public static final String USAGE = ScanDirClient.class.getSimpleName() + + " <server-host> <rmi-port-number>"; + + /** + * Connects to a secured JMX <i>scandir</i> application. + * @param args The {@code main} method takes two parameters: + * <ul> + * <li>args[0] must be the server's host</li> + * <li>args[1] must be the rmi port number at which the + * JMX <i>scandir</i> daemon is listening for connections + * - that is, the port number of its JMX RMI Connector which + * was configured in {@code management.properties} + * </li> + * <ul> + **/ + public static void main(String[] args) { + try { + // Check args + // + if (args==null || args.length!=2) { + System.err.println("Bad number of arguments: usage is: \n\t" + + USAGE); + System.exit(1); + } + try { + InetAddress.getByName(args[0]); + } catch (UnknownHostException x) { + System.err.println("No such host: " + args[0]+ + "\n usage is: \n\t" + USAGE); + System.exit(2); + } catch (Exception x) { + System.err.println("Bad address: " + args[0]+ + "\n usage is: \n\t" + USAGE); + System.exit(2); + } + try { + if (Integer.parseInt(args[1]) <= 0) { + System.err.println("Bad port value: " + args[1]+ + "\n usage is: \n\t" + USAGE); + System.exit(2); + } + } catch (Exception x) { + System.err.println("Bad argument: " + args[1]+ + "\n usage is: \n\t" + USAGE); + System.exit(2); + } + + // Create an environment map to hold connection properties + // like credentials etc... We will later pass this map + // to the JMX Connector. + // + System.out.println("\nInitialize the environment map"); + final Map<String,Object> env = new HashMap<String,Object>(); + + // Provide the credentials required by the server + // to successfully perform user authentication + // + final String[] credentials = new String[] { "guest" , "guestpasswd" }; + env.put("jmx.remote.credentials", credentials); + + // Provide the SSL/TLS-based RMI Client Socket Factory required + // by the JNDI/RMI Registry Service Provider to communicate with + // the SSL/TLS-protected RMI Registry + // + env.put("com.sun.jndi.rmi.factory.socket", + new SslRMIClientSocketFactory()); + + // Create the RMI connector client and + // connect it to the RMI connector server + // args[0] is the server's host - localhost + // args[1] is the secure server port - 4545 + // + System.out.println("\nCreate the RMI connector client and " + + "connect it to the RMI connector server"); + final JMXServiceURL url = new JMXServiceURL( + "service:jmx:rmi:///jndi/rmi://"+args[0]+":"+args[1] + + "/jmxrmi"); + + System.out.println("Connecting to: "+url); + final JMXConnector jmxc = JMXConnectorFactory.connect(url, env); + + // Get an MBeanServerConnection + // + System.out.println("\nGet the MBeanServerConnection"); + final MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + + // Create a proxy for the ScanManager MXBean + // + final ScanManagerMXBean proxy = + ScanManager.newSingletonProxy(mbsc); + + // Get the ScanDirConfig MXBean from the scan manager + // + System.out.println( + "\nGet ScanDirConfigMXBean from ScanManagerMXBean"); + final ScanDirConfigMXBean configMBean = + proxy.getConfigurationMBean(); + + // Print the scan dir configuration + // + System.out.println( + "\nGet 'Configuration' attribute on ScanDirConfigMXBean"); + System.out.println("\nConfiguration:\n" + + configMBean.getConfiguration()); + + // Try to invoke the "close" method on the ScanManager MXBean. + // + // Should get a SecurityException as the user "guest" doesn't + // have readwrite access. + // + System.out.println("\nInvoke 'close' on ScanManagerMXBean"); + try { + proxy.close(); + } catch (SecurityException e) { + System.out.println("\nGot expected security exception: " + e); + } + + // Close MBeanServer connection + // + System.out.println("\nClose the connection to the server"); + jmxc.close(); + System.out.println("\nBye! Bye!"); + } catch (Exception e) { + System.out.println("\nGot unexpected exception: " + e); + e.printStackTrace(); + System.exit(3); + } + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfig.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfig.java new file mode 100644 index 0000000..7ecd8a1 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfig.java @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import static com.sun.jmx.examples.scandir.ScanManager.getNextSeqNumber; +import static com.sun.jmx.examples.scandir.ScanDirConfigMXBean.SaveState.*; +import com.sun.jmx.examples.scandir.config.XmlConfigUtils; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.FileMatch; +import com.sun.jmx.examples.scandir.config.ScanManagerConfig; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.*; +import javax.xml.bind.JAXBException; + +/** + * <p>The <code>ScanDirConfig</code> MBean is in charge of the + * <i>scandir</i> application configuration. + * </p> + * <p>The <code>ScanDirConfig</code> MBean is able to + * load and save the <i>scandir</i> application configuration to and from an + * XML file. + * </p> + * <p> + * It will let you also interactively modify that configuration, which you + * can later save to the file, by calling {@link #save}, or discard, by + * reloading the file without saving - see {@link #load}. + * </p> + * <p> + * There can be as many <code>ScanDirConfigMXBean</code> registered + * in the MBeanServer as you like, but only one of them will be identified as + * the current configuration of the {@link ScanManagerMXBean}. + * You can switch to another configuration by calling {@link + * ScanManagerMXBean#setConfigurationMBean + * ScanManagerMXBean.setConfigurationMBean}. + * </p> + * <p> + * Once the current configuration has been loaded (by calling {@link #load}) + * or modified (by calling one of {@link #addDirectoryScanner + * addDirectoryScanner}, {@link #removeDirectoryScanner removeDirectoryScanner} + * or {@link #setConfiguration setConfiguration}) it can be pushed + * to the {@link ScanManagerMXBean} by calling {@link + * ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration(true)} - + * <code>true</code> means that we apply the configuration from memory, + * without first reloading the file. + * </p> + * <p> + * The <code>ScanDirConfig</code> uses the XML annotated Java Beans defined + * in the {@link com.sun.jmx.examples.scandir.config} package. + * </p> + * <p> + * <u>Note:</u> The <code>ScanDirConfig</code> should probably use + * {@code java.nio.channels.FileLock} and lock its configuration file so that + * two <code>ScanDirConfig</code> object do not share the same file, but it + * doesn't. Feel free to improve the application in that way. + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class ScanDirConfig extends NotificationBroadcasterSupport + implements ScanDirConfigMXBean, MBeanRegistration { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(ScanDirConfig.class.getName()); + + // We will emit a notification when the save state of this object + // chenges. We use directly the base notification class, with a + // notification type that indicates the new state at which the + // object has arrived. + // + // All these notification types will have the same prefix, which is + // 'com.sun.jmx.examples.scandir.config'. + // + private final static String NOTIFICATION_PREFIX = + ScanManagerConfig.class.getPackage().getName(); + + /** + * The <i>com.sun.jmx.examples.scandir.config.saved</i> notification + * indicates that the configuration data was saved. + **/ + public final static String NOTIFICATION_SAVED = + NOTIFICATION_PREFIX+".saved"; + /** + * The <i>com.sun.jmx.examples.scandir.config.loaded</i> notification + * indicates that the configuration data was loaded. + **/ + public final static String NOTIFICATION_LOADED = + NOTIFICATION_PREFIX+".loaded"; + + /** + * The <i>com.sun.jmx.examples.scandir.config.modified</i> notification + * indicates that the configuration data was modified. + **/ + public final static String NOTIFICATION_MODIFIED = + NOTIFICATION_PREFIX+".modified"; + + // The array of MBeanNotificationInfo that will be exposed in the + // ScanDirConfigMXBean MBeanInfo. + // We will pass this array to the NotificationBroadcasterSupport + // constructor. + // + private static MBeanNotificationInfo[] NOTIFICATION_INFO = { + new MBeanNotificationInfo( + new String[] {NOTIFICATION_SAVED}, + Notification.class.getName(), + "Emitted when the configuration is saved"), + new MBeanNotificationInfo( + new String[] {NOTIFICATION_LOADED}, + Notification.class.getName(), + "Emitted when the configuration is loaded"), + new MBeanNotificationInfo( + new String[] {NOTIFICATION_MODIFIED}, + Notification.class.getName(), + "Emitted when the configuration is modified"), + }; + + // The ScanDirConfigMXBean configuration data. + private volatile ScanManagerConfig config; + + // The name of the configuration file + private String filename = null; + + // The name of this configuration. This is usually both equal to + // config.getName() and objectName.getKeyProperty(name). + private volatile String configname = null; + + // This object save state. CREATED is the initial state. + // + private volatile SaveState status = CREATED; + + /** + * Creates a new {@link ScanDirConfigMXBean}. + * <p>{@code ScanDirConfigMXBean} can be created by the {@link + * ScanManagerMXBean}, or directly by a remote client, using + * {@code createMBean} or {@code registerMBean}. + * </p> + * <p>{@code ScanDirConfigMXBean} created by the {@link + * ScanManagerMXBean} will be unregistered by the + * {@code ScanManagerMXBean}. {@code ScanDirConfigMXBean} created + * directly by a remote client will not be unregistered by the + * {@code ScanManagerMXBean} - this will remain to the responsibility of + * the code/client that created them. + * </p> + * <p>This object is created empty, you should call load() if you want it + * to load its data from the configuration file. + * </p> + * @param filename The configuration file used by this MBean. + * Can be null (in which case load() and save() will fail). + * Can point to a file that does not exists yet (in which case + * load() will fail if called before save(), and save() will + * attempt to create that file). Can point to an existing file, + * in which case load() will load that file and save() will save + * to that file. + * + **/ + public ScanDirConfig(String filename) { + this(filename,null); + } + + /** + * Create a new ScanDirConfig MBean with an initial configuration. + * @param filename The name of the configuration file. + * @param initialConfig an initial configuration. + **/ + public ScanDirConfig(String filename, ScanManagerConfig initialConfig) { + super(NOTIFICATION_INFO); + this.filename = filename; + this.config = initialConfig; + } + + + // see ScanDirConfigMXBean + public void load() throws IOException { + if (filename == null) + throw new UnsupportedOperationException("load"); + + synchronized(this) { + config = new XmlConfigUtils(filename).readFromFile(); + if (configname != null) config = config.copy(configname); + else configname = config.getName(); + + status=LOADED; + } + sendNotification(NOTIFICATION_LOADED); + } + + // see ScanDirConfigMXBean + public void save() throws IOException { + if (filename == null) + throw new UnsupportedOperationException("load"); + synchronized (this) { + new XmlConfigUtils(filename).writeToFile(config); + status = SAVED; + } + sendNotification(NOTIFICATION_SAVED); + } + + // see ScanDirConfigMXBean + public ScanManagerConfig getConfiguration() { + synchronized (this) { + return XmlConfigUtils.xmlClone(config); + } + } + + + // sends a notification indicating the new save state. + private void sendNotification(String type) { + final Object source = (objectName==null)?this:objectName; + final Notification n = new Notification(type,source, + getNextSeqNumber(), + "The configuration is "+ + type.substring(type.lastIndexOf('.')+1)); + sendNotification(n); + } + + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. This name is null if the + * name parameter to one of the createMBean or registerMBean methods in + * the MBeanServer interface is null. In that case, this method will + * try to guess its MBean name by examining its configuration data. + * If its configuration data is null (nothing was provided in the + * constructor) or doesn't contain a name, this method returns {@code null}, + * and registration will fail. + * <p> + * Otherwise, if {@code name} wasn't {@code null} or if a default name could + * be constructed, the name of the configuration will be set to + * the value of the ObjectName's {@code name=} key, and the configuration + * data will always be renamed to reflect this change. + * </p> + * + * @return The name under which the MBean is to be registered. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) { + if (config == null) return null; + if (config.getName() == null) return null; + name = ScanManager. + makeMBeanName(ScanDirConfigMXBean.class,config.getName()); + } + objectName = name; + mbeanServer = server; + synchronized (this) { + configname = name.getKeyProperty("name"); + if (config == null) config = new ScanManagerConfig(configname); + else config = config.copy(configname); + } + return name; + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * <p>This implementation does nothing</p> + * @param registrationDone Indicates whether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + public void postRegister(Boolean registrationDone) { + // Nothing to do here. + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * <p>This implementation does nothing</p> + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public void preDeregister() throws Exception { + // Nothing to do here. + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + * <p>This implementation does nothing</p> + */ + public void postDeregister() { + // Nothing to do here. + } + + // see ScanDirConfigMXBean + public String getConfigFilename() { + return filename; + } + + // see ScanDirConfigMXBean + public void setConfiguration(ScanManagerConfig config) { + synchronized (this) { + if (config == null) { + this.config = null; + return; + } + + if (configname == null) + configname = config.getName(); + + this.config = config.copy(configname); + status = MODIFIED; + } + sendNotification(NOTIFICATION_MODIFIED); + } + + // see ScanDirConfigMXBean + public DirectoryScannerConfig + addDirectoryScanner(String name, String dir, String filePattern, + long sizeExceedsMaxBytes, long sinceLastModified) { + final DirectoryScannerConfig scanner = + new DirectoryScannerConfig(name); + scanner.setRootDirectory(dir); + if (filePattern!=null||sizeExceedsMaxBytes>0||sinceLastModified>0) { + final FileMatch filter = new FileMatch(); + filter.setFilePattern(filePattern); + filter.setSizeExceedsMaxBytes(sizeExceedsMaxBytes); + if (sinceLastModified > 0) + filter.setLastModifiedBefore(new Date(new Date().getTime() + -sinceLastModified)); + scanner.addIncludeFiles(filter); + } + synchronized (this) { + config.putScan(scanner); + status = MODIFIED; + } + LOG.fine("config: "+config); + sendNotification(NOTIFICATION_MODIFIED); + return scanner; + } + + // see ScanDirConfigMXBean + public DirectoryScannerConfig removeDirectoryScanner(String name) + throws IOException, InstanceNotFoundException { + final DirectoryScannerConfig scanner; + synchronized (this) { + scanner = config.removeScan(name); + if (scanner == null) + throw new IllegalArgumentException(name+": scanner not found"); + status = MODIFIED; + } + sendNotification(NOTIFICATION_MODIFIED); + return scanner; + } + + // see ScanDirConfigMXBean + public SaveState getSaveState() { + return status; + } + + // These methods are used by ScanManager to guess a configuration name from + // a configuration filename. + // + static String DEFAULT = "DEFAULT"; + + private static String getBasename(String name) { + final int dot = name.indexOf('.'); + if (dot<0) return name; + if (dot==0) return getBasename(name.substring(1)); + return name.substring(0,dot); + } + + static String guessConfigName(String configFileName,String defaultFile) { + try { + if (configFileName == null) return DEFAULT; + final File f = new File(configFileName); + if (f.canRead()) { + final String confname = XmlConfigUtils.read(f).getName(); + if (confname != null && confname.length()>0) return confname; + } + final File f2 = new File(defaultFile); + if (f.equals(f2)) return DEFAULT; + final String guess = getBasename(f.getName()); + if (guess == null) return DEFAULT; + if (guess.length()==0) return DEFAULT; + return guess; + } catch (Exception x) { + return DEFAULT; + } + } + + // Set by preRegister() + private volatile MBeanServer mbeanServer; + private volatile ObjectName objectName; + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.java new file mode 100644 index 0000000..eb4f375 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanDirConfigMXBean.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.ScanManagerConfig; +import java.io.IOException; +import javax.management.InstanceNotFoundException; + +/** + * <p>The <code>ScanDirConfigMXBean</code> is in charge of the + * <i>scandir</i> application configuration. + * </p> + * <p>The <code>ScanDirConfigMXBean</code> is an MBean which is able to + * load and save the <i>scandir</i> application configuration to and from an + * XML file. + * </p> + * <p> + * It will let you also interactively modify that configuration, which you + * can later save to the file, by calling {@link #save}, or discard, by + * reloading the file without saving - see {@link #load}. + * </p> + * <p> + * There can be as many <code>ScanDirConfigMXBean</code> registered + * in the MBeanServer as you like, but only one of them will be identified as + * the current configuration of the {@link ScanManagerMXBean}. + * You can switch to another configuration by calling {@link + * ScanManagerMXBean#setConfigurationMBean + * ScanManagerMXBean.setConfigurationMBean}. + * </p> + * <p> + * Once the current configuration has been loaded (by calling {@link #load}) + * or modified (by calling one of {@link #addDirectoryScanner + * addDirectoryScanner}, {@link #removeDirectoryScanner removeDirectoryScanner} + * or {@link #setConfiguration setConfiguration}) it can be pushed + * to the {@link ScanManagerMXBean} by calling {@link + * ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration(true)} - + * <code>true</code> means that we apply the configuration from memory, + * without first reloading the file. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public interface ScanDirConfigMXBean { + /** + * This state tells whether the configuration reflected by the + * {@link ScanDirConfigMXBean} was loaded in memory, saved to the + * configuration file, or modified since last saved. + * Note that this state doesn't tell whether the configuration was + * applied by the {@link ScanManagerMXBean}. + **/ + public enum SaveState { + /** + * Initial state: the {@link ScanDirConfigMXBean} is created, but + * neither {@link #load} or {@link #save} was yet called. + **/ + CREATED, + + /** + * The configuration reflected by the {@link ScanDirConfigMXBean} has + * been loaded, but not modified yet. + **/ + LOADED, + + /** + * The configuration was modified. The modifications are held in memory. + * Call {@link #save} to save them to the file, or {@link #load} to + * reload the file and discard them. + **/ + MODIFIED, + + /** + * The configuration was saved. + **/ + SAVED + }; + + /** + * Loads the configuration from the {@link + * #getConfigFilename configuration file}. + * <p>Any unsaved modification will be lost. The {@link #getSaveState state} + * is switched to {@link SaveState#LOADED LOADED}. + * </p> + * <p> + * This action has no effect on the {@link ScanManagerMXBean} until + * {@link ScanManagerMXBean#getConfigurationMBean ScanManagerMXBean} + * points to this MBean and {@link ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration} is called. + * </p> + * @see #getSaveState() + * @throws IOException The configuration couldn't be loaded from the file, + * e.g. because the file doesn't exist or isn't + * readable. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void load() + throws IOException, InstanceNotFoundException; + + /** + * Saves the configuration to the {@link + * #getConfigFilename configuration file}. + * + * <p>If the configuration file doesn't exists, this method will + * attempt to create it. Otherwise, the existing file will + * be renamed by appending a '~' to its name, and a new file + * will be created, in which the configuration will be saved. + * The {@link #getSaveState state} + * is switched to {@link SaveState#SAVED SAVED}. + * </p> + * <p> + * This action has no effect on the {@link ScanManagerMXBean}. + * </p> + * @see #getSaveState() + * + * @throws IOException The configuration couldn't be saved to the file, + * e.g. because the file couldn't be created. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void save() + throws IOException, InstanceNotFoundException; + + /** + * Gets the name of the configuration file. + * <p>If the configuration file doesn't exists, {@link #load} will fail + * and {@link #save} will attempt to create the file. + * </p> + * + * @return The configuration file name for this MBean. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public String getConfigFilename() + throws IOException, InstanceNotFoundException; + + /** + * Gets the current configuration data. + * <p> + * This method returns the configuration data which is currently held + * in memory. + * </p> + * <p>Call {@link #load} to reload the data from the configuration + * file, and {@link #save} to save the data to the configuration + * file. + * </p> + * @see #getSaveState() + * @return The current configuration data in memory. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public ScanManagerConfig getConfiguration() + throws IOException, InstanceNotFoundException; + + /** + * Sets the current configuration data. + * <p> + * This method replaces the configuration data in memory. + * The {@link #getSaveState state} is switched to {@link + * SaveState#MODIFIED MODIFIED}. + * </p> + * <p>Calling {@link #load} will reload the data from the configuration + * file, and all modifications will be lost. + * Calling {@link #save} will save the modified data to the configuration + * file. + * </p> + * <p> + * This action has no effect on the {@link ScanManagerMXBean} until + * {@link ScanManagerMXBean#getConfigurationMBean ScanManagerMXBean} + * points to this MBean and {@link ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration} is called. + * </p> + * @param config The new configuration data. + * @see #getSaveState() + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + */ + public void setConfiguration(ScanManagerConfig config) + throws IOException, InstanceNotFoundException; + + /** + * Adds a new directory scanner to the current configuration data. + * <p> + * This method updates the configuration data in memory, adding + * a {@link DirectoryScannerConfig} to the {@link + * ScanManagerConfig#getScanList directory scanner list}. + * The {@link #getSaveState state} is switched to {@link + * SaveState#MODIFIED MODIFIED}. + * </p> + * <p>Calling {@link #load} will reload the data from the configuration + * file, and all modifications will be lost. + * Calling {@link #save} will save the modified data to the configuration + * file. + * </p> + * <p> + * This action has no effect on the {@link ScanManagerMXBean} until + * {@link ScanManagerMXBean#getConfigurationMBean ScanManagerMXBean} + * points to this MBean and {@link ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration} is called. + * </p> + * @param name A name for the new directory scanner. This is the value + * that will be later used in the {@link DirectoryScannerMXBean} + * ObjectName for the <code>name=</code> key. + * @param dir The root directory at which this scanner will start scanning. + * @param filePattern A {@link java.util.regex.Pattern regular expression} + * to match against a selected file name. + * @param sizeExceedsMaxBytes Only file whose size exceeds that limit will + * be selected. <code.0</code> or a + * negative value means no limit. + * @param sinceLastModified Select files which haven't been modified for + * that number of milliseconds - i.e. + * {@code sinceLastModified=3600000} will exclude files which + * have been modified in the last hour. + * The date of last modification is ignored if <code>0</code> or a + * negative value is provided. + * @see #getSaveState() + * @return The added <code>DirectoryScannerConfig</code>. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public DirectoryScannerConfig + addDirectoryScanner(String name, String dir, String filePattern, + long sizeExceedsMaxBytes, long sinceLastModified) + throws IOException, InstanceNotFoundException; + + /** + * Removes a directory scanner from the current configuration data. + * <p> + * This method updates the configuration data in memory, removing + * a {@link DirectoryScannerConfig} from the {@link + * ScanManagerConfig#getScanList directory scanner list}. + * The {@link #getSaveState state} is switched to {@link + * SaveState#MODIFIED MODIFIED}. + * </p> + * <p>Calling {@link #load} will reload the data from the configuration + * file, and all modifications will be lost. + * Calling {@link #save} will save the modified data to the configuration + * file. + * </p> + * <p> + * This action has no effect on the {@link ScanManagerMXBean} until + * {@link ScanManagerMXBean#getConfigurationMBean ScanManagerMXBean} + * points to this MBean and {@link ScanManagerMXBean#applyConfiguration + * ScanManagerMXBean.applyConfiguration} is called. + * </p> + * @param name The name of the new directory scanner. This is the value + * that is used in the {@link DirectoryScannerMXBean} + * ObjectName for the <code>name=</code> key. + * @return The removed <code>DirectoryScannerConfig</code>. + * @throws IllegalArgumentException if there's no directory scanner by + * that name in the current configuration data. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public DirectoryScannerConfig + removeDirectoryScanner(String name) + throws IOException, InstanceNotFoundException; + + /** + * Gets the save state of the current configuration data. + * <p> + * {@link SaveState#CREATED CREATED} means that the configuration data was just + * created. It has not been loaded from the configuration file. + * Calling {@link #load} will load the data from the configuration file. + * Calling {@link #save} will write the empty data to the configuration + * file. + * </p> + * <p> + * {@link SaveState#LOADED LOADED} means that the configuration data + * was loaded from the configuration file. + * </p> + * <p> + * {@link SaveState#MODIFIED MODIFIED} means that the configuration data + * was modified since it was last loaded or saved. + * Calling {@link #load} will reload the data from the configuration file, + * and all modifications will be lost. + * Calling {@link #save} will write the modified data to the configuration + * file. + * </p> + * <p> + * {@link SaveState#SAVED SAVED} means that the configuration data + * was saved to the configuration file. + * </p> + * <p> + * This state doesn't indicate whether this MBean configuration data + * was {@link ScanManagerMXBean#applyConfiguration applied} by the + * {@link ScanManagerMXBean}. + * </p> + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + * @return The save state of the {@code ScanDirConfigMXBean}. + */ + public SaveState getSaveState() + throws IOException, InstanceNotFoundException; + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManager.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManager.java new file mode 100644 index 0000000..e34b12a --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManager.java @@ -0,0 +1,1160 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.ScanManagerConfig; +import java.io.File; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.AttributeChangeNotification; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * <p> + * The <code>ScanManager</code> is responsible for applying a configuration, + * starting and scheduling directory scans, and reporting application state. + * </p> + * <p> + * The ScanManager MBean is a singleton MBean which controls + * scan session. The ScanManager name is defined by + * {@link #SCAN_MANAGER_NAME ScanManager.SCAN_MANAGER_NAME}. + * </p> + * <p> + * The <code>ScanManager</code> MBean is the entry point of the <i>scandir</i> + * application management interface. It is from this MBean that all other MBeans + * will be created and registered. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class ScanManager implements ScanManagerMXBean, + NotificationEmitter, MBeanRegistration { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(ScanManager.class.getName()); + + /** + * The name of the ScanManager singleton MBean. + **/ + public final static ObjectName SCAN_MANAGER_NAME = + makeSingletonName(ScanManagerMXBean.class); + + /** + * Sequence number used for sending notifications. We use this + * sequence number throughout the application. + **/ + private static long seqNumber=0; + + /** + * The NotificationBroadcasterSupport object used to handle + * listener registration. + **/ + private final NotificationBroadcasterSupport broadcaster; + + /** + * The MBeanServer in which this MBean is registered. We obtain + * this reference by implementing the {@link MBeanRegistration} + * interface. + **/ + private volatile MBeanServer mbeanServer; + + /** + * A queue of pending notifications we are about to send. + * We're using a BlockingQueue in order to avoid sending + * notifications from within a synchronized block. + **/ + private final BlockingQueue<Notification> pendingNotifs; + + /** + * The state of the scan session. + **/ + private volatile ScanState state = STOPPED; + + /** + * The list of DirectoryScannerMBean that are run by a scan session. + **/ + private final Map<ObjectName,DirectoryScannerMXBean> scanmap; + + /** + * The list of ScanDirConfigMXBean that were created by this MBean. + **/ + private final Map<ObjectName, ScanDirConfigMXBean> configmap; + + // The ResultLogManager for this application. + private final ResultLogManager log; + + /** + * We use a semaphore to ensure proper sequencing of exclusive + * action. The logic we have implemented is to fail - rather + * than block, if an exclusive action is already in progress. + **/ + private final Semaphore sequencer = new Semaphore(1); + + // A proxy to the current ScanDirConfigMXBean which holds the current + // configuration data. + // + private volatile ScanDirConfigMXBean config = null; + + // Avoid to write parameters twices when creating a new ConcurrentHashMap. + // + private static <K, V> Map<K, V> newConcurrentHashMap() { + return new ConcurrentHashMap<K, V>(); + } + + // Avoid to write parameters twices when creating a new HashMap. + // + private static <K, V> Map<K, V> newHashMap() { + return new HashMap<K, V>(); + } + + /** + * Creates a default singleton ObjectName for a given class. + * @param clazz The interface class of the MBean for which we want to obtain + * a default singleton name, or its implementation class. + * Give one or the other depending on what you wish to see in + * the value of the key {@code type=}. + * @return A default singleton name for a singleton MBean class. + * @throws IllegalArgumentException if the name can't be created + * for some unfathomable reason (e.g. an unexpected + * exception was raised). + **/ + public final static ObjectName makeSingletonName(Class clazz) { + try { + final Package p = clazz.getPackage(); + final String packageName = (p==null)?null:p.getName(); + final String className = clazz.getSimpleName(); + final String domain; + if (packageName == null || packageName.length()==0) { + // We use a reference to ScanDirAgent.class to ease + // to keep track of possible class renaming. + domain = ScanDirAgent.class.getSimpleName(); + } else { + domain = packageName; + } + final ObjectName name = new ObjectName(domain,"type",className); + return name; + } catch (Exception x) { + final IllegalArgumentException iae = + new IllegalArgumentException(String.valueOf(clazz),x); + throw iae; + } + } + + /** + * Creates a default ObjectName with keys <code>type=</code> and + * <code>name=</code> for an instance of a given MBean interface class. + * @param clazz The interface class of the MBean for which we want to obtain + * a default name, or its implementation class. + * Give one or the other depending on what you wish to see in + * the value of the key {@code type=}. + * @param name The value of the <code>name=</code> key. + * @return A default name for an instance of the given MBean interface class. + * @throws IllegalArgumentException if the name can't be created. + * (e.g. an unexpected exception was raised). + **/ + public static final ObjectName makeMBeanName(Class clazz, String name) { + try { + return ObjectName. + getInstance(makeSingletonName(clazz) + .toString()+",name="+name); + } catch (MalformedObjectNameException x) { + final IllegalArgumentException iae = + new IllegalArgumentException(String.valueOf(name),x); + throw iae; + } + } + + /** + * Return the ObjectName for a DirectoryScannerMXBean of that name. + * This is {@code makeMBeanName(DirectoryScannerMXBean.class,name)}. + * @param name The value of the <code>name=</code> key. + * @return the ObjectName for a DirectoryScannerMXBean of that name. + */ + public static final ObjectName makeDirectoryScannerName(String name) { + return makeMBeanName(DirectoryScannerMXBean.class,name); + } + + /** + * Return the ObjectName for a {@code ScanDirConfigMXBean} of that name. + * This is {@code makeMBeanName(ScanDirConfigMXBean.class,name)}. + * @param name The value of the <code>name=</code> key. + * @return the ObjectName for a {@code ScanDirConfigMXBean} of that name. + */ + public static final ObjectName makeScanDirConfigName(String name) { + return makeMBeanName(ScanDirConfigMXBean.class,name); + } + + /** + * Create and register a new singleton instance of the ScanManager + * MBean in the given {@link MBeanServerConnection}. + * @param mbs The MBeanServer in which the new singleton instance + * should be created. + * @throws JMException The MBeanServer connection raised an exception + * while trying to instantiate and register the singleton MBean + * instance. + * @throws IOException There was a connection problem while trying to + * communicate with the underlying MBeanServer. + * @return A proxy for the registered MBean. + **/ + public static ScanManagerMXBean register(MBeanServerConnection mbs) + throws IOException, JMException { + final ObjectInstance moi = + mbs.createMBean(ScanManager.class.getName(),SCAN_MANAGER_NAME); + final ScanManagerMXBean proxy = + JMX.newMXBeanProxy(mbs,moi.getObjectName(), + ScanManagerMXBean.class,true); + return proxy; + } + + /** + * Creates a new {@code ScanManagerMXBean} proxy over the given + * {@code MBeanServerConnection}. Does not check whether a + * {@code ScanManagerMXBean} + * is actually registered in that {@code MBeanServerConnection}. + * @return a new {@code ScanManagerMXBean} proxy. + * @param mbs The {@code MBeanServerConnection} which holds the + * {@code ScanManagerMXBean} to proxy. + */ + public static ScanManagerMXBean + newSingletonProxy(MBeanServerConnection mbs) { + final ScanManagerMXBean proxy = + JMX.newMXBeanProxy(mbs,SCAN_MANAGER_NAME, + ScanManagerMXBean.class,true); + return proxy; + } + + /** + * Creates a new {@code ScanManagerMXBean} proxy over the platform + * {@code MBeanServer}. This is equivalent to + * {@code newSingletonProxy(ManagementFactory.getPlatformMBeanServer())}. + * @return a new {@code ScanManagerMXBean} proxy. + **/ + public static ScanManagerMXBean newSingletonProxy() { + return newSingletonProxy(ManagementFactory.getPlatformMBeanServer()); + } + + /** + * Create and register a new singleton instance of the ScanManager + * MBean in the given {@link MBeanServerConnection}. + * @throws JMException The MBeanServer connection raised an exception + * while trying to instantiate and register the singleton MBean + * instance. + * @throws IOException There was a connection problem while trying to + * communicate with the underlying MBeanServer. + * @return A proxy for the registered MBean. + **/ + public static ScanManagerMXBean register() + throws IOException, JMException { + final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + return register(mbs); + } + + /** + * Create a new ScanManager MBean + **/ + public ScanManager() { + broadcaster = new NotificationBroadcasterSupport(); + pendingNotifs = new LinkedBlockingQueue<Notification>(100); + scanmap = newConcurrentHashMap(); + configmap = newConcurrentHashMap(); + log = new ResultLogManager(); + } + + + // Creates a new DirectoryScannerMXBean, from the given configuration data. + DirectoryScannerMXBean createDirectoryScanner(DirectoryScannerConfig config) { + return new DirectoryScanner(config,log); + } + + // Applies a configuration. + // throws IllegalStateException if lock can't be acquired. + // Unregisters all existing directory scanners, the create and registers + // new directory scanners according to the given config. + // Then pushes the log config to the result log manager. + // + private void applyConfiguration(ScanManagerConfig bean) + throws IOException, JMException { + if (bean == null) return; + if (!sequencer.tryAcquire()) { + throw new IllegalStateException("Can't acquire lock"); + } + try { + unregisterScanners(); + final DirectoryScannerConfig[] scans = bean.getScanList(); + if (scans == null) return; + for (DirectoryScannerConfig scan : scans) { + addDirectoryScanner(scan); + } + log.setConfig(bean.getInitialResultLogConfig()); + } finally { + sequencer.release(); + } + } + + // See ScanManagerMXBean + public void applyConfiguration(boolean fromMemory) + throws IOException, JMException { + if (fromMemory == false) config.load(); + applyConfiguration(config.getConfiguration()); + } + + // See ScanManagerMXBean + public void applyCurrentResultLogConfig(boolean toMemory) + throws IOException, JMException { + final ScanManagerConfig bean = config.getConfiguration(); + bean.setInitialResultLogConfig(log.getConfig()); + config.setConfiguration(bean); + if (toMemory==false) config.save(); + } + + // See ScanManagerMXBean + public void setConfigurationMBean(ScanDirConfigMXBean config) { + this.config = config; + } + + // See ScanManagerMXBean + public ScanDirConfigMXBean getConfigurationMBean() { + return config; + } + + // Creates and registers a new directory scanner. + // Called by applyConfiguration. + // throws IllegalStateException if state is not STOPPED or COMPLETED + // (you cannot change the config while scanning is scheduled or running). + // + private DirectoryScannerMXBean addDirectoryScanner( + DirectoryScannerConfig bean) + throws JMException { + try { + final DirectoryScannerMXBean scanner; + final ObjectName scanName; + synchronized (this) { + if (state != STOPPED && state != COMPLETED) + throw new IllegalStateException(state.toString()); + scanner = createDirectoryScanner(bean); + scanName = makeDirectoryScannerName(bean.getName()); + } + LOG.fine("server: "+mbeanServer); + LOG.fine("scanner: "+scanner); + LOG.fine("scanName: "+scanName); + final ObjectInstance moi = + mbeanServer.registerMBean(scanner,scanName); + final ObjectName moiName = moi.getObjectName(); + final DirectoryScannerMXBean proxy = + JMX.newMXBeanProxy(mbeanServer,moiName, + DirectoryScannerMXBean.class,true); + scanmap.put(moiName,proxy); + return proxy; + } catch (RuntimeException x) { + final String msg = "Operation failed: "+x; + if (LOG.isLoggable(Level.FINEST)) + LOG.log(Level.FINEST,msg,x); + else LOG.fine(msg); + throw x; + } catch (JMException x) { + final String msg = "Operation failed: "+x; + if (LOG.isLoggable(Level.FINEST)) + LOG.log(Level.FINEST,msg,x); + else LOG.fine(msg); + throw x; + } + } + + // See ScanManagerMXBean + public ScanDirConfigMXBean createOtherConfigurationMBean(String name, + String filename) + throws JMException { + final ScanDirConfig profile = new ScanDirConfig(filename); + final ObjectName profName = makeScanDirConfigName(name); + final ObjectInstance moi = mbeanServer.registerMBean(profile,profName); + final ScanDirConfigMXBean proxy = + JMX.newMXBeanProxy(mbeanServer,profName, + ScanDirConfigMXBean.class,true); + configmap.put(moi.getObjectName(),proxy); + return proxy; + } + + + // See ScanManagerMXBean + public Map<String,DirectoryScannerMXBean> getDirectoryScanners() { + final Map<String,DirectoryScannerMXBean> proxyMap = newHashMap(); + for (Entry<ObjectName,DirectoryScannerMXBean> item : scanmap.entrySet()){ + proxyMap.put(item.getKey().getKeyProperty("name"),item.getValue()); + } + return proxyMap; + } + + // --------------------------------------------------------------- + // State Management + // --------------------------------------------------------------- + + /** + * For each operation, this map stores a list of states from + * which the corresponding operation can be legally called. + * For instance, it is legal to call "stop" regardless of the + * application state. However, "schedule" can be called only if + * the application state is STOPPED, etc... + **/ + private final static Map<String,EnumSet<ScanState>> allowedStates; + static { + allowedStates = newHashMap(); + // You can always call stop + allowedStates.put("stop",EnumSet.allOf(ScanState.class)); + + // You can only call closed when stopped + allowedStates.put("close",EnumSet.of(STOPPED,COMPLETED,CLOSED)); + + // You can call schedule only when the current task is + // completed or stopped. + allowedStates.put("schedule",EnumSet.of(STOPPED,COMPLETED)); + + // switch reserved for background task: goes from SCHEDULED to + // RUNNING when it enters the run() method. + allowedStates.put("scan-running",EnumSet.of(SCHEDULED)); + + // switch reserved for background task: goes from RUNNING to + // SCHEDULED when it has completed but needs to reschedule + // itself for specified interval. + allowedStates.put("scan-scheduled",EnumSet.of(RUNNING)); + + // switch reserved for background task: + // goes from RUNNING to COMPLETED upon successful completion + allowedStates.put("scan-done",EnumSet.of(RUNNING)); + } + + // Get this object's state. No need to synchronize because + // state is volatile. + // See ScanManagerMXBean + public ScanState getState() { + return state; + } + + /** + * Enqueue a state changed notification for the given states. + **/ + private void queueStateChangedNotification( + long sequence, + long time, + ScanState old, + ScanState current) { + final AttributeChangeNotification n = + new AttributeChangeNotification(SCAN_MANAGER_NAME,sequence,time, + "ScanManager State changed to "+current,"State", + ScanState.class.getName(),old.toString(),current.toString()); + // Queue the notification. We have created an unlimited queue, so + // this method should always succeed. + try { + if (!pendingNotifs.offer(n,2,TimeUnit.SECONDS)) { + LOG.fine("Can't queue Notification: "+n); + } + } catch (InterruptedException x) { + LOG.fine("Can't queue Notification: "+x); + } + } + + /** + * Send all notifications present in the queue. + **/ + private void sendQueuedNotifications() { + Notification n; + while ((n = pendingNotifs.poll()) != null) { + broadcaster.sendNotification(n); + } + } + + /** + * Checks that the current state is allowed for the given operation, + * and if so, switch its value to the new desired state. + * This operation also enqueue the appropriate state changed + * notification. + **/ + private ScanState switchState(ScanState desired,String forOperation) { + return switchState(desired,allowedStates.get(forOperation)); + } + + /** + * Checks that the current state is one of the allowed states, + * and if so, switch its value to the new desired state. + * This operation also enqueue the appropriate state changed + * notification. + **/ + private ScanState switchState(ScanState desired,EnumSet<ScanState> allowed) { + final ScanState old; + final long timestamp; + final long sequence; + synchronized(this) { + old = state; + if (!allowed.contains(state)) + throw new IllegalStateException(state.toString()); + state = desired; + timestamp = System.currentTimeMillis(); + sequence = getNextSeqNumber(); + } + LOG.fine("switched state: "+old+" -> "+desired); + if (old != desired) + queueStateChangedNotification(sequence,timestamp,old,desired); + return old; + } + + + // --------------------------------------------------------------- + // schedule() creates a new SessionTask that will be executed later + // (possibly right away if delay=0) by a Timer thread. + // --------------------------------------------------------------- + + // The timer used by this object. Lazzy evaluation. Cleaned in + // postDeregister() + // + private Timer timer = null; + + // See ScanManagerMXBean + public void schedule(long delay, long interval) { + if (!sequencer.tryAcquire()) { + throw new IllegalStateException("Can't acquire lock"); + } + try { + LOG.fine("scheduling new task: state="+state); + final ScanState old = switchState(SCHEDULED,"schedule"); + final boolean scheduled = + scheduleSession(new SessionTask(interval),delay); + if (scheduled) + LOG.fine("new task scheduled: state="+state); + } finally { + sequencer.release(); + } + sendQueuedNotifications(); + } + + // Schedule a SessionTask. The session task may reschedule + // a new identical task when it eventually ends. + // We use this logic so that the 'interval' time is measured + // starting at the end of the task that finishes, rather than + // at its beginning. Therefore if a repeated task takes x ms, + // it will be repeated every x+interval ms. + // + private synchronized boolean scheduleSession(SessionTask task, long delay) { + if (state == STOPPED) return false; + if (timer == null) timer = new Timer("ScanManager"); + tasklist.add(task); + timer.schedule(task,delay); + return true; + } + + // --------------------------------------------------------------- + // start() is equivalent to schedule(0,0) + // --------------------------------------------------------------- + + // See ScanManagerMXBean + public void start() throws IOException, InstanceNotFoundException { + schedule(0,0); + } + + // --------------------------------------------------------------- + // Methods used to implement stop() - stop() is asynchronous, + // and needs to notify any running background task that it needs + // to stop. It also needs to prevent scheduled task from being + // run. + // --------------------------------------------------------------- + + // See ScanManagerMXBean + public void stop() { + if (!sequencer.tryAcquire()) + throw new IllegalStateException("Can't acquire lock"); + int errcount = 0; + final StringBuilder b = new StringBuilder(); + + try { + switchState(STOPPED,"stop"); + + errcount += cancelSessionTasks(b); + errcount += stopDirectoryScanners(b); + } finally { + sequencer.release(); + } + + sendQueuedNotifications(); + if (errcount > 0) { + b.insert(0,"stop partially failed with "+errcount+" error(s):"); + throw new RuntimeException(b.toString()); + } + } + + // See ScanManagerMXBean + public void close() { + switchState(CLOSED,"close"); + sendQueuedNotifications(); + } + + // Appends exception to a StringBuilder message. + // + private void append(StringBuilder b,String prefix,Throwable t) { + final String first = (prefix==null)?"\n":"\n"+prefix; + b.append(first).append(String.valueOf(t)); + Throwable cause = t; + while ((cause = cause.getCause())!=null) { + b.append(first).append("Caused by:").append(first); + b.append('\t').append(String.valueOf(cause)); + } + } + + // Cancels all scheduled session tasks + // + private int cancelSessionTasks(StringBuilder b) { + int errcount = 0; + // Stops scheduled tasks if any... + // + for (SessionTask task : tasklist) { + try { + task.cancel(); + tasklist.remove(task); + } catch (Exception ex) { + errcount++; + append(b,"\t",ex); + } + } + return errcount; + } + + // Stops all DirectoryScanners configured for this object. + // + private int stopDirectoryScanners(StringBuilder b) { + int errcount = 0; + // Stops directory scanners if any... + // + for (DirectoryScannerMXBean s : scanmap.values()) { + try { + s.stop(); + } catch (Exception ex) { + errcount++; + append(b,"\t",ex); + } + } + return errcount; + } + + + // --------------------------------------------------------------- + // We start scanning in background in a Timer thread. + // The methods below implement that logic. + // --------------------------------------------------------------- + + private void scanAllDirectories() + throws IOException, InstanceNotFoundException { + + int errcount = 0; + final StringBuilder b = new StringBuilder(); + for (ObjectName key : scanmap.keySet()) { + final DirectoryScannerMXBean s = scanmap.get(key); + try { + if (state == STOPPED) return; + s.scan(); + } catch (Exception ex) { + LOG.log(Level.FINE,key + " failed to scan: "+ex,ex); + errcount++; + append(b,"\t",ex); + } + } + if (errcount > 0) { + b.insert(0,"scan partially performed with "+errcount+" error(s):"); + throw new RuntimeException(b.toString()); + } + } + + // List of scheduled session task. Needed by stop() to cancel + // scheduled sessions. There's usually at most 1 session in + // this list (unless there's a bug somewhere ;-)) + // + private final ConcurrentLinkedQueue<SessionTask> tasklist = + new ConcurrentLinkedQueue<SessionTask>(); + + // Used to give a unique id to session task - useful for + // debugging. + // + private volatile static long taskcount = 0; + + /** + * A session task will be scheduled to run in background in a + * timer thread. There can be at most one session task running + * at a given time (this is ensured by using a timer - which is + * a single threaded object). + * + * If the session needs to be repeated, it will reschedule an + * identical session when it finishes to run. This ensure that + * two session runs are separated by the given interval time. + * + **/ + private class SessionTask extends TimerTask { + + /** + * Delay after which the next iteration of this task will + * start. This delay is measured starting at the end of + * the previous iteration. + **/ + final long delayBeforeNext; + + /** + * A unique id for this task. + **/ + final long taskid; + + /** + * Whether it's been cancelled by stop() + **/ + volatile boolean cancelled=false; + + /** + * create a new SessionTask. + **/ + SessionTask(long scheduleNext) { + delayBeforeNext = scheduleNext; + taskid = taskcount++; + } + + /** + * When run() begins, the state is switched to RUNNING. + * When run() ends then: + * If the task is repeated, the state will be switched + * to SCHEDULED (because a new task was scheduled). + * Otherwise the state will be switched to either + * STOPPED (if it was stopped before it could complete) + * or COMPLETED (if it completed gracefully) + * This method is used to switch to the desired state and + * send the appropriate notifications. + * When entering the method, we check whether the state is + * STOPPED. If so, we return false - and the SessionTask will + * stop. Otherwise, we switch the state to the desired value. + **/ + private boolean notifyStateChange(ScanState newState,String condition) { + synchronized (ScanManager.this) { + if (state == STOPPED || state == CLOSED) return false; + switchState(newState,condition); + } + sendQueuedNotifications(); + return true; + } + + // Cancels this task. + public boolean cancel() { + cancelled=true; + return super.cancel(); + } + + /** + * Invoke all directories scanners in sequence. At each + * step, checks to see whether the task should stop. + **/ + private boolean execute() { + final String tag = "Scheduled session["+taskid+"]"; + try { + if (cancelled) { + LOG.finer(tag+" cancelled: done"); + return false; + } + if (!notifyStateChange(RUNNING,"scan-running")) { + LOG.finer(tag+" stopped: done"); + return false; + } + scanAllDirectories(); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINEST)) { + LOG.log(Level.FINEST, + tag+" failed to scan: "+x,x); + } else if (LOG.isLoggable(Level.FINE)) { + LOG.fine(tag+" failed to scan: "+x); + } + } + return true; + } + + /** + * Schedule an identical task for next iteration. + **/ + private boolean scheduleNext() { + final String tag = "Scheduled session["+taskid+"]"; + + // We need now to reschedule a new task for after 'delayBeforeNext' ms. + try { + LOG.finer(tag+": scheduling next session for "+ delayBeforeNext + "ms"); + if (cancelled || !notifyStateChange(SCHEDULED,"scan-scheduled")) { + LOG.finer(tag+" stopped: do not reschedule"); + return false; + } + final SessionTask nextTask = new SessionTask(delayBeforeNext); + if (!scheduleSession(nextTask,delayBeforeNext)) return false; + LOG.finer(tag+": next session successfully scheduled"); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINEST)) { + LOG.log(Level.FINEST,tag+ + " failed to schedule next session: "+x,x); + } else if (LOG.isLoggable(Level.FINE)) { + LOG.fine(tag+" failed to schedule next session: "+x); + } + } + return true; + } + + + /** + * The run method: + * executes scanning logic, the schedule next iteration if needed. + **/ + public void run() { + final String tag = "Scheduled session["+taskid+"]"; + LOG.entering(SessionTask.class.getName(),"run"); + LOG.finer(tag+" starting..."); + try { + if (execute()==false) return; + + LOG.finer(tag+" terminating - state is "+state+ + ((delayBeforeNext >0)?(" next session is due in "+delayBeforeNext+" ms."): + " no additional session scheduled")); + + // if delayBeforeNext <= 0 we are done, either because the session was + // stopped or because it successfully completed. + if (delayBeforeNext <= 0) { + if (!notifyStateChange(COMPLETED,"scan-done")) + LOG.finer(tag+" stopped: done"); + else + LOG.finer(tag+" completed: done"); + return; + } + + // we need to reschedule a new session for 'delayBeforeNext' ms. + scheduleNext(); + + } finally { + tasklist.remove(this); + LOG.finer(tag+" finished..."); + LOG.exiting(SessionTask.class.getName(),"run"); + } + } + } + + // --------------------------------------------------------------- + // --------------------------------------------------------------- + + // --------------------------------------------------------------- + // MBean Notification support + // The methods below are imported from {@link NotificationEmitter} + // --------------------------------------------------------------- + + /** + * Delegates the implementation of this method to the wrapped + * {@code NotificationBroadcasterSupport} object. + **/ + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { + broadcaster.addNotificationListener(listener, filter, handback); + } + + + /** + * We emit an {@code AttributeChangeNotification} when the {@code State} + * attribute changes. + **/ + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + AttributeChangeNotification.class.getName(), + "Emitted when the State attribute changes") + }; + } + + /** + * Delegates the implementation of this method to the wrapped + * {@code NotificationBroadcasterSupport} object. + **/ + public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + /** + * Delegates the implementation of this method to the wrapped + * {@code NotificationBroadcasterSupport} object. + **/ + public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener, filter, handback); + } + + /** + * Returns and increment the sequence number used for + * notifications. We use the same sequence number throughout the + * application - this is why this method is only package protected. + * @return A unique sequence number for the next notification. + */ + static synchronized long getNextSeqNumber() { + return seqNumber++; + } + + // --------------------------------------------------------------- + // End of MBean Notification support + // --------------------------------------------------------------- + + // --------------------------------------------------------------- + // MBeanRegistration support + // The methods below are imported from {@link MBeanRegistration} + // --------------------------------------------------------------- + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. + * <p>In this implementation, we check that the provided name is + * either {@code null} or equals to {@link #SCAN_MANAGER_NAME}. If it + * isn't then we throw an IllegalArgumentException, otherwise we return + * {@link #SCAN_MANAGER_NAME}.</p> + * <p>This ensures that there will be a single instance of ScanManager + * registered in a given MBeanServer, and that it will always be + * registered with the singleton's {@link #SCAN_MANAGER_NAME}.</p> + * <p>We do not need to check whether an MBean by that name is + * already registered because the MBeanServer will perform + * this check just after having called preRegister().</p> + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. This name is null if the + * name parameter to one of the createMBean or registerMBean methods in + * the MBeanServer interface is null. In that case, this method must + * return a non-null ObjectName for the new MBean. + * @return The name under which the MBean is to be registered. This value + * must not be null. If the name parameter is not null, it will usually + * but not necessarily be the returned value. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { + if (name != null) { + if (!SCAN_MANAGER_NAME.equals(name)) + throw new IllegalArgumentException(String.valueOf(name)); + } + mbeanServer = server; + return SCAN_MANAGER_NAME; + } + + // Returns the default configuration filename + static String getDefaultConfigurationFileName() { + // This is a file calles 'jmx-scandir.xml' located + // in the user directory. + final String user = System.getProperty("user.home"); + final String defconf = user+File.separator+"jmx-scandir.xml"; + return defconf; + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * <p> + * If registration was not successful, the method returns immediately. + * <p> + * If registration is successful, register the {@link ResultLogManager} + * and default {@link ScanDirConfigMXBean}. If registering these + * MBean fails, the {@code ScanManager} state will be switched to + * {@link #close CLOSED}, and postRegister ends there. + * </p> + * <p>Otherwise the {@code ScanManager} will ask the + * {@link ScanDirConfigMXBean} to load its configuration. + * If it succeeds, the configuration will be {@link + * #applyConfiguration applied}. Otherwise, the method simply returns, + * assuming that the user will later create/update a configuration and + * apply it. + * @param registrationDone Indicates whether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + public void postRegister(Boolean registrationDone) { + if (!registrationDone) return; + Exception test=null; + try { + mbeanServer.registerMBean(log, + ResultLogManager.RESULT_LOG_MANAGER_NAME); + final String defconf = getDefaultConfigurationFileName(); + final String conf = System.getProperty("scandir.config.file",defconf); + final String confname = ScanDirConfig.guessConfigName(conf,defconf); + final ObjectName defaultProfileName = + makeMBeanName(ScanDirConfigMXBean.class,confname); + if (!mbeanServer.isRegistered(defaultProfileName)) + mbeanServer.registerMBean(new ScanDirConfig(conf), + defaultProfileName); + config = JMX.newMXBeanProxy(mbeanServer,defaultProfileName, + ScanDirConfigMXBean.class,true); + configmap.put(defaultProfileName,config); + } catch (Exception x) { + LOG.config("Failed to populate MBeanServer: "+x); + close(); + return; + } + try { + config.load(); + } catch (Exception x) { + LOG.finest("No config to load: "+x); + test = x; + } + if (test == null) { + try { + applyConfiguration(config.getConfiguration()); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINEST)) + LOG.log(Level.FINEST,"Failed to apply config: "+x,x); + LOG.config("Failed to apply config: "+x); + } + } + } + + // Unregisters all created DirectoryScanners + private void unregisterScanners() throws JMException { + unregisterMBeans(scanmap); + } + + // Unregisters all created ScanDirConfigs + private void unregisterConfigs() throws JMException { + unregisterMBeans(configmap); + } + + // Unregisters all MBeans named by the given map + private void unregisterMBeans(Map<ObjectName,?> map) throws JMException { + for (ObjectName key : map.keySet()) { + if (mbeanServer.isRegistered(key)) + mbeanServer.unregisterMBean(key); + map.remove(key); + } + } + + // Unregisters the ResultLogManager. + private void unregisterResultLogManager() throws JMException { + final ObjectName name = ResultLogManager.RESULT_LOG_MANAGER_NAME; + if (mbeanServer.isRegistered(name)) { + mbeanServer.unregisterMBean(name); + } + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * This implementation also unregisters all the MXBeans + * that were created by this object. + * @throws IllegalStateException if the lock can't be acquire, or if + * the MBean's state doesn't allow the MBean to be unregistered + * (e.g. because it's scheduled or running). + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public void preDeregister() throws Exception { + try { + close(); + if (!sequencer.tryAcquire()) + throw new IllegalStateException("can't acquire lock"); + try { + unregisterScanners(); + unregisterConfigs(); + unregisterResultLogManager(); + } finally { + sequencer.release(); + } + } catch (Exception x) { + LOG.log(Level.FINEST,"Failed to unregister: "+x,x); + throw x; + } + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + * Cancels the internal timer - if any. + */ + public synchronized void postDeregister() { + if (timer != null) { + try { + timer.cancel(); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINEST)) + LOG.log(Level.FINEST,"Failed to cancel timer",x); + else if (LOG.isLoggable(Level.FINE)) + LOG.fine("Failed to cancel timer: "+x); + } finally { + timer = null; + } + } + } + + // --------------------------------------------------------------- + // End of MBeanRegistration support + // --------------------------------------------------------------- + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManagerMXBean.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManagerMXBean.java new file mode 100644 index 0000000..1f6d4ff --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/ScanManagerMXBean.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import java.io.IOException; +import java.util.Map; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; + +/** + * The <code>ScanManagerMXBean</code> is responsible for applying a + * configuration, starting and scheduling directory scans, and reporting + * application state. + * <p> + * The <code>ScanManagerMXBean</code> is a singleton MBean: there can be + * at most one instance of such an MBean registered in a given MBeanServer. + * The name of that MBean is a constant defined in + * {@link ScanManager#SCAN_MANAGER_NAME ScanManager.SCAN_MANAGER_NAME}. + * </p> + * <p> + * The <code>ScanManagerMXBean</code> is the entry point of the <i>scandir</i> + * application management interface. It is from this MBean that all other + * MBeans will be created and registered. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + **/ +public interface ScanManagerMXBean { + /** + * This state tells whether directory scans are running, scheduled, + * successfully completed, or stopped. + * <p> + * The {@link #CLOSED} state means + * that the {@link ScanManagerMXBean} was closed and is no longer usable. + * This state is used when the {@link ScanManagerMXBean} needs to be + * unregistered. + * </p> + **/ + public enum ScanState { + /** + * Scanning of directories is in process. + **/ + RUNNING, + + /** + * Scanning of directories is not in process, but is scheduled + * for a later date. + **/ + SCHEDULED, + + /** + * Scanning is successfully completed. + **/ + COMPLETED, + + /** + * Scanning is stopped. No scanning is scheduled. + **/ + STOPPED, + + /** + * close() was called. + **/ + CLOSED + + } + + /** + * Returns the current state of the application. + * @return the current state of the application. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public ScanState getState() + throws IOException, InstanceNotFoundException; + + /** + * Schedule a scan session for a later date. + * <p> + * A scan session is a background task that will sequentially call {@link + * DirectoryScannerMXBean#scan scan()} on every {@link + * DirectoryScannerMXBean} configured for this MBean. + * </p> + * @see #getDirectoryScanners + * @param delay The first scan session will be started after + * the given delay. 0 means start now. + * @param interval Scan session will be rescheduled periodically + * at the specified interval. The interval starts at the + * the end of the scan session: if a scan session takes + * on average x milliseconds to complete, then a scan session will + * be started on average every x+interval milliseconds. + * if (interval == 0) then scan session will not be + * rescheduled, and will run only once. + * @throws IllegalStateException if a scan session is already + * running or scheduled, or the MBean is closed. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void schedule(long delay, long interval) + throws IOException, InstanceNotFoundException; + + + /** + * Stops current running or scheduled scan sessions if any. + * <p> + * A scan session is a background task that will sequentially call {@link + * DirectoryScannerMXBean#scan scan()} on every {@link + * DirectoryScannerMXBean} configured for this MBean. + * </p> + * <p> + * Scan sessions are started/scheduled by calls to {@link #start start} or + * {@link #schedule schedule}. + * </p> + * After this method completes the state of the application will + * be {@link ScanState#STOPPED}. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void stop() + throws IOException, InstanceNotFoundException; + + /** + * Switches the state to CLOSED. + * When closed, this MBean cannot be used any more. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void close() + throws IOException, InstanceNotFoundException; + + /** + * Starts a scan session immediately. + * This is equivalent to {@link #schedule(long,long) schedule(0,0)}. + * @throws IllegalStateException if a scan session is already + * running or scheduled, or the MBean is closed. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public void start() + throws IOException, InstanceNotFoundException; + + /** + * Gets the list of directory scanners configured for this MBean. + * @return A {@code Map<String,DirectoryScannerMXBean>} where the + * key in the map is the value of the <code>name=</code> key + * of the {@link DirectoryScannerMXBean} ObjectName. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws JMException The MBeanServer failed to call the underlying MBean. + **/ + public Map<String,DirectoryScannerMXBean> getDirectoryScanners() + throws IOException, JMException; + + /** + * Apply the configuration handled by the {@link + * #getConfigurationMBean configuration MBean}. + * <p> + * When the configuration is applied, all the {@link DirectoryScannerMXBean} + * created by this MBean will be unregistered, and new {@link + * DirectoryScannerMXBean} will be created and registered from the + * new {@link ScanDirConfigMXBean#getConfiguration configuration data}. + * </p> + * <p> + * The initial result log configuration held by the {@link + * #getConfigurationMBean configuration MBean} will also be pushed to the + * {@link ResultLogManagerMXBean}. If you don't want to lose your current + * {@link ResultLogManagerMXBean} configuration, you should therefore call + * {@link #applyCurrentResultLogConfig + * applyCurrentResultLogConfig} before calling + * {@link #applyConfiguration applyConfiguration} + * </p> + * @param fromMemory if {@code true}, the configuration will be applied + * from memory. if {@code false}, the {@code ScanManagerMXBean} will + * ask the {@link + * #getConfigurationMBean configuration MBean} to {@link + * ScanDirConfigMXBean#load reload its configuration} before applying + * it. + * @throws IllegalStateException if a scan session is + * running or scheduled, or the MBean is closed. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws JMException The MBeanServer failed to call the underlying MBean. + **/ + public void applyConfiguration(boolean fromMemory) + throws IOException, JMException; + /** + * Replaces the {@link + * #getConfigurationMBean configuration MBean}'s {@link + * com.sun.jmx.examples.scandir.config.ScanManagerConfig#getInitialResultLogConfig + * initial result log configuration} with the current {@link + * ResultLogManagerMXBean} + * configuration. This prevents the <code>ResultLogManagerMXBean</code> + * current configuration from being reset when {@link #applyConfiguration + * applyConfiguration} is called. + * @param toMemory if {@code true} only replaces the initial result log + * configuration held in memory. + * if {@code false}, the {@link + * #getConfigurationMBean configuration MBean} will be asked to commit + * the whole configuration to the configuration file. + * + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws JMException The MBeanServer failed to call the underlying MBean. + **/ + public void applyCurrentResultLogConfig(boolean toMemory) + throws IOException, JMException; + + /** + * Instruct the {@code ScanManagerMXBean} to use another {@link + * ScanDirConfigMXBean configuration MBean}. + * <p>This method doesn't {@link #applyConfiguration apply} the new + * configuration. If you want to apply the new configuration, you should + * additionally call {@link #applyConfiguration + * applyConfiguration(true|false)}. Note that you cannot apply a + * configuration as long as a scan session is scheduled or running. + * In that case you will need to wait for that session to complete + * or call {@link #stop} to stop it. + * </p> + * @param config A proxy to the {@link ScanDirConfigMXBean} that holds + * the new configuration for the application. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + */ + public void setConfigurationMBean(ScanDirConfigMXBean config) + throws IOException, InstanceNotFoundException; + /** + * Gets the current configuration MBean. + * @return A proxy to the current configuration MBean. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws InstanceNotFoundException The underlying MBean is not + * registered in the MBeanServer. + **/ + public ScanDirConfigMXBean getConfigurationMBean() + throws IOException, InstanceNotFoundException; + /** + * This method creates a new alternate {@link ScanDirConfigMXBean}. + * + * <p>You will need to call {@link #setConfigurationMBean + * setConfigurationMBean} if you + * want this new {@link ScanDirConfigMXBean} to become the + * current configuration MBean. + * </p> + * <p> + * This new {@link ScanDirConfigMXBean} will be unregistered automatically + * by the {@code ScanManagerMXBean} when the {@code ScanManagerMXBean} + * is unregistered. + * </p> + * @param name The short name for the new {@link ScanDirConfigMXBean}. + * This name will be used in the ObjectName <code>name=</code> key + * of the new {@link ScanDirConfigMXBean}. + * @param filename The path of the file from which the new {@link + * ScanDirConfigMXBean} can {@link ScanDirConfigMXBean#load load} or + * {@link ScanDirConfigMXBean#save save} its configuration data. + * Note that even if the file exists and contain a valid + * configuration, you will still need to call {@link + * ScanDirConfigMXBean#load load} to make the {@link + * ScanDirConfigMXBean} load its configuration data. + * @throws IOException A connection problem occurred when accessing + * the underlying resource. + * @throws JMException The MBeanServer failed to call the underlying MBean. + * @return A proxy to the created {@link ScanDirConfigMXBean}. + */ + public ScanDirConfigMXBean createOtherConfigurationMBean(String name, + String filename) + throws JMException, IOException; +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/DirectoryScannerConfig.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/DirectoryScannerConfig.java new file mode 100644 index 0000000..b3f8e9f --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/DirectoryScannerConfig.java @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlList; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * The <code>DirectoryScannerConfig</code> Java Bean is used to model + * the configuration of a {@link + * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}. + * <p> + * This class is annotated for XML binding. + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + */ +@XmlRootElement(name="DirectoryScanner", + namespace=XmlConfigUtils.NAMESPACE) +public class DirectoryScannerConfig { + + // + // A logger for this class. + // + // private static final Logger LOG = + // Logger.getLogger(DirectoryScannerConfig.class.getName()); + + /** + * This enumeration is used to model the actions that a {@link + * com.sun.jmx.examples.scandir.DirectoryScannerMXBean + * DirectoryScannerMXBean} should take when a file matches its set + * of matching criteria. + **/ + public enum Action { + /** + * Indicates that the {@code DirectoryScannerMXBean} should + * emit a {@code Notification} when a matching file is found. + */ + NOTIFY, + /** + * Indicates that the {@code DirectoryScannerMXBean} should + * delete the matching files. + */ + DELETE, + /** + * Indicates that the {@code DirectoryScannerMXBean} should + * log the actions that were taken on the matching files. + */ + LOGRESULT }; + + // A short name for the Directory Scanner + // This name is used for the value of the {@code name=} key in the + // {@code DirectoryScannerMXBean} ObjectName. + private String name; + + // The root directory of the Directory Scanner + private String rootDirectory; + + // List of filters identifying files that should be selected. + // A file is selected if at least one filter matches. + // + private final List<FileMatch> includeFiles = + new ArrayList<FileMatch>(); + + // List of filters identifying files that should be excluded. + // A file is excluded if at least one filter matches. + // + private final List<FileMatch> excludeFiles = + new ArrayList<FileMatch>(); + + + // The actions that this Directory Scanner should carry out when a + // file is selected. Default is NOTIFY and LOGRESULT. + // + private Action[] actions = { Action.NOTIFY, Action.LOGRESULT }; + + /** + * Creates a new instance of {@code DirectoryScannerConfig}. + * We keep this empty constructor to make XML binding easier. + * You shouldn't use this constructor directly: + * use {@link #DirectoryScannerConfig(String) + * DirectoryScannerConfig(String name)} instead. + * @deprecated <p>Tagged deprecated so that a compiler warning is issued. + * Use {@link #DirectoryScannerConfig(String) + * DirectoryScannerConfig(String name)} instead. + * </p> + **/ + public DirectoryScannerConfig() { + this(null); + } + + /** + * Creates a new instance of {@code DirectoryScannerConfig}. + * @param name A short name for the Directory Scanner. This name is used for + * the value of the {@code name=} key in the + * {@code DirectoryScannerMXBean} ObjectName. + **/ + public DirectoryScannerConfig(String name) { + this.name = name; + rootDirectory = null; + } + + /** + * Gets the root directory configured for that Directory Scanner. + * @return the root directory at which the directory scanner should start + * scanning. + **/ + @XmlElement(name="RootDirectory",namespace=XmlConfigUtils.NAMESPACE) + public String getRootDirectory() { + return rootDirectory; + } + + /** + * Configures a root directory for that Directory Scanner. + * @param root The root directory at which the directory scanner should + * start scanning. + **/ + public void setRootDirectory(String root) { + rootDirectory=root; + } + + + /** + * Gets the short name of this directory scanner. + * + * <p> + * This name is used for the value of the {@code name=} key in the + * {@code DirectoryScannerMXBean} ObjectName. + * </p> + * + * @return the short name of this directory scanner. + **/ + @XmlAttribute(name="name",required=true) + public String getName() { + return this.name; + } + + /** + * Setter for property {@link #getName() name}. + * Once set its value cannot change. + * @param name New value of property name. + * @throws IllegalArgumentException if {@code name} is already set to a + * different non null value. + */ + public void setName(String name) { + if (this.name == null) + this.name = name; + else if (name == null) + throw new IllegalArgumentException("name=null"); + else if (!name.equals(this.name)) + throw new IllegalArgumentException("name="+name); + } + + /** + * Getter for property includeFiles. + * This is an array of filters identifying files that should be selected. + * A file is selected if at least one filter matches. + * @return Value of property includeFiles. + */ + @XmlElementWrapper(name="IncludeFiles", + namespace=XmlConfigUtils.NAMESPACE) + @XmlElementRef + public FileMatch[] getIncludeFiles() { + synchronized(includeFiles) { + return includeFiles.toArray(new FileMatch[0]); + } + } + + /** + * Adds a filter to the includeFiles property. + * A file is selected if at least one filter matches. + * @param include A filter identifying files that should be selected. + */ + public void addIncludeFiles(FileMatch include) { + if (include == null) + throw new IllegalArgumentException("null"); + synchronized (includeFiles) { + includeFiles.add(include); + } + } + + /** + * Setter for property includeFiles. + * @param includeFiles New value of property includeFiles. + * This is an array of filters identifying files + * that should be selected. A file is selected if at least + * one filter matches. + */ + public void setIncludeFiles(FileMatch[] includeFiles) { + synchronized (this.includeFiles) { + this.includeFiles.clear(); + if (includeFiles == null) return; + this.includeFiles.addAll(Arrays.asList(includeFiles)); + } + } + + /** + * Getter for property excludeFiles. + * This is an array of filters identifying files that should be excluded. + * A file is excluded if at least one filter matches. + * @return Value of property excludeFiles. + */ + @XmlElementWrapper(name="ExcludeFiles", + namespace=XmlConfigUtils.NAMESPACE) + @XmlElementRef + public FileMatch[] getExcludeFiles() { + synchronized(excludeFiles) { + return excludeFiles.toArray(new FileMatch[0]); + } + } + + /** + * Setter for property excludeFiles. + * @param excludeFiles New value of property excludeFiles. + * This is an array of filters identifying files + * that should be excluded. A file is excluded if at least + * one filter matches. + */ + public void setExcludeFiles(FileMatch[] excludeFiles) { + synchronized (this.excludeFiles) { + this.excludeFiles.clear(); + if (excludeFiles == null) return; + this.excludeFiles.addAll(Arrays.asList(excludeFiles)); + } + } + + /** + * Adds a filter to the excludeFiles property. + * A file is excluded if at least one filter matches. + * @param exclude A filter identifying files that should be excluded. + */ + public void addExcludeFiles(FileMatch exclude) { + if (exclude == null) + throw new IllegalArgumentException("null"); + synchronized (excludeFiles) { + this.excludeFiles.add(exclude); + } + } + + /** + * Gets the list of actions that this Directory Scanner should carry + * out when a file is selected. Default is NOTIFY and LOGRESULT. + + * @return The list of actions that this Directory Scanner should carry + * out when a file is selected. + */ + @XmlElement(name="Actions",namespace=XmlConfigUtils.NAMESPACE) + @XmlList + public Action[] getActions() { + return (actions == null)?null:actions.clone(); + } + + /** + * Sets the list of actions that this Directory Scanner should carry + * out when a file is selected. Default is NOTIFY and LOGRESULT. + + * @param actions The list of actions that this Directory Scanner should + * carry out when a file is selected. + */ + public void setActions(Action[] actions) { + this.actions = (actions == null)?null:actions.clone(); + } + + /** + * Builds a {@code FileFilter} from the {@link #getIncludeFiles + * includeFiles} and {@link #getExcludeFiles excludeFiles} lists. + * A file will be accepted if it is selected by at least one of + * the filters in {@link #getIncludeFiles includeFiles}, and is + * not excluded by any of the filters in {@link + * #getExcludeFiles excludeFiles}. If there's no filter in + * {@link #getIncludeFiles includeFiles}, then a file is accepted + * simply if it is not excluded by any of the filters in {@link + * #getExcludeFiles excludeFiles}. + * + * @return A new {@code FileFilter} created from the current snapshot + * of the {@link #getIncludeFiles + * includeFiles} and {@link #getExcludeFiles excludeFiles} lists. + * Later modification of these lists will not affect the + * returned {@code FileFilter}. + **/ + public FileFilter buildFileFilter() { + final FileFilter[] ins = getIncludeFiles(); + final FileFilter[] outs = getExcludeFiles(); + final FileFilter filter = new FileFilter() { + public boolean accept(File f) { + boolean result = false; + // If no include filter, all files are included. + if (ins != null) { + for (FileFilter in: ins) { + // if one filter accepts it, file is included + if (!in.accept(f)) continue; + + // file is accepted, include it + result=true; + break; + } + } else result= true; + if (result == false) return false; + + // The file is in the include list. Let's see if it's not + // in the exclude list... + // + if (outs != null) { + for (FileFilter out: outs) { + // if one filter accepts it, file is excluded + if (!out.accept(f)) continue; + + // file is accepted, exclude it. + result=false; + break; + } + } + return result; + } + }; + return filter; + } + + // Used for equality - see equals(). + private Object[] toArray() { + final Object[] thisconfig = { + name,rootDirectory,actions,excludeFiles,includeFiles + }; + return thisconfig; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof DirectoryScannerConfig)) return false; + final DirectoryScannerConfig other = (DirectoryScannerConfig)o; + final Object[] thisconfig = toArray(); + final Object[] otherconfig = other.toArray(); + return Arrays.deepEquals(thisconfig,otherconfig); + } + + @Override + public int hashCode() { + final String key = name; + if (key == null) return 0; + else return key.hashCode(); + } + + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/FileMatch.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/FileMatch.java new file mode 100644 index 0000000..31f44ce --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/FileMatch.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import java.io.File; +import java.io.FileFilter; +import java.util.Arrays; +import java.util.Date; +import java.util.logging.Logger; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * The <code>FileMatch</code> Java Bean is used to model + * the configuration of a {@link FileFilter} which + * matches {@link File files} against a set of criteria. + * <p> + * The <code>FileMatch</code> class also implements + * {@link FileFilter} - applying an {@code AND} on all + * its conditions. {@code OR} conditions can be obtained + * by supplying several instances of <code>FileMatch</code> + * to the encapsulating {@link DirectoryScannerConfig}, which + * respectively applies an {@code OR} on all its + * {@code <FileFilter>} elements. + * </p> + * + * <p> + * This class is annotated for XML binding. + * </p> + * @author Sun Microsystems, 2006 - All rights reserved. + */ +@XmlRootElement(name="FileFilter", + namespace=XmlConfigUtils.NAMESPACE) +public class FileMatch implements FileFilter { + + // + // A logger for this class. + // + // private static final Logger LOG = + // Logger.getLogger(FileMatch.class.getName()); + + /** + * A regular expression against which directory names should be matched. + */ + private String directoryPattern; + + /** + * A regular expression against which file names should be matched. + */ + private String filePattern; + + /** + * File whose size in bytes exceeds this limit will be selected. + */ + private long sizeExceedsMaxBytes; + + /** + * A file which will be selected only if it was last modified after + * this date + */ + private Date lastModifiedAfter; + + /** + * A file which will be selected only if it was last modified before + * this date + */ + private Date lastModifiedBefore; + + /** + * Creates a new instance of FileMatch + */ + public FileMatch() { + } + + /** + * Getter for property directoryPattern. This is a regular expression + * against which directory names should be matched. + * Applies only to directory, and tells whether a directory should be + * included or excluded from the search. + * <p>If File.isDirectory() && directoryPattern!=null && + * File.getName().matches(directoryPattern), + * then File matches this filter.<br> + * If File.isDirectory() && directoryPattern!=null && + * File.getName().matches(directoryPattern)==false, + * then File doesn't match this filter.<br> + * </p> + * @see java.util.regex.Pattern + * @see java.lang.String#matches(java.lang.String) + * @return Value of property directoryPattern. + */ + @XmlElement(name="DirectoryPattern",namespace=XmlConfigUtils.NAMESPACE) + public String getDirectoryPattern() { + return this.directoryPattern; + } + + /** + * Setter for property directoryPattern. + * @param directoryPattern New value of property directoryPattern. + * This is a regular expression + * against which directory names should be {@link #getDirectoryPattern + * matched}. + * @see java.util.regex.Pattern + * @see java.lang.String#matches(java.lang.String) + */ + public void setDirectoryPattern(String directoryPattern) { + this.directoryPattern = directoryPattern; + } + + /** + * Getter for property filePattern. This is a regular expression + * against which file names should be matched. + * Applies only to files. + * <p> + * If File.isDirectory()==false && filePattern!=null && + * File.getName().matches(filePattern)==false, + * then File doesn't match this filter. + * </p> + * @see java.util.regex.Pattern + * @see java.lang.String#matches(java.lang.String) + * @return Value of property filePatern. + */ + @XmlElement(name="FilePattern",namespace=XmlConfigUtils.NAMESPACE) + public String getFilePattern() { + return this.filePattern; + } + + /** + * Setter for property filePattern. + * @param filePattern New value of property filePattern. + * This is a regular expression + * against which file names should be {@link #getFilePattern matched}. + * @see java.util.regex.Pattern + * @see java.lang.String#matches(java.lang.String) + */ + public void setFilePattern(String filePattern) { + this.filePattern = filePattern; + } + + /** + * Getter for property sizeExceedsMaxBytes. + * Ignored if 0 or negative. Otherwise, files whose size in bytes does + * not exceed this limit will be excluded by this filter. + * + * @return Value of property sizeExceedsMaxBytes. + */ + @XmlElement(name="SizeExceedsMaxBytes",namespace=XmlConfigUtils.NAMESPACE) + public long getSizeExceedsMaxBytes() { + return this.sizeExceedsMaxBytes; + } + + /** + * Setter for property sizeExceedsMaxBytes. + * @param sizeLimitInBytes New value of property sizeExceedsMaxBytes. + * Ignored if 0 or negative. Otherwise, files whose size in bytes does + * not exceed this limit will be excluded by this filter. + * + */ + public void setSizeExceedsMaxBytes(long sizeLimitInBytes) { + this.sizeExceedsMaxBytes = sizeLimitInBytes; + } + + /** + * Getter for property {@code lastModifiedAfter}. + * A file will be selected only if it was last modified after + * {@code lastModifiedAfter}. + * <br>This condition is ignored if {@code lastModifiedAfter} is + * {@code null}. + * @return Value of property {@code lastModifiedAfter}. + */ + @XmlElement(name="LastModifiedAfter",namespace=XmlConfigUtils.NAMESPACE) + public Date getLastModifiedAfter() { + return (lastModifiedAfter==null)?null:(Date)lastModifiedAfter.clone(); + } + + /** + * Setter for property {@code lastModifiedAfter}. + * @param lastModifiedAfter A file will be selected only if it was + * last modified after {@code lastModifiedAfter}. + * <br>This condition is ignored if {@code lastModifiedAfter} is + * {@code null}. + */ + public void setLastModifiedAfter(Date lastModifiedAfter) { + this.lastModifiedAfter = + (lastModifiedAfter==null)?null:(Date)lastModifiedAfter.clone(); + } + + /** + * Getter for property {@code lastModifiedBefore}. + * A file will be selected only if it was last modified before + * {@code lastModifiedBefore}. + * <br>This condition is ignored if {@code lastModifiedBefore} is + * {@code null}. + * @return Value of property {@code lastModifiedBefore}. + */ + @XmlElement(name="LastModifiedBefore",namespace=XmlConfigUtils.NAMESPACE) + public Date getLastModifiedBefore() { + return (lastModifiedBefore==null)?null:(Date)lastModifiedBefore.clone(); + } + + /** + * Setter for property {@code lastModifiedBefore}. + * @param lastModifiedBefore A file will be selected only if it was + * last modified before {@code lastModifiedBefore}. + * <br>This condition is ignored if {@code lastModifiedBefore} is + * {@code null}. + */ + public void setLastModifiedBefore(Date lastModifiedBefore) { + this.lastModifiedBefore = + (lastModifiedBefore==null)?null:(Date)lastModifiedBefore.clone(); + } + + // Accepts or rejects a file with regards to the values of the fields + // configured in this bean. The accept() method is the implementation + // of FileFilter.accept(File); + // + /** + * A file is accepted when all the criteria that have been set + * are matched. + * @param f The file to match against the configured criteria. + * @return {@code true} if the file matches all criteria, + * {@code false} otherwise. + */ + public boolean accept(File f) { + + // Directories are accepted if they match against the directory pattern. + // + if (f.isDirectory()) { + if (directoryPattern != null + && !f.getName().matches(directoryPattern)) + return false; + else return true; + } + + // If we reach here, the f is not a directory. + // + // Files are accepted if they match all other conditions. + + // Check whether f matches filePattern + if (filePattern != null + && !f.getName().matches(filePattern)) + return false; + + // Check whether f exceeeds size limit + if (sizeExceedsMaxBytes > 0 && f.length() <= sizeExceedsMaxBytes) + return false; + + // Check whether f was last modified after lastModifiedAfter + if (lastModifiedAfter != null && + lastModifiedAfter.after(new Date(f.lastModified()))) + return false; + + // Check whether f was last modified before lastModifiedBefore + if (lastModifiedBefore != null && + lastModifiedBefore.before(new Date(f.lastModified()))) + return false; + + // All conditions were met: accept file. + return true; + } + + // used by equals() + private Object[] toArray() { + final Object[] thisconfig = { + directoryPattern, filePattern, lastModifiedAfter, + lastModifiedBefore, sizeExceedsMaxBytes + }; + return thisconfig; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof FileMatch)) return false; + final FileMatch other = (FileMatch)o; + final Object[] thisconfig = toArray(); + final Object[] otherconfig = other.toArray(); + return Arrays.deepEquals(thisconfig,otherconfig); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultLogConfig.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultLogConfig.java new file mode 100644 index 0000000..5f3d668 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultLogConfig.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import java.util.Arrays; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * The <code>ResultLogConfig</code> Java Bean is used to model + * the initial configuration of the {@link + * com.sun.jmx.examples.scandir.ResultLogManagerMXBean}. + * + * <p> + * This class is annotated for XML binding. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +@XmlRootElement(name="ResultLogConfig", + namespace=XmlConfigUtils.NAMESPACE) +public class ResultLogConfig { + + // + // A logger for this class. + // + // private static final Logger LOG = + // Logger.getLogger(ResultLogConfig.class.getName()); + + /** + * The path to the result log file. {@code null} means that logging to + * file is disabled. + */ + private String logFileName; + + /** + * Maximum number of record that will be logged in the log file before + * switching to a new log file. + */ + private long logFileMaxRecords; + + /** + * The maximum number of records that can be contained in the memory log. + * When this number is reached, the memory log drops its eldest record + * to make way for the new one. + */ + private int memoryMaxRecords; + + /** + * Creates a new instance of ResultLogConfig + */ + public ResultLogConfig() { + } + + /** + * Gets the path to the result log file. {@code null} means that logging to + * file is disabled. + * @return the path to the result log file. + */ + @XmlElement(name="LogFileName",namespace=XmlConfigUtils.NAMESPACE) + public String getLogFileName() { + return this.logFileName; + } + + /** + * Sets the path to the result log file. {@code null} means that + * logging to file is disabled. + * @param logFileName the path to the result log file. + */ + public void setLogFileName(String logFileName) { + this.logFileName = logFileName; + } + + /** + * Gets the maximum number of record that will be logged in the log file + * before switching to a new log file. + * A 0 or negative value means no limit. + * @return the maximum number of record that will be logged in the log file. + */ + @XmlElement(name="LogFileMaxRecords",namespace=XmlConfigUtils.NAMESPACE) + public long getLogFileMaxRecords() { + return this.logFileMaxRecords; + } + + /** + * Sets the maximum number of record that will be logged in the log file + * before switching to a new log file. + * A 0 or negative value means no limit. + * @param logFileMaxRecords the maximum number of record that will be + * logged in the log file. + */ + public void setLogFileMaxRecords(long logFileMaxRecords) { + this.logFileMaxRecords = logFileMaxRecords; + } + + /** + * Gets the maximum number of records that can be contained in the memory + * log. + * When this number is reached, the memory log drops its eldest record + * to make way for the new one. + * @return the maximum number of records that can be contained in the + * memory log. + */ + @XmlElement(name="MemoryMaxRecords",namespace=XmlConfigUtils.NAMESPACE) + public int getMemoryMaxRecords() { + return this.memoryMaxRecords; + } + + /** + * Sets the maximum number of records that can be contained in the memory + * log. + * When this number is reached, the memory log drops its eldest record + * to make way for the new one. + * @param memoryMaxRecords the maximum number of records that can be + * contained in the memory log. + */ + public void setMemoryMaxRecords(int memoryMaxRecords) { + this.memoryMaxRecords = memoryMaxRecords; + } + + private Object[] toArray() { + final Object[] thisconfig = { + memoryMaxRecords,logFileMaxRecords,logFileName + }; + return thisconfig; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof ResultLogConfig)) return false; + final ResultLogConfig other = (ResultLogConfig)o; + return Arrays.deepEquals(toArray(),other.toArray()); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultRecord.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultRecord.java new file mode 100644 index 0000000..5e3188a --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ResultRecord.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import java.util.Date; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlList; +import javax.xml.bind.annotation.XmlRootElement; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig.Action; +import java.io.File; +import java.util.Arrays; + +/** + * The <code>ResultRecord</code> Java Bean is used to write the + * results of a directory scan to a result log. + * + * <p> + * This class is annotated for XML binding. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +@XmlRootElement(name="ResultRecord",namespace=XmlConfigUtils.NAMESPACE) +public class ResultRecord { + + /** + * The name of the file for which this result record is built. + */ + private String filename; + + /** + * The Date at which this result was obtained. + */ + private Date date; + + /** + * The short name of the directory scanner which performed the operation. + * @see DirectoryScannerConfig#getName() + */ + private String directoryScanner; + + /** + * The list of actions that were successfully carried out. + */ + private Action[] actions; + + /** + * Creates a new empty instance of ResultRecord. + */ + public ResultRecord() { + } + + /** + * Creates a new instance of ResultRecord. + * @param scan The DirectoryScannerConfig for which this result was + * obtained. + * @param actions The list of actions that were successfully carried out. + * @param f The file for which these actions were successfully carried out. + */ + public ResultRecord(DirectoryScannerConfig scan, Action[] actions, + File f) { + directoryScanner = scan.getName(); + this.actions = actions; + date = new Date(); + filename = f.getAbsolutePath(); + } + + /** + * Gets the name of the file for which this result record is built. + * @return The name of the file for which this result record is built. + */ + @XmlElement(name="Filename",namespace=XmlConfigUtils.NAMESPACE) + public String getFilename() { + return this.filename; + } + + /** + * Sets the name of the file for which this result record is being built. + * @param filename the name of the file for which this result record is + * being built. + */ + public void setFilename(String filename) { + this.filename = filename; + } + + /** + * Gets the Date at which this result was obtained. + * @return the Date at which this result was obtained. + */ + @XmlElement(name="Date",namespace=XmlConfigUtils.NAMESPACE) + public Date getDate() { + synchronized(this) { + return (date==null)?null:(new Date(date.getTime())); + } + } + + /** + * Sets the Date at which this result was obtained. + * @param date the Date at which this result was obtained. + */ + public void setDate(Date date) { + synchronized (this) { + this.date = (date==null)?null:(new Date(date.getTime())); + } + } + + /** + * Gets the short name of the directory scanner which performed the + * operation. + * @see DirectoryScannerConfig#getName() + * @return the short name of the directory scanner which performed the + * operation. + */ + @XmlElement(name="DirectoryScanner",namespace=XmlConfigUtils.NAMESPACE) + public String getDirectoryScanner() { + return this.directoryScanner; + } + + /** + * Sets the short name of the directory scanner which performed the + * operation. + * @see DirectoryScannerConfig#getName() + * @param directoryScanner the short name of the directory scanner which + * performed the operation. + */ + public void setDirectoryScanner(String directoryScanner) { + this.directoryScanner = directoryScanner; + } + + /** + * Gets the list of actions that were successfully carried out. + * @return the list of actions that were successfully carried out. + */ + @XmlElement(name="Actions",namespace=XmlConfigUtils.NAMESPACE) + @XmlList + public Action[] getActions() { + return (actions == null)?null:actions.clone(); + } + + /** + * Sets the list of actions that were successfully carried out. + * @param actions the list of actions that were successfully carried out. + */ + public void setActions(Action[] actions) { + this.actions = (actions == null)?null:actions.clone(); + } + + // Used for equality + private Object[] toArray() { + final Object[] thisconfig = { + filename, date, directoryScanner, actions + }; + return thisconfig; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ResultRecord)) return false; + return Arrays.deepEquals(toArray(),((ResultRecord)o).toArray()); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ScanManagerConfig.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ScanManagerConfig.java new file mode 100644 index 0000000..e1afcce --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/ScanManagerConfig.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + + +/** + * The <code>ScanManagerConfig</code> Java Bean is used to model + * the configuration of the {@link + * com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean}. + * + * The {@link + * com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean} will + * use this configuration to initialize the {@link + * com.sun.jmx.examples.scandir.ResultLogManagerMXBean ResultLogManagerMXBean} + * and create the {@link + * com.sun.jmx.examples.scandir.DirectoryScannerMXBean DirectoryScannerMXBeans} + * <p> + * This class is annotated for XML binding. + * </p> + * + * @author Sun Microsystems, 2006 - All rights reserved. + **/ +@XmlRootElement(name="ScanManager", + namespace="jmx:com.sun.jmx.examples.scandir.config") +public class ScanManagerConfig { + + // A logger for this class + // + // private static final Logger LOG = + // Logger.getLogger(ScanManagerConfig.class.getName()); + + /** + * A set of DirectoryScannerConfig objects indexed by their names. + **/ + private final Map<String, DirectoryScannerConfig> directoryScanners; + + /** + * The initial Result Log configuration. + */ + private ResultLogConfig initialResultLogConfig; + + /** + * Holds value of property name. The name of the configuration + * usually corresponds to + * the value of the {@code name=} key of the {@code ObjectName} + * of the {@link + * com.sun.jmx.examples.scandir.ScanDirConfigMXBean + * ScanDirConfigMXBean} which owns this configuration. + **/ + private String name; + + /** + * Creates a new instance of ScanManagerConfig. + * <p>You should not use this constructor directly, but use + * {@link #ScanManagerConfig(String)} instead. + * </p> + * <p>This constructor is tagged deprecated so that the compiler + * will generate a warning if it is used by mistake. + * </p> + * @deprecated Use {@link #ScanManagerConfig(String)} instead. This + * constructor is used through reflection by the XML + * binding framework. + */ + public ScanManagerConfig() { + this(null,true); + } + + /** + * Creates a new instance of ScanManagerConfig. + * @param name The name of the configuration which usually corresponds to + * the value of the {@code name=} key of the {@code ObjectName} + * of the {@link + * com.sun.jmx.examples.scandir.ScanDirConfigMXBean + * ScanDirConfigMXBean} which owns this configuration. + **/ + public ScanManagerConfig(String name) { + this(name,false); + } + + // Our private constructor... + private ScanManagerConfig(String name, boolean allowsNull) { + if (name == null && allowsNull==false) + throw new IllegalArgumentException("name=null"); + this.name = name; + directoryScanners = new LinkedHashMap<String,DirectoryScannerConfig>(); + this.initialResultLogConfig = new ResultLogConfig(); + this.initialResultLogConfig.setMemoryMaxRecords(1024); + } + + // Creates an array for deep equality. + private Object[] toArray() { + final Object[] thisconfig = { + name,directoryScanners,initialResultLogConfig + }; + return thisconfig; + } + + // equals + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof ScanManagerConfig)) return false; + final ScanManagerConfig other = (ScanManagerConfig)o; + if (this.directoryScanners.size() != other.directoryScanners.size()) + return false; + return Arrays.deepEquals(toArray(),other.toArray()); + } + + @Override + public int hashCode() { + final String key = name; + if (key == null) return 0; + else return key.hashCode(); + } + + /** + * Gets the name of this configuration. The name of the configuration + * usually corresponds to + * the value of the {@code name=} key of the {@code ObjectName} + * of the {@link + * com.sun.jmx.examples.scandir.ScanDirConfigMXBean + * ScanDirConfigMXBean} which owns this configuration. + * @return The name of this configuration. + */ + @XmlAttribute(name="name",required=true) + public String getName() { + return this.name; + } + + /** + * Sets the name of this configuration. The name of the configuration + * usually corresponds to + * the value of the {@code name=} key of the {@code ObjectName} + * of the {@link + * com.sun.jmx.examples.scandir.ScanDirConfigMXBean + * ScanDirConfigMXBean} which owns this configuration. + * <p>Once set this value cannot change.</p> + * @param name The name of this configuration. + */ + public void setName(String name) { + if (this.name == null) + this.name = name; + else if (name == null) + throw new IllegalArgumentException("name=null"); + else if (!name.equals(this.name)) + throw new IllegalArgumentException("name="+name); + } + + /** + * Gets the list of Directory Scanner configured by this + * configuration. From each element in this list, the + * {@link com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean} + * will create, initialize, and register a {@link + * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}. + * @return The list of Directory Scanner configured by this configuration. + */ + @XmlElementWrapper(name="DirectoryScannerList", + namespace=XmlConfigUtils.NAMESPACE) + @XmlElementRef + public DirectoryScannerConfig[] getScanList() { + return directoryScanners.values().toArray(new DirectoryScannerConfig[0]); + } + + /** + * Sets the list of Directory Scanner configured by this + * configuration. From each element in this list, the + * {@link com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean} + * will create, initialize, and register a {@link + * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}. + * @param scans The list of Directory Scanner configured by this configuration. + */ + public void setScanList(DirectoryScannerConfig[] scans) { + directoryScanners.clear(); + for (DirectoryScannerConfig scan : scans) + directoryScanners.put(scan.getName(),scan); + } + + /** + * Get a directory scanner by its name. + * + * @param name The name of the directory scanner. This is the + * value returned by {@link + * DirectoryScannerConfig#getName()}. + * @return The named {@code DirectoryScannerConfig} + */ + public DirectoryScannerConfig getScan(String name) { + return directoryScanners.get(name); + } + + /** + * Adds a directory scanner to the list. + * <p>If a directory scanner + * configuration by that name already exists in the list, it will + * be replaced by the given <var>scan</var>. + * </p> + * @param scan The {@code DirectoryScannerConfig} to add to the list. + * @return The replaced {@code DirectoryScannerConfig}, or {@code null} + * if there was no {@code DirectoryScannerConfig} by that name + * in the list. + */ + public DirectoryScannerConfig putScan(DirectoryScannerConfig scan) { + return this.directoryScanners.put(scan.getName(),scan); + } + + // XML value of this object. + public String toString() { + return XmlConfigUtils.toString(this); + } + + /** + * Removes the named directory scanner from the list. + * + * @param name The name of the directory scanner. This is the + * value returned by {@link + * DirectoryScannerConfig#getName()}. + * @return The removed {@code DirectoryScannerConfig}, or {@code null} + * if there was no directory scanner by that name in the list. + */ + public DirectoryScannerConfig removeScan(String name) { + return this.directoryScanners.remove(name); + } + + /** + * Gets the initial Result Log Configuration. + * @return The initial Result Log Configuration. + */ + @XmlElement(name="InitialResultLogConfig",namespace=XmlConfigUtils.NAMESPACE) + public ResultLogConfig getInitialResultLogConfig() { + return this.initialResultLogConfig; + } + + /** + * Sets the initial Result Log Configuration. + * @param initialLogConfig The initial Result Log Configuration. + */ + public void setInitialResultLogConfig(ResultLogConfig initialLogConfig) { + this.initialResultLogConfig = initialLogConfig; + } + + /** + * Creates a copy of this object, with the specified name. + * @param newname the name of the copy. + * @return A copy of this object. + **/ + public ScanManagerConfig copy(String newname) { + return copy(newname,this); + } + + // Copy by XML cloning, then change the name. + // + private static ScanManagerConfig + copy(String newname, ScanManagerConfig other) { + ScanManagerConfig newbean = XmlConfigUtils.xmlClone(other); + newbean.name = newname; + return newbean; + } +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/XmlConfigUtils.java b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/XmlConfigUtils.java new file mode 100644 index 0000000..a3e663d --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/XmlConfigUtils.java @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +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.util.logging.Logger; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +/** + * The class XmlConfigUtils is used to deal with XML serialization + * and XML files. + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class XmlConfigUtils { + + /** + * A URI for our XML configuration namespace. This doesn't start with + * http:// because we are not going to publish this private schema + * anywhere. + **/ + public static final String NAMESPACE = + "jmx:com.sun.jmx.examples.scandir.config"; + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(XmlConfigUtils.class.getName()); + + // Our JAXBContext. + private static JAXBContext context; + + // The file name of the XML file in which an instance of this object + // will read and write XML data. + final String file; + + /** + * Creates a new instance of XmlConfigUtils. + * @param file The file name of the XML file in which an instance of this + * object will read and write XML data. + */ + public XmlConfigUtils(String file) { + this.file = file; + } + + /** + * Write the given bean to the XML file. + * <p> + * Performs an atomic write, first writing in {@code <file>.new}, then + * renaming {@code <file>} to {@code <file>~}, then renaming + * renaming {@code <file>.new} to {@code <file>}. + * </p> + * @param bean The configuration to write in the XML file. + * @throws IOException if write to file failed. + **/ + public synchronized void writeToFile(ScanManagerConfig bean) + throws IOException { + + // Creates a new file named <file>.new + final File f = newXmlTmpFile(file); + try { + final FileOutputStream out = new FileOutputStream(f); + boolean failed = true; + try { + // writes to <file>.new + write(bean,out,false); + + // no exception: set failed=false for finaly {} block. + failed = false; + } finally { + out.close(); + // An exception was raised: delete temporary file. + if (failed == true) f.delete(); + } + + // rename <file> to <file>~ and <file>.new to <file> + commit(file,f); + } catch (JAXBException x) { + final IOException io = + new IOException("Failed to write SessionConfigBean to " + + file+": "+x,x); + throw io; + } + } + + /** + * Creates an XML string representation of the given bean. + * @throws IllegalArgumentException if the bean class is not known by the + * underlying XMLbinding context. + * @return An XML string representation of the given bean. + **/ + public static String toString(Object bean) { + try { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final Marshaller m = createMarshaller(); + m.setProperty(m.JAXB_FRAGMENT,Boolean.TRUE); + m.marshal(bean, baos); + return baos.toString(); + } catch (JAXBException x) { + final IllegalArgumentException iae = + new IllegalArgumentException( + "Failed to write SessionConfigBean: "+x,x); + throw iae; + } + } + + /** + * Creates an XML clone of the given bean. + * <p> + * In other words, this method XML-serializes the given bean, and + * XML-deserializes a copy of that bean. + * </p> + * @return A deep-clone of the given bean. + * @throws IllegalArgumentException if the bean class is not known by the + * underlying XML binding context. + * @param bean The bean to clone. + */ + public static ScanManagerConfig xmlClone(ScanManagerConfig bean) { + final Object clone = copy(bean); + return (ScanManagerConfig)clone; + } + + /** + * Creates an XML clone of the given bean. + * <p> + * In other words, this method XML-serializes the given bean, and + * XML-deserializes a copy of that bean. + * </p> + * @throws IllegalArgumentException if the bean class is not known by the + * underlying XML binding context. + * @return A deep-clone of the given bean. + **/ + private static Object copy(Object bean) { + try { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final Marshaller m = createMarshaller(); + m.marshal(bean, baos); + final ByteArrayInputStream bais = + new ByteArrayInputStream(baos.toByteArray()); + return createUnmarshaller().unmarshal(bais); + } catch (JAXBException x) { + final IllegalArgumentException iae = + new IllegalArgumentException("Failed to write SessionConfigBean: "+x,x); + throw iae; + } + } + + /** + * Creates an XML clone of the given bean. + * <p> + * In other words, this method XML-serializes the given bean, and + * XML-deserializes a copy of that bean. + * </p> + * @return A deep-clone of the given bean. + * @throws IllegalArgumentException if the bean class is not known by the + * underlying XML binding context. + * @param bean The bean to clone. + */ + public static DirectoryScannerConfig xmlClone(DirectoryScannerConfig bean) { + final Object clone = copy(bean); + return (DirectoryScannerConfig)clone; + } + + /** + * Reads the configuration from the XML configuration file. + * @throws IOException if it fails to read the configuration. + * @return A {@code ScanManagerConfig} bean read from the + * XML configuration file. + **/ + public synchronized ScanManagerConfig readFromFile() throws IOException { + final File f = new File(file); + if (!f.exists()) + throw new IOException("No such file: "+file); + if (!f.canRead()) + throw new IOException("Can't read file: "+file); + try { + return read(f); + } catch (JAXBException x) { + final IOException io = + new IOException("Failed to read SessionConfigBean from " + + file+": "+x,x); + throw io; + } + } + + /** + * Reads the configuration from the given XML configuration file. + * @param f the file to read from. + * @return A {@code ScanManagerConfig} bean read from the + * XML configuration file. + * @throws javax.xml.bind.JAXBException if it fails to read the configuration. + */ + public static ScanManagerConfig read(File f) + throws JAXBException { + final Unmarshaller u = createUnmarshaller(); + return (ScanManagerConfig) u.unmarshal(f); + + } + + /** + * Writes the given bean to the given output stream. + * @param bean the bean to write. + * @param os the output stream to write to. + * @param fragment whether the {@code <?xml ... ?>} header should be + * included. The header is not included if the bean is just an + * XML fragment encapsulated in a higher level XML element. + * @throws JAXBException An XML Binding exception occurred. + **/ + public static void write(ScanManagerConfig bean, OutputStream os, + boolean fragment) + throws JAXBException { + writeXml((Object)bean,os,fragment); + } + + /** + * Writes the given bean to the given output stream. + * @param bean the bean to write. + * @param os the output stream to write to. + * @param fragment whether the {@code <?xml ... ?>} header should be + * included. The header is not included if the bean is just an + * XML fragment encapsulated in a higher level XML element. + * @throws JAXBException An XML Binding exception occurred. + **/ + public static void write(ResultRecord bean, OutputStream os, boolean fragment) + throws JAXBException { + writeXml((Object)bean,os,fragment); + } + + /** + * Writes the given bean to the given output stream. + * @param bean the bean to write. + * @param os the output stream to write to. + * @param fragment whether the {@code <?xml ... ?>} header should be + * included. The header is not included if the bean is just an + * XML fragment encapsulated in a higher level XML element. + * @throws JAXBException An XML Binding exception occurred. + **/ + private static void writeXml(Object bean, OutputStream os, boolean fragment) + throws JAXBException { + final Marshaller m = createMarshaller(); + if (fragment) m.setProperty(m.JAXB_FRAGMENT,Boolean.TRUE); + m.marshal(bean,os); + } + + // Creates a JAXB Unmarshaller. + private static Unmarshaller createUnmarshaller() throws JAXBException { + return getContext().createUnmarshaller(); + } + + // Creates a JAXB Marshaller - for nicely XML formatted output. + private static Marshaller createMarshaller() throws JAXBException { + final Marshaller m = getContext().createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE); + return m; + } + + // Creates a JAXBContext if needed, and returns it. + // The JAXBContext instance we create will be able to handle the + // ScanManagerConfig and ResultRecord classes, plus all the property + // classes they reference (DirectoryScannerBean etc...). + // + private static synchronized JAXBContext getContext() throws JAXBException { + if (context == null) + context = JAXBContext.newInstance(ScanManagerConfig.class, + ResultRecord.class); + return context; + } + + + // Creates a new XML temporary file called <basename>.new + // This method is used to implement atomic writing to file. + // The usual sequence is: + // + // Final tmp = newXmlTmpFile(basename); + // boolean failed = true; + // try { + // ... write to 'tmp' ... + // // no exception: set failed=false for finaly {} block. + // failed = false; + // } finally + // // failed==true means there was an exception and + // // commit won't be called... + // if (failed==true) tmp.delete(); + // } + // commit(tmp,basename) + // + private static File newXmlTmpFile(String basename) throws IOException { + final File f = new File(basename+".new"); + if (!f.createNewFile()) + throw new IOException("file "+f.getName()+" already exists"); + + try { + final OutputStream newStream = new FileOutputStream(f); + try { + final String decl = + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"; + newStream.write(decl.getBytes("UTF-8")); + newStream.flush(); + } finally { + newStream.close(); + } + } catch (IOException x) { + f.delete(); + throw x; + } + return f; + } + + // Commit the temporary file by renaming <basename> to <baesname>~ + // and tmpFile to <basename>. + private static File commit(String basename, File tmpFile) + throws IOException { + try { + final String backupName = basename+"~"; + final File desired = new File(basename); + final File backup = new File(backupName); + backup.delete(); + if (desired.exists()) { + if (!desired.renameTo(new File(backupName))) + throw new IOException("can't rename to "+backupName); + } + if (!tmpFile.renameTo(new File(basename))) + throw new IOException("can't rename to "+basename); + } catch (IOException x) { + tmpFile.delete(); + throw x; + } + return new File(basename); + } + + /** + * Creates a new committed XML file for {@code <basename>}, containing only + * the {@code <?xml ...?>} header. + * <p>This method will rename {@code <basename>} to {@code <basename>~}, + * if it exists. + * </p> + * @return A newly created XML file containing the regular + * {@code <?xml ...?>} header. + * @param basename The name of the new file. + * @throws IOException if the new XML file couldn't be created. + */ + public static File createNewXmlFile(String basename) throws IOException { + return commit(basename,newXmlTmpFile(basename)); + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/package.html b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/package.html new file mode 100644 index 0000000..5390c29 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/config/package.html @@ -0,0 +1,69 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> + <head> + +<!-- + Copyright (c) 2006, 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. +--> + + <title>com.sun.jmx.examples.scandir.config</title> + </head> + <body> + <p> + This package defines plain Java Beans, annotated for + XML bindings, and used to store and model the scandir + application configuration. + </p> + <p>All the Java Beans defined in this package have been + designed to be <i>naturally serialized</i> by JAXB. + Their bean properties were designed to minimize + the number of XML annotation required, as well as + making them transparently convertible by the + JMX MXBean framework. + </p> + <p>The {@link com.sun.jmx.examples.scandir.config.ScanManagerConfig} + bean corresponds to the root element of the application's configuration. + From an instance of this element, the + {@link com.sun.jmx.examples.scandir.ScanManagerMXBean} will be + able to initialize the + {@link com.sun.jmx.examples.scandir.ResultLogManagerMXBean} and will + create, register and initialize + {@link com.sun.jmx.examples.scandir.DirectoryScannerMXBean DirectoryScannerMXBeans} + </p> + <p>The {@link com.sun.jmx.examples.scandir.config.XmlConfigUtils} class is a simple utility + classes used to deal with XML and XML configuration files. + </p> + <p>The {@link com.sun.jmx.examples.scandir.config.ResultRecord ResultRecords} + are used to store the results of directory scans in the result logs + managed by the {@link com.sun.jmx.examples.scandir.ResultLogManagerMXBean} + </p> + </body> +</html> diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/package.html b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/package.html new file mode 100644 index 0000000..54d3172 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/com/sun/jmx/examples/scandir/package.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> + <head> +<!-- + Copyright (c) 2006, 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. +--> + + <title>com.sun.jmx.examples.scandir</title> + </head> + <body> + <p> + This package defines the set of MBeans which compose the + management interface of the scandir application. + </p> + + </body> +</html> diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/etc/access.properties b/darwin-x86/sample/jmx/jmx-scandir/src/etc/access.properties new file mode 100644 index 0000000..c8286ed --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/etc/access.properties @@ -0,0 +1,51 @@ +###################################################################### +# Default Access Control File for Remote JMX(TM) Monitoring +###################################################################### +# +# Access control file for Remote JMX API access to monitoring. +# This file defines the allowed access for different roles. The +# password file (jmxremote.password by default) defines the roles and their +# passwords. To be functional, a role must have an entry in +# both the password and the access files. +# +# Default location of this file is $JRE/lib/management/jmxremote.access +# You can specify an alternate location by specifying a property in +# the management config file $JRE/lib/management/management.properties +# (See that file for details) +# +# The file format for password and access files is syntactically the same +# as the Properties file format. The syntax is described in the Javadoc +# for java.util.Properties.load. +# Typical access file has multiple lines, where each line is blank, +# a comment (like this one), or an access control entry. +# +# An access control entry consists of a role name, and an +# associated access level. The role name is any string that does not +# itself contain spaces or tabs. It corresponds to an entry in the +# password file (jmxremote.password). The access level is one of the +# following: +# "readonly" grants access to read attributes of MBeans. +# For monitoring, this means that a remote client in this +# role can read measurements but cannot perform any action +# that changes the environment of the running program. +# "readwrite" grants access to read and write attributes of MBeans, +# to invoke operations on them, and to create or remove them. +# This access should be granted to only trusted clients, +# since they can potentially interfere with the smooth +# operation of a running program +# +# A given role should have at most one entry in this file. If a role +# has no entry, it has no access. +# If multiple entries are found for the same role name, then the last +# access entry is used. +# +# +# Default access control entries: +# o The "monitorRole" role has readonly access. +# o The "controlRole" role has readwrite access. +# +# monitorRole readonly +# controlRole readwrite + +guest readonly +admin readwrite diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/etc/management.properties b/darwin-x86/sample/jmx/jmx-scandir/src/etc/management.properties new file mode 100644 index 0000000..5035139 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/etc/management.properties @@ -0,0 +1,273 @@ +##################################################################### +# Default Configuration File for Java Platform Management +##################################################################### +# +# The Management Configuration file (in java.util.Properties format) +# will be read if one of the following system properties is set: +# -Dcom.sun.management.jmxremote.port=<port-number> +# or -Dcom.sun.management.snmp.port=<port-number> +# or -Dcom.sun.management.config.file=<this-file> +# +# The default Management Configuration file is: +# +# $JRE/lib/management/management.properties +# +# Another location for the Management Configuration File can be specified +# by the following property on the Java command line: +# +# -Dcom.sun.management.config.file=<this-file> +# +# If -Dcom.sun.management.config.file=<this-file> is set, the port +# number for the management agent can be specified in the config file +# using the following lines: +# +# ################ Management Agent Port ######################### +# +# For setting the JMX RMI agent port use the following line +com.sun.management.jmxremote.port=4545 +# +# For setting the SNMP agent port use the following line +# com.sun.management.snmp.port=<port-number> + +##################################################################### +# Optional Instrumentation +##################################################################### +# +# By default only the basic instrumentation with low overhead is on. +# The following properties allow to selectively turn on optional +# instrumentation which are off by default and may have some +# additional overhead. +# +# com.sun.management.enableThreadContentionMonitoring +# +# This option enables thread contention monitoring if the +# Java virtual machine supports such instrumentation. +# Refer to the specification for the java.lang.management.ThreadMBean +# interface - see isThreadContentionMonitoringSupported() method. +# + +# To enable thread contention monitoring, uncomment the following line +# com.sun.management.enableThreadContentionMonitoring + +##################################################################### +# SNMP Management Properties +##################################################################### +# +# If the system property -Dcom.sun.management.snmp.port=<port-number> +# is set then +# - The SNMP agent (with the Java virtual machine MIB) is started +# that listens on the specified port for incoming SNMP requests. +# - the following properties for read for SNMP management. +# +# The configuration can be specified only at startup time. +# Later changes to the above system property (e.g. via setProperty method), this +# config file, or the ACL file has no effect to the running SNMP agent. +# + +# +# ##################### SNMP Trap Port ######################### +# +# com.sun.management.snmp.trap=<trap-destination-port-number> +# Specifies the remote port number at which managers are expected +# to listen for trap. For each host defined in the ACL file, +# the SNMP agent will send traps at <host>:<trap-destination-port-number> +# Default for this property is 162. +# + +# To set port for sending traps to a different port use the following line +# com.sun.management.snmp.trap=<trap-destination-port-number> + +# +# ################ SNMP listen interface ######################### +# +# com.sun.management.snmp.interface=<InetAddress> +# Specifies the local interface on which the SNMP agent will bind. +# This is usefull when running on machines which have several +# interfaces defined. It makes it possible to listen to a specific +# subnet accessible through that interface. +# Default for this property is "localhost". +# +# The format of the value for that property is any string accepted +# by java.net.InetAddress.getByName(String). +# + +# For restricting the port on which SNMP agent listens use the following line +# com.sun.management.snmp.interface=<InetAddress> + +# +# #################### SNMP ACL file ######################### +# +# com.sun.management.snmp.acl=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as false then the ACL file +# is not checked: all manager hosts are allowed all access. +# + +# For SNMP without checking ACL file uncomment the following line +# com.sun.management.snmp.acl=false + +# +# com.sun.management.snmp.acl.file=filepath +# Specifies location for ACL file +# This is optional - default location is +# $JRE/lib/management/snmp.acl +# +# If the property "com.sun.management.snmp.acl" is set to false, +# then this property and the ACL file are ignored. +# Otherwise the ACL file must exist and be in the valid format. +# If the ACL file is empty or non existent then no access is allowed. +# +# The SNMP agent will read the ACL file at startup time. +# Modification to the ACL file has no effect to any running SNMP +# agents which read that ACL file at startup. +# + +# For a non-default acl file location use the following line +# com.sun.management.snmp.acl.file=filepath + +##################################################################### +# RMI Management Properties +##################################################################### +# +# If system property -Dcom.sun.management.jmxremote.port=<port-number> +# is set then +# - A MBean server is started +# - JRE Platform MBeans are registered in the MBean server +# - RMI connector is published in a private readonly registry at +# specified port using a well known name, "jmxrmi" +# - the following properties are read for JMX remote management. +# +# The configuration can be specified only at startup time. +# Later changes to above system property (e.g. via setProperty method), +# this config file, the password file, or the access file have no effect to the +# running MBean server, the connector, or the registry. +# + +# +# ###################### RMI SSL ############################# +# +# com.sun.management.jmxremote.ssl=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as false then SSL is not used. +# + +# For RMI monitoring without SSL use the following line +# com.sun.management.jmxremote.ssl=false + +# com.sun.management.jmxremote.ssl.enabled.cipher.suites=<cipher-suites> +# The value of this property is a string that is a comma-separated list +# of SSL/TLS cipher suites to enable. This property can be specified in +# conjunction with the previous property "com.sun.management.jmxremote.ssl" +# in order to control which particular SSL/TLS cipher suites are enabled +# for use by accepted connections. If this property is not specified then +# the SSL/TLS RMI Server Socket Factory uses the SSL/TLS cipher suites that +# are enabled by default. +# + +# com.sun.management.jmxremote.ssl.enabled.protocols=<protocol-versions> +# The value of this property is a string that is a comma-separated list +# of SSL/TLS protocol versions to enable. This property can be specified in +# conjunction with the previous property "com.sun.management.jmxremote.ssl" +# in order to control which particular SSL/TLS protocol versions are +# enabled for use by accepted connections. If this property is not +# specified then the SSL/TLS RMI Server Socket Factory uses the SSL/TLS +# protocol versions that are enabled by default. +# + +# com.sun.management.jmxremote.ssl.need.client.auth=true|false +# Default for this property is false. (Case for true/false ignored) +# If this property is specified as true in conjunction with the previous +# property "com.sun.management.jmxremote.ssl" then the SSL/TLS RMI Server +# Socket Factory will require client authentication. +# + +# For RMI monitoring with SSL client authentication use the following line +com.sun.management.jmxremote.ssl.need.client.auth=true + +# com.sun.management.jmxremote.registry.ssl=true|false +# Default for this property is false. (Case for true/false ignored) +# If this property is specified as true then the RMI registry used +# to bind the RMIServer remote object is protected with SSL/TLS +# RMI Socket Factories that can be configured with the properties: +# com.sun.management.jmxremote.ssl.enabled.cipher.suites +# com.sun.management.jmxremote.ssl.enabled.protocols +# com.sun.management.jmxremote.ssl.need.client.auth +# If the two properties below are true at the same time, i.e. +# com.sun.management.jmxremote.ssl=true +# com.sun.management.jmxremote.registry.ssl=true +# then the RMIServer remote object and the RMI registry are +# both exported with the same SSL/TLS RMI Socket Factories. +# + +# For using an SSL/TLS protected RMI registry use the following line +com.sun.management.jmxremote.registry.ssl=true + +# +# ################ RMI User authentication ################ +# +# com.sun.management.jmxremote.authenticate=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as false then no authentication is +# performed and all users are allowed all access. +# + +# For RMI monitoring without any checking use the following line +# com.sun.management.jmxremote.authenticate=false + +# +# ################ RMI Login configuration ################### +# +# com.sun.management.jmxremote.login.config=<config-name> +# Specifies the name of a JAAS login configuration entry to use when +# authenticating users of RMI monitoring. +# +# Setting this property is optional - the default login configuration +# specifies a file-based authentication that uses the password file. +# +# When using this property to override the default login configuration +# then the named configuration entry must be in a file that gets loaded +# by JAAS. In addition, the login module(s) specified in the configuration +# should use the name and/or password callbacks to acquire the user's +# credentials. See the NameCallback and PasswordCallback classes in the +# javax.security.auth.callback package for more details. +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# + +# For a non-default login configuration use the following line +# com.sun.management.jmxremote.login.config=<config-name> + +# +# ################ RMI Password file location ################## +# +# com.sun.management.jmxremote.password.file=filepath +# Specifies location for password file +# This is optional - default location is +# $JRE/lib/management/jmxremote.password +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# Otherwise the password file must exist and be in the valid format. +# If the password file is empty or non-existent then no access is allowed. +# + +# For a non-default password file location use the following line +com.sun.management.jmxremote.password.file=src/etc/password.properties + +# +# ################ RMI Access file location ##################### +# +# com.sun.management.jmxremote.access.file=filepath +# Specifies location for access file +# This is optional - default location is +# $JRE/lib/management/jmxremote.access +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# Otherwise, the access file must exist and be in the valid format. +# If the access file is empty or non-existent then no access is allowed. +# + +# For a non-default password file location use the following line +com.sun.management.jmxremote.access.file=src/etc/access.properties diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/etc/password.properties b/darwin-x86/sample/jmx/jmx-scandir/src/etc/password.properties new file mode 100644 index 0000000..d90c8c8 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/etc/password.properties @@ -0,0 +1,55 @@ +############################################################## +# Password File for Remote JMX Monitoring +############################################################## +# +# Password file for Remote JMX API access to monitoring. This +# file defines the different roles and their passwords. The access +# control file (jmxremote.access by default) defines the allowed +# access for each role. To be functional, a role must have an entry +# in both the password and the access files. +# +# Default location of this file is $JRE/lib/management/jmxremote.password +# You can specify an alternate location by specifying a property in +# the management config file $JRE/lib/management/management.properties +# or by specifying a system property (See that file for details). + + +############################################################## +# File permissions of the jmxremote.password file +############################################################## +# Since there are cleartext passwords stored in this file, +# this file must be readable by ONLY the owner, +# otherwise the program will exit with an error. +# +# The file format for password and access files is syntactically the same +# as the Properties file format. The syntax is described in the Javadoc +# for java.util.Properties.load. +# Typical password file has multiple lines, where each line is blank, +# a comment (like this one), or a password entry. +# +# +# A password entry consists of a role name and an associated +# password. The role name is any string that does not itself contain +# spaces or tabs. The password is again any string that does not +# contain spaces or tabs. Note that passwords appear in the clear in +# this file, so it is a good idea not to use valuable passwords. +# +# A given role should have at most one entry in this file. If a role +# has no entry, it has no access. +# If multiple entries are found for the same role name, then the last one +# is used. +# +# In a typical installation, this file can be read by anybody on the +# local machine, and possibly by people on other machines. +# For # security, you should either restrict the access to this file, +# or specify another, less accessible file in the management config file +# as described above. +# +# Following are two commented-out entries. The "measureRole" role has +# password "QED". The "controlRole" role has password "R&D". +# +# monitorRole QED +# controlRole R&D + +guest guestpasswd +admin adminpasswd diff --git a/darwin-x86/sample/jmx/jmx-scandir/src/etc/testconfig.xml b/darwin-x86/sample/jmx/jmx-scandir/src/etc/testconfig.xml new file mode 100644 index 0000000..cf0fece --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/src/etc/testconfig.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<ScanManager xmlns="jmx:com.sun.jmx.examples.scandir.config" name="testconfig"> + <InitialResultLogConfig> + <LogFileMaxRecords>2048</LogFileMaxRecords> + <LogFileName>build/scandir.log</LogFileName> + <MemoryMaxRecords>128</MemoryMaxRecords> + </InitialResultLogConfig> + <DirectoryScannerList> + <DirectoryScanner name="scan-build"> + <Actions>NOTIFY LOGRESULT</Actions> + <ExcludeFiles/> + <IncludeFiles> + <FileFilter> + <FilePattern>.*\.class</FilePattern> + <SizeExceedsMaxBytes>4096</SizeExceedsMaxBytes> + </FileFilter> + </IncludeFiles> + <RootDirectory>build</RootDirectory> + </DirectoryScanner> + </DirectoryScannerList> +</ScanManager> diff --git a/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/DirectoryScannerTest.java b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/DirectoryScannerTest.java new file mode 100644 index 0000000..06d1559 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/DirectoryScannerTest.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.ResultRecord; +import com.sun.jmx.examples.scandir.config.ScanManagerConfig; +import java.util.LinkedList; +import java.util.concurrent.BlockingQueue; +import junit.framework.*; +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; +import com.sun.jmx.examples.scandir.ScanManagerTest.Call; +import java.util.EnumSet; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.AttributeChangeNotification; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +import static com.sun.jmx.examples.scandir.ScanManagerTest.*; +import static com.sun.jmx.examples.scandir.TestUtils.*; +import java.io.File; +import java.lang.management.ManagementFactory; +import java.util.List; + +/** + * Unit tests for {@code DirectoryScanner} + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class DirectoryScannerTest extends TestCase { + + public DirectoryScannerTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + public static Test suite() { + TestSuite suite = new TestSuite(DirectoryScannerTest.class); + + return suite; + } + + private void doTestOperation( + DirectoryScannerMXBean proxy, + Call op, + EnumSet<ScanState> after, + String testName) + throws Exception { + System.out.println("doTestOperation: "+testName); + + final LinkedBlockingQueue<Notification> queue = + new LinkedBlockingQueue<Notification>(); + + NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + queue.put(notification); + } catch (Exception x) { + System.err.println("Failed to queue notif: "+x); + } + } + }; + NotificationFilter filter = null; + Object handback = null; + final ScanState before; + final NotificationEmitter emitter = (NotificationEmitter) + makeNotificationEmitter(proxy,DirectoryScannerMXBean.class); + emitter.addNotificationListener(listener, filter, handback); + before = proxy.getState(); + op.call(); + try { + final Notification notification = + queue.poll(3000,TimeUnit.MILLISECONDS); + assertEquals(AttributeChangeNotification.ATTRIBUTE_CHANGE, + notification.getType()); + assertEquals(AttributeChangeNotification.class, + notification.getClass()); + assertEquals(getObjectName(proxy), + notification.getSource()); + AttributeChangeNotification acn = + (AttributeChangeNotification)notification; + assertEquals("State",acn.getAttributeName()); + assertEquals(ScanState.class.getName(),acn.getAttributeType()); + assertEquals(before,ScanState.valueOf((String)acn.getOldValue())); + assertContained(after,ScanState.valueOf((String)acn.getNewValue())); + emitter.removeNotificationListener(listener,filter,handback); + } finally { + try { + op.cancel(); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + + /** + * Test of getRootDirectory method, of class com.sun.jmx.examples.scandir.DirectoryScanner. + */ + public void testGetRootDirectory() throws Exception { + System.out.println("getRootDirectory"); + + final ScanManagerMXBean manager = ScanManager.register(); + try { + final String tmpdir = System.getProperty("java.io.tmpdir"); + final ScanDirConfigMXBean config = manager.getConfigurationMBean(); + System.err.println("Configuration MXBean is: " + config); + final DirectoryScannerConfig bean = + config.addDirectoryScanner("test",tmpdir,".*",0,0); + final String root = bean.getRootDirectory(); + if (root == null) + throw new NullPointerException("bean.getRootDirectory()"); + if (config.getConfiguration().getScan("test").getRootDirectory() == null) + throw new NullPointerException("config.getConfig().getScan(\"test\").getRootDirectory()"); + manager.applyConfiguration(true); + final DirectoryScannerMXBean proxy = + manager.getDirectoryScanners().get("test"); + final File tmpFile = new File(tmpdir); + final File rootFile = new File(proxy.getRootDirectory()); + assertEquals(tmpFile,rootFile); + } catch (Exception x) { + x.printStackTrace(); + throw x; + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + + /** + * Test of scan method, of class com.sun.jmx.examples.scandir.DirectoryScanner. + */ + public void testScan() throws Exception { + System.out.println("scan"); + + final ScanManagerMXBean manager = ScanManager.register(); + try { + final String tmpdir = System.getProperty("java.io.tmpdir"); + final ScanDirConfigMXBean config = manager.getConfigurationMBean(); + final DirectoryScannerConfig bean = + config.addDirectoryScanner("test1",tmpdir,".*",0,0); + config.addDirectoryScanner("test2",tmpdir,".*",0,0); + config.addDirectoryScanner("test3",tmpdir,".*",0,0); + manager.applyConfiguration(true); + final DirectoryScannerMXBean proxy = + manager.getDirectoryScanners().get("test1"); + final Call op = new Call() { + public void call() throws Exception { + final BlockingQueue<Notification> queue = + new LinkedBlockingQueue<Notification>(); + final NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + queue.put(notification); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + manager.start(); + while(true) { + final Notification n = queue.poll(10,TimeUnit.SECONDS); + if (n == null) break; + final AttributeChangeNotification at = + (AttributeChangeNotification) n; + if (RUNNING == ScanState.valueOf((String)at.getNewValue())) + break; + else { + System.err.println("New state: "+(String)at.getNewValue() + +" isn't "+RUNNING); + } + } + assertContained(EnumSet.of(SCHEDULED,RUNNING,COMPLETED), + proxy.getState()); + } + public void cancel() throws Exception { + manager.stop(); + } + }; + doTestOperation(proxy,op, + EnumSet.of(RUNNING,SCHEDULED,COMPLETED), + "scan"); + } catch (Exception x) { + x.printStackTrace(); + throw x; + } finally { + try { + manager.stop(); + } catch (Exception x) { + System.err.println("Failed to stop: "+x); + } + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + /** + * Test of getState method, of class com.sun.jmx.examples.scandir.DirectoryScanner. + */ + public void testGetState() { + System.out.println("getState"); + + final DirectoryScannerConfig bean = + new DirectoryScannerConfig("test"); + bean.setRootDirectory(System.getProperty("java.io.tmpdir")); + final ResultLogManager log = new ResultLogManager(); + DirectoryScanner instance = + new DirectoryScanner(bean,log); + + ScanState expResult = STOPPED; + ScanState result = instance.getState(); + assertEquals(STOPPED, result); + instance.scan(); + result = instance.getState(); + assertEquals(COMPLETED, result); + } + + /** + * Test of addNotificationListener method, of class com.sun.jmx.examples.scandir.DirectoryScanner. + */ + public void testAddNotificationListener() throws Exception { + System.out.println("addNotificationListener"); + + final ScanManagerMXBean manager = ScanManager.register(); + final Call op = new Call() { + public void call() throws Exception { + manager.start(); + } + public void cancel() throws Exception { + manager.stop(); + } + }; + try { + final String tmpdir = System.getProperty("java.io.tmpdir"); + final ScanDirConfigMXBean config = manager.getConfigurationMBean(); + final DirectoryScannerConfig bean = + config.addDirectoryScanner("test1",tmpdir,".*",0,0); + manager.applyConfiguration(true); + final DirectoryScannerMXBean proxy = + manager.getDirectoryScanners().get("test1"); + doTestOperation(proxy,op, + EnumSet.of(RUNNING,SCHEDULED), + "scan"); + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanDirConfigTest.java b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanDirConfigTest.java new file mode 100644 index 0000000..c7e9599 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanDirConfigTest.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import com.sun.jmx.examples.scandir.config.XmlConfigUtils; +import com.sun.jmx.examples.scandir.config.FileMatch; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import junit.framework.*; +import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; +import com.sun.jmx.examples.scandir.config.ScanManagerConfig; +import java.io.File; +import java.util.concurrent.BlockingQueue; +import javax.management.*; + +/** + * Unit tests for {@code ScanDirConfig} + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class ScanDirConfigTest extends TestCase { + + public ScanDirConfigTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + public static Test suite() { + TestSuite suite = new TestSuite(ScanDirConfigTest.class); + + return suite; + } + + /** + * Test of load method, of class com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testLoad() throws Exception { + System.out.println("load"); + + final File file = File.createTempFile("testconf",".xml"); + final ScanDirConfig instance = new ScanDirConfig(file.getAbsolutePath()); + final ScanManagerConfig bean = + new ScanManagerConfig("testLoad"); + final DirectoryScannerConfig dir = + new DirectoryScannerConfig("tmp"); + dir.setRootDirectory(file.getParent()); + bean.putScan(dir); + XmlConfigUtils.write(bean,new FileOutputStream(file),false); + instance.load(); + + assertEquals(bean,instance.getConfiguration()); + bean.removeScan(dir.getName()); + XmlConfigUtils.write(bean,new FileOutputStream(file),false); + + assertNotSame(bean,instance.getConfiguration()); + + instance.load(); + + assertEquals(bean,instance.getConfiguration()); + + } + + /** + * Test of save method, of class com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testSave() throws Exception { + System.out.println("save"); + + final File file = File.createTempFile("testconf",".xml"); + final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + final ScanManagerMXBean manager = ScanManager.register(mbs); + + try { + final ScanDirConfigMXBean instance = + manager.createOtherConfigurationMBean("testSave",file.getAbsolutePath()); + assertTrue(mbs.isRegistered( + ScanManager.makeScanDirConfigName("testSave"))); + final ScanManagerConfig bean = + new ScanManagerConfig("testSave"); + final DirectoryScannerConfig dir = + new DirectoryScannerConfig("tmp"); + dir.setRootDirectory(file.getParent()); + bean.putScan(dir); + instance.setConfiguration(bean); + instance.save(); + final ScanManagerConfig loaded = + new XmlConfigUtils(file.getAbsolutePath()).readFromFile(); + assertEquals(instance.getConfiguration(),loaded); + assertEquals(bean,loaded); + + instance.getConfiguration().removeScan("tmp"); + instance.save(); + assertNotSame(loaded,instance.getConfiguration()); + final ScanManagerConfig loaded2 = + new XmlConfigUtils(file.getAbsolutePath()).readFromFile(); + assertEquals(instance.getConfiguration(),loaded2); + } finally { + manager.close(); + mbs.unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } + final ObjectName all = + new ObjectName(ScanManager.SCAN_MANAGER_NAME.getDomain()+":*"); + assertEquals(0,mbs.queryNames(all,null).size()); + } + + /** + * Test of saveTo method, of class com.sun.jmx.examples.scandir.ScanProfile. + */ + /* + public void testSaveTo() throws Exception { + System.out.println("saveTo"); + + String filename = ""; + ScanDirConfig instance = null; + + instance.saveTo(filename); + + // TODO review the generated test code and remove the default call to fail. + fail("The test case is a prototype."); + } + */ + + /** + * Test of getXmlConfigString method, of class com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testGetXmlConfigString() throws Exception { + System.out.println("getXmlConfigString"); + + try { + final File file = File.createTempFile("testconf",".xml"); + final ScanDirConfig instance = new ScanDirConfig(file.getAbsolutePath()); + final ScanManagerConfig bean = + new ScanManagerConfig("testGetXmlConfigString"); + final DirectoryScannerConfig dir = + new DirectoryScannerConfig("tmp"); + dir.setRootDirectory(file.getParent()); + bean.putScan(dir); + instance.setConfiguration(bean); + System.out.println("Expected: " + XmlConfigUtils.toString(bean)); + System.out.println("Received: " + + instance.getConfiguration().toString()); + assertEquals(XmlConfigUtils.toString(bean), + instance.getConfiguration().toString()); + } catch (Exception x) { + x.printStackTrace(); + throw x; + } + } + + + /** + * Test of addNotificationListener method, of class + * com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testAddNotificationListener() throws Exception { + System.out.println("addNotificationListener"); + + final File file = File.createTempFile("testconf",".xml"); + final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + final ScanManagerMXBean manager = ScanManager.register(mbs); + + try { + final ScanDirConfigMXBean instance = + TestUtils.makeNotificationEmitter( + manager.createOtherConfigurationMBean("testSave", + file.getAbsolutePath()), + ScanDirConfigMXBean.class); + assertTrue(mbs.isRegistered( + ScanManager.makeScanDirConfigName("testSave"))); + DirectoryScannerConfig dir = + instance.addDirectoryScanner("tmp",file.getParent(),".*",0,0); + + final BlockingQueue<Notification> queue = + new LinkedBlockingQueue<Notification>(); + final NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + }; + NotificationFilter filter = null; + Object handback = null; + + ((NotificationEmitter)instance).addNotificationListener(listener, + filter, handback); + + instance.save(); + final ScanManagerConfig loaded = + new XmlConfigUtils(file.getAbsolutePath()).readFromFile(); + assertEquals(instance.getConfiguration(),loaded); + + final ScanManagerConfig newConfig = + instance.getConfiguration(); + newConfig.removeScan("tmp"); + instance.setConfiguration(newConfig); + instance.save(); + assertNotSame(loaded,instance.getConfiguration()); + final ScanManagerConfig loaded2 = + new XmlConfigUtils(file.getAbsolutePath()).readFromFile(); + assertEquals(instance.getConfiguration(),loaded2); + instance.load(); + for (int i=0;i<4;i++) { + final Notification n = queue.poll(3,TimeUnit.SECONDS); + assertNotNull(n); + assertEquals(TestUtils.getObjectName(instance),n.getSource()); + switch(i) { + case 0: case 2: + assertEquals(ScanDirConfig.NOTIFICATION_SAVED,n.getType()); + break; + case 1: + assertEquals(ScanDirConfig.NOTIFICATION_MODIFIED,n.getType()); + break; + case 3: + assertEquals(ScanDirConfig.NOTIFICATION_LOADED,n.getType()); + break; + default: break; + } + } + } finally { + manager.close(); + mbs.unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } + final ObjectName all = + new ObjectName(ScanManager.SCAN_MANAGER_NAME.getDomain()+":*"); + assertEquals(0,mbs.queryNames(all,null).size()); + } + + /** + * Test of getConfigFilename method, of class + * com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testGetConfigFilename() throws Exception { + System.out.println("getConfigFilename"); + + final File file = File.createTempFile("testconf",".xml"); + final ScanDirConfig instance = new ScanDirConfig(file.getAbsolutePath()); + + String result = instance.getConfigFilename(); + assertEquals(file.getAbsolutePath(), new File(result).getAbsolutePath()); + + } + + /** + * Test of addDirectoryScanner method, of class + * com.sun.jmx.examples.scandir.ScanDirConfig. + */ + public void testAddDirectoryScanner() throws IOException { + System.out.println("addDirectoryScanner"); + + System.out.println("save"); + + final File file = File.createTempFile("testconf",".xml"); + final ScanDirConfig instance = new ScanDirConfig(file.getAbsolutePath()); + final ScanManagerConfig bean = + new ScanManagerConfig("testSave"); + final DirectoryScannerConfig dir = + new DirectoryScannerConfig("tmp"); + dir.setRootDirectory(file.getParent()); + FileMatch filter = new FileMatch(); + filter.setFilePattern(".*"); + dir.setIncludeFiles(new FileMatch[] { + filter + }); + instance.setConfiguration(bean); + instance.addDirectoryScanner(dir.getName(), + dir.getRootDirectory(), + filter.getFilePattern(), + filter.getSizeExceedsMaxBytes(), + 0); + instance.save(); + final ScanManagerConfig loaded = + new XmlConfigUtils(file.getAbsolutePath()).readFromFile(); + assertNotNull(loaded.getScan(dir.getName())); + assertEquals(dir,loaded.getScan(dir.getName())); + assertEquals(instance.getConfiguration(),loaded); + assertEquals(instance.getConfiguration().getScan(dir.getName()),dir); + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanManagerTest.java b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanManagerTest.java new file mode 100644 index 0000000..94e3c98 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/ScanManagerTest.java @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.InstanceNotFoundException; +import javax.management.Notification; +import junit.framework.*; +import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; +import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.logging.Logger; +import javax.management.AttributeChangeNotification; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; + +/** + * Unit tests for {@code ScanManager} + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class ScanManagerTest extends TestCase { + + public ScanManagerTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + public static Test suite() { + TestSuite suite = new TestSuite(ScanManagerTest.class); + + return suite; + } + + /** + * Test of makeSingletonName method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testMakeSingletonName() { + System.out.println("makeSingletonName"); + + Class clazz = ScanManagerMXBean.class; + + ObjectName expResult = ScanManager.SCAN_MANAGER_NAME; + ObjectName result = ScanManager.makeSingletonName(clazz); + assertEquals(expResult, result); + + } + + /** + * Test of register method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testRegister() throws Exception { + System.out.println("register"); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + + ScanManagerMXBean result = ScanManager.register(mbs); + try { + assertEquals(STOPPED,result.getState()); + } finally { + try { + mbs.unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + + } + + public interface Call { + public void call() throws Exception; + public void cancel() throws Exception; + } + + /** + * Test of addNotificationListener method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testAddNotificationListener() throws Exception { + System.out.println("addNotificationListener"); + + final ScanManagerMXBean manager = ScanManager.register(); + final Call op = new Call() { + public void call() throws Exception { + manager.schedule(100000,0); + } + public void cancel() throws Exception { + manager.stop(); + } + }; + try { + doTestOperation(manager,op, + EnumSet.of(RUNNING,SCHEDULED), + "schedule"); + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + /** + * Test of addNotificationListener method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + private void doTestOperation( + ScanManagerMXBean proxy, + Call op, + EnumSet<ScanState> after, + String testName) + throws Exception { + System.out.println("doTestOperation: "+testName); + + final LinkedBlockingQueue<Notification> queue = + new LinkedBlockingQueue<Notification>(); + + NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + queue.put(notification); + } catch (Exception x) { + System.err.println("Failed to queue notif: "+x); + } + } + }; + NotificationFilter filter = null; + Object handback = null; + final ScanState before; + final NotificationEmitter emitter = (NotificationEmitter)proxy; + emitter.addNotificationListener(listener, filter, handback); + before = proxy.getState(); + op.call(); + try { + final Notification notification = + queue.poll(3000,TimeUnit.MILLISECONDS); + assertEquals(AttributeChangeNotification.ATTRIBUTE_CHANGE, + notification.getType()); + assertEquals(AttributeChangeNotification.class, + notification.getClass()); + assertEquals(ScanManager.SCAN_MANAGER_NAME, + notification.getSource()); + AttributeChangeNotification acn = + (AttributeChangeNotification)notification; + assertEquals("State",acn.getAttributeName()); + assertEquals(ScanState.class.getName(),acn.getAttributeType()); + assertEquals(before,ScanState.valueOf((String)acn.getOldValue())); + assertContained(after,ScanState.valueOf((String)acn.getNewValue())); + emitter.removeNotificationListener(listener,filter,handback); + } finally { + try { + op.cancel(); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + /** + * Test of preRegister method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testPreRegister() throws Exception { + System.out.println("preRegister"); + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName("DownUnder:type=Wombat"); + ScanManager instance = new ScanManager(); + + ObjectName expResult = ScanManager.SCAN_MANAGER_NAME; + ObjectName result; + try { + result = instance.preRegister(server, name); + throw new RuntimeException("bad name accepted!"); + } catch (IllegalArgumentException x) { + // OK! + result = instance.preRegister(server, null); + } + assertEquals(expResult, result); + result = instance.preRegister(server, ScanManager.SCAN_MANAGER_NAME); + assertEquals(expResult, result); + } + + + /** + * Test of getState method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testGetState() throws IOException, InstanceNotFoundException { + System.out.println("getState"); + + ScanManager instance = new ScanManager(); + + ScanState expResult = ScanState.STOPPED; + ScanState result = instance.getState(); + assertEquals(expResult, result); + instance.start(); + final ScanState afterStart = instance.getState(); + assertContained(EnumSet.of(RUNNING,SCHEDULED,COMPLETED),afterStart); + instance.stop(); + assertEquals(STOPPED,instance.getState()); + instance.schedule(1000000L,1000000L); + assertEquals(SCHEDULED,instance.getState()); + instance.stop(); + assertEquals(STOPPED,instance.getState()); + } + + /** + * Test of schedule method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testSchedule() throws Exception { + System.out.println("schedule"); + + final long delay = 10000L; + final long interval = 10000L; + + final ScanManagerMXBean manager = ScanManager.register(); + final Call op = new Call() { + public void call() throws Exception { + manager.schedule(delay,interval); + assertEquals(SCHEDULED,manager.getState()); + } + public void cancel() throws Exception { + manager.stop(); + } + }; + try { + doTestOperation(manager,op,EnumSet.of(SCHEDULED), + "schedule"); + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + public static void assertContained(EnumSet<ScanState> allowed, + ScanState state) { + final String msg = String.valueOf(state) + " is not one of " + allowed; + assertTrue(msg,allowed.contains(state)); + } + + /** + * Test of stop method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testStop() throws Exception { + System.out.println("stop"); + final ScanManagerMXBean manager = ScanManager.register(); + try { + manager.schedule(1000000,0); + assertContained(EnumSet.of(SCHEDULED),manager.getState()); + final Call op = new Call() { + public void call() throws Exception { + manager.stop(); + assertEquals(STOPPED,manager.getState()); + } + public void cancel() throws Exception { + if (manager.getState() != STOPPED) + manager.stop(); + } + }; + doTestOperation(manager,op,EnumSet.of(STOPPED),"stop"); + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + + /** + * Test of start method, of class com.sun.jmx.examples.scandir.ScanManager. + */ + public void testStart() throws Exception { + final ScanManagerMXBean manager = ScanManager.register(); + try { + final Call op = new Call() { + public void call() throws Exception { + assertEquals(STOPPED,manager.getState()); + manager.start(); + assertContained(EnumSet.of(RUNNING,SCHEDULED,COMPLETED), + manager.getState()); + } + public void cancel() throws Exception { + manager.stop(); + } + }; + doTestOperation(manager,op,EnumSet.of(RUNNING,SCHEDULED,COMPLETED), + "start"); + } finally { + try { + ManagementFactory.getPlatformMBeanServer(). + unregisterMBean(ScanManager.SCAN_MANAGER_NAME); + } catch (Exception x) { + System.err.println("Failed to cleanup: "+x); + } + } + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/TestUtils.java b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/TestUtils.java new file mode 100644 index 0000000..4832949 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/TestUtils.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.logging.Logger; +import javax.management.JMX; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.NotificationEmitter; +import javax.management.ObjectName; + +/** + * A utility class defining static methods used by our tests. + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class TestUtils { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(TestUtils.class.getName()); + + /** Creates a new instance of TestUtils */ + private TestUtils() { + } + + /** + * Returns the ObjectName of the MBean that a proxy object + * is proxying. + **/ + public static ObjectName getObjectName(Object proxy) { + if (!(proxy instanceof Proxy)) + throw new IllegalArgumentException("not a "+Proxy.class.getName()); + final Proxy p = (Proxy) proxy; + final InvocationHandler handler = + Proxy.getInvocationHandler(proxy); + if (handler instanceof MBeanServerInvocationHandler) + return ((MBeanServerInvocationHandler)handler).getObjectName(); + throw new IllegalArgumentException("not a JMX Proxy"); + } + + /** + * Transfroms a proxy implementing T in a proxy implementing T plus + * NotificationEmitter + * + **/ + public static <T> T makeNotificationEmitter(T proxy, + Class<T> mbeanInterface) { + if (proxy instanceof NotificationEmitter) + return proxy; + if (proxy == null) return null; + if (!(proxy instanceof Proxy)) + throw new IllegalArgumentException("not a "+Proxy.class.getName()); + final Proxy p = (Proxy) proxy; + final InvocationHandler handler = + Proxy.getInvocationHandler(proxy); + if (!(handler instanceof MBeanServerInvocationHandler)) + throw new IllegalArgumentException("not a JMX Proxy"); + final MBeanServerInvocationHandler h = + (MBeanServerInvocationHandler)handler; + final ObjectName name = h.getObjectName(); + final MBeanServerConnection mbs = h.getMBeanServerConnection(); + final boolean isMXBean = h.isMXBean(); + final T newProxy; + if (isMXBean) + newProxy = JMX.newMXBeanProxy(mbs,name,mbeanInterface,true); + else + newProxy = JMX.newMBeanProxy(mbs,name,mbeanInterface,true); + return newProxy; + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/config/XmlConfigUtilsTest.java b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/config/XmlConfigUtilsTest.java new file mode 100644 index 0000000..e4cea49 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/test/com/sun/jmx/examples/scandir/config/XmlConfigUtilsTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.jmx.examples.scandir.config; + +import junit.framework.*; +import java.io.File; + +/** + * Unit tests for {@code XmlConfigUtils} + * + * @author Sun Microsystems, 2006 - All rights reserved. + */ +public class XmlConfigUtilsTest extends TestCase { + + public XmlConfigUtilsTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + public static Test suite() { + TestSuite suite = new TestSuite(XmlConfigUtilsTest.class); + + return suite; + } + + + /** + * Test of writeToFile method, of class XmlConfigUtils. + */ + public void testWriteToFile() throws Exception { + System.out.println("writeToFile"); + + final File file = File.createTempFile("test",".xml"); + file.deleteOnExit(); + + final String tmp = System.getProperty("java.io.tmpdir"); + + DirectoryScannerConfig dir1 = + new DirectoryScannerConfig("scan2"); + dir1.setRootDirectory(tmp); + ScanManagerConfig bean = new ScanManagerConfig("session2"); + bean.putScan(dir1); + XmlConfigUtils instance = new XmlConfigUtils(file.getPath()); + + instance.writeToFile(bean); + } + + /** + * Test of readFromFile method, of class com.sun.jmx.examples.scandir.config.XmlConfigUtils. + */ + public void testReadFromFile() throws Exception { + System.out.println("readFromFile"); + + final String tmp = System.getProperty("java.io.tmpdir"); + final File file = File.createTempFile("test",".xml"); + file.deleteOnExit(); + + DirectoryScannerConfig dir1 = + new DirectoryScannerConfig("scan1"); + dir1.setRootDirectory(tmp); + ScanManagerConfig bean = new ScanManagerConfig("session1"); + bean.putScan(dir1); + XmlConfigUtils instance = new XmlConfigUtils(file.getPath()); + + instance.writeToFile(bean); + + ScanManagerConfig expResult = bean; + ScanManagerConfig result = instance.readFromFile(); + System.out.println(result); + assertEquals(expResult, result); + + + } + +} diff --git a/darwin-x86/sample/jmx/jmx-scandir/truststore b/darwin-x86/sample/jmx/jmx-scandir/truststore Binary files differnew file mode 100644 index 0000000..2f5ba34 --- /dev/null +++ b/darwin-x86/sample/jmx/jmx-scandir/truststore diff --git a/darwin-x86/sample/lambda/BulkDataOperations/index.html b/darwin-x86/sample/lambda/BulkDataOperations/index.html new file mode 100644 index 0000000..5a16695 --- /dev/null +++ b/darwin-x86/sample/lambda/BulkDataOperations/index.html @@ -0,0 +1,49 @@ +<!DOCTYPE html>
+<html>
+<head>
+ <title>Bulk Data Operations Demo</title>
+</head>
+<body>
+<h2>Bulk Data Operations Demo</h2>
+
+<p>
+ This demo shows how to use bulk data operations with the new JDK8
+ Collections API.
+ The demo also demonstrates new features of JDK8 such as lambda expressions
+ and method/constructor references.
+</p>
+
+<ul>
+ <li><h3>CSV Processor</h3>
+
+ <p>
+ Analyzes a CSV file, finds and collects useful information, computes
+ different statistics. For more information, see the source file.
+ </p>
+ Source: <a href="src/CSVProcessor.java">src/CSVProcessor.java</a>
+ <li><h3>Grep</h3>
+
+ <p>
+ Behaves like the standard Linux tool Grep. For more information, see
+ the source file.
+ </p>
+ Source: <a href="src/Grep.java">src/Grep.java</a>
+ <li><h3>PasswordGenerator</h3>
+
+ <p>
+ Produces a password of desired length. For more information see
+ source file.
+ </p>
+ Source: <a
+ href="src/PasswordGenerator.java">src/PasswordGenerator.java</a>
+ <li><h3>WC</h3>
+
+ <p>
+ Counts newlines, words, characters, and the maximum line length of a
+ text file. For more information, see the source
+ file.
+ </p>
+ Source: <a href="src/WC.java">src/WC.java</a>
+</ul>
+</body>
+</html>
\ No newline at end of file diff --git a/darwin-x86/sample/lambda/BulkDataOperations/src/CSVProcessor.java b/darwin-x86/sample/lambda/BulkDataOperations/src/CSVProcessor.java new file mode 100644 index 0000000..ded9030 --- /dev/null +++ b/darwin-x86/sample/lambda/BulkDataOperations/src/CSVProcessor.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; +import java.util.function.*; +import java.util.regex.Pattern; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import static java.lang.Double.parseDouble; +import static java.util.stream.Collectors.*; + +/** + * CSVProcessor is a tool for processing CSV files. There are several + * command-line options. Consult the {@link #printUsageAndExit} method for + * instructions and command line parameters. This sample shows examples of the + * following features: + * <ul> + * <li>Lambda and bulk operations. Working with streams: map(...), filter(...), + * sorted(...) methods. The collect(...) method with different collectors: + * Collectors.maxBy(...), Collectors.minBy(...), Collectors.toList(), + * Collectors.toCollection(...), Collectors.groupingBy(...), + * Collectors.toDoubleSummaryStatistics(...), and a custom Collector.</li> + * <li>Static method reference for printing values.</li> + * <li>Try-with-resources feature for closing files.</li> + * <li>Switch by String feature.</li> + * <li>Other new APIs: Pattern.asPredicate(), BinaryOperator + * BufferedReader.lines(), Collection.forEach(...), Comparator.comparing(...), + * Comparator.reversed(), Arrays.stream(...).</li> + * </ul> + * + */ +public class CSVProcessor { + + //Number of characters that may be read + private static final int READ_AHEAD_LIMIT = 100_000_000; + + /** + * The main method for the CSVProcessor program. Run the program with an + * empty argument list to see possible arguments. + * + * @param args the argument list for CSVProcessor. + */ + public static void main(String[] args) { + if (args.length < 2) { + printUsageAndExit(); + } + try (BufferedReader br = new BufferedReader( + Files.newBufferedReader(Paths.get(args[args.length - 1])))) { + //Assume that the first line contains column names. + List<String> header = Arrays.stream(br.readLine().split(",")) + .map(String::trim).collect(toList()); + //Calculate an index of the column in question. + int column = getColumnNumber(header, args[1]); + switch (args[0]) { + case "sort": + verifyArgumentNumber(args, 4); + //Define the sort order. + boolean isAsc; + switch (args[2].toUpperCase()) { + case "ASC": + isAsc = true; + break; + case "DESC": + isAsc = false; + break; + default: + printUsageAndExit("Illegal argument" + args[2]); + return;//Should not be reached. + } + /* + * Create a comparator that compares lines by comparing + * values in the specified column. + */ + Comparator<String> cmp + = Comparator.comparing(str -> getCell(str, column), + String.CASE_INSENSITIVE_ORDER); + /* + * sorted(...) is used to sort records. + * forEach(...) is used to output sorted records. + */ + br.lines().sorted(isAsc ? cmp : cmp.reversed()) + .forEach(System.out::println); + break; + case "search": + verifyArgumentNumber(args, 4); + /* + * Records are filtered by a regex. + * forEach(...) is used to output filtered records. + */ + Predicate<String> pattern + = Pattern.compile(args[2]).asPredicate(); + br.lines().filter(str -> pattern.test(getCell(str, column))) + .forEach(System.out::println); + break; + case "groupby": + verifyArgumentNumber(args, 3); + /* + * Group lines by values in the column with collect(...), and + * print with forEach(...) for every distinct value within + * the column. + */ + br.lines().collect( + Collectors.groupingBy(str -> getCell(str, column), + toCollection(TreeSet::new))) + .forEach((str, set) -> { + System.out.println(str + ":"); + set.forEach(System.out::println); + }); + break; + case "stat": + verifyArgumentNumber(args, 3); + + /* + * BufferedReader will be read several times. + * Mark this point to return here after each pass. + * BufferedReader will be read right after the headers line + * because it is already read. + */ + br.mark(READ_AHEAD_LIMIT); + + /* + * Statistics can be collected by a custom collector in one + * pass. One pass is preferable. + */ + System.out.println( + br.lines().collect(new Statistics(column))); + + /* + * Alternatively, statistics can be collected + * by a built-in API in several passes. + * This method demonstrates how separate operations can be + * implemented using a built-in API. + */ + br.reset(); + statInSeveralPasses(br, column); + break; + default: + printUsageAndExit("Illegal argument" + args[0]); + } + } catch (IOException e) { + printUsageAndExit(e.toString()); + } + } + + private static void statInSeveralPasses(BufferedReader br, int column) + throws IOException { + System.out.println("#-----Statistics in several passes-------#"); + //Create a comparator to compare records by the column. + Comparator<String> comparator + = Comparator.comparing( + (String str) -> parseDouble(getCell(str, column))); + //Find max record by using Collectors.maxBy(...) + System.out.println( + "Max: " + br.lines().collect(maxBy(comparator)).get()); + br.reset(); + //Find min record by using Collectors.minBy(...) + System.out.println( + "Min: " + br.lines().collect(minBy(comparator)).get()); + br.reset(); + //Compute the average value and sum with + //Collectors.toDoubleSummaryStatistics(...) + DoubleSummaryStatistics doubleSummaryStatistics + = br.lines().collect(summarizingDouble( + str -> parseDouble(getCell(str, column)))); + System.out.println("Average: " + doubleSummaryStatistics.getAverage()); + System.out.println("Sum: " + doubleSummaryStatistics.getSum()); + } + + private static void verifyArgumentNumber(String[] args, int n) { + if (args.length != n) { + printUsageAndExit("Expected " + n + " arguments but was " + + args.length); + } + } + + private static int getColumnNumber(List<String> header, String name) { + int column = header.indexOf(name); + if (column == -1) { + printUsageAndExit("There is no column with name " + name); + } + return column; + } + + private static String getCell(String record, int column) { + return record.split(",")[column].trim(); + } + + private static void printUsageAndExit(String... str) { + System.out.println("Usages:"); + + System.out.println("CSVProcessor sort COLUMN_NAME ASC|DESC FILE"); + System.out.println("Sort lines by column COLUMN_NAME in CSV FILE\n"); + + System.out.println("CSVProcessor search COLUMN_NAME REGEX FILE"); + System.out.println("Search for REGEX in column COLUMN_NAME in CSV FILE\n"); + + System.out.println("CSVProcessor groupby COLUMN_NAME FILE"); + System.out.println("Split lines into different groups according to column " + + "COLUMN_NAME value\n"); + + System.out.println("CSVProcessor stat COLUMN_NAME FILE"); + System.out.println("Compute max/min/average/sum statistics by column " + + "COLUMN_NAME\n"); + + Arrays.asList(str).forEach(System.err::println); + System.exit(1); + } + + /* + * This is a custom implementation of the Collector interface. + * Statistics are objects gather max,min,sum,average statistics. + */ + private static class Statistics + implements Collector<String, Statistics, Statistics> { + + + /* + * This implementation does not need to be thread safe because + * the parallel implementation of + * {@link java.util.stream.Stream#collect Stream.collect()} + * provides the necessary partitioning and isolation for safe parallel + * execution. + */ + private String maxRecord; + private String minRecord; + + private double sum; + private int lineCount; + private final BinaryOperator<String> maxOperator; + private final BinaryOperator<String> minOperator; + private final int column; + + public Statistics(int column) { + this.column = column; + Comparator<String> cmp = Comparator.comparing( + (String str) -> parseDouble(getCell(str, column))); + maxOperator = BinaryOperator.maxBy(cmp); + minOperator = BinaryOperator.minBy(cmp); + } + + /* + * Process line. + */ + public Statistics accept(String line) { + maxRecord = maxRecord == null + ? line : maxOperator.apply(maxRecord, line); + minRecord = minRecord == null + ? line : minOperator.apply(minRecord, line); + + sum += parseDouble(getCell(line, column)); + lineCount++; + return this; + } + + + /* + * Merge two Statistics. + */ + public Statistics combine(Statistics stat) { + maxRecord = maxOperator.apply(maxRecord, stat.getMaxRecord()); + minRecord = minOperator.apply(minRecord, stat.getMinRecord()); + sum += stat.getSum(); + lineCount += stat.getLineCount(); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("#------Statistics------#\n"); + sb.append("Max: ").append(getMaxRecord()).append("\n"); + sb.append("Min: ").append(getMinRecord()).append("\n"); + sb.append("Sum = ").append(getSum()).append("\n"); + sb.append("Average = ").append(average()).append("\n"); + sb.append("#------Statistics------#\n"); + return sb.toString(); + } + + @Override + public Supplier<Statistics> supplier() { + return () -> new Statistics(column); + } + + @Override + public BiConsumer<Statistics, String> accumulator() { + return Statistics::accept; + } + + @Override + public BinaryOperator<Statistics> combiner() { + return Statistics::combine; + + } + + @Override + public Function<Statistics, Statistics> finisher() { + return stat -> stat; + } + + @Override + public Set<Characteristics> characteristics() { + return EnumSet.of(Characteristics.IDENTITY_FINISH); + } + + private String getMaxRecord() { + return maxRecord; + } + + private String getMinRecord() { + return minRecord; + } + + private double getSum() { + return sum; + } + + private double average() { + return sum / lineCount; + } + + private int getLineCount() { + return lineCount; + } + + } + +} diff --git a/darwin-x86/sample/lambda/BulkDataOperations/src/Grep.java b/darwin-x86/sample/lambda/BulkDataOperations/src/Grep.java new file mode 100644 index 0000000..cb4bdf7 --- /dev/null +++ b/darwin-x86/sample/lambda/BulkDataOperations/src/Grep.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +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.List; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +/** + * Grep prints lines matching a regex. See {@link #printUsageAndExit(String...)} + * method for instructions and command line parameters. This sample shows + * examples of using next features: + * <ul> + * <li>Lambda and bulk operations. Working with streams: + * map(...),filter(...),flatMap(...),limit(...) methods.</li> + * <li>Static method reference for printing values.</li> + * <li>New Collections API forEach(...) method.</li> + * <li>Try-with-resources feature.</li> + * <li>new Files.walk(...), Files.lines(...) API.</li> + * <li>Streams that need to be closed.</li> + * </ul> + * + */ +public class Grep { + + private static void printUsageAndExit(String... str) { + System.out.println("Usage: " + Grep.class.getSimpleName() + + " [OPTION]... PATTERN FILE..."); + System.out.println("Search for PATTERN in each FILE. " + + "If FILE is a directory then whole file tree of the directory" + + " will be processed."); + System.out.println("Example: grep -m 100 'hello world' menu.h main.c"); + System.out.println("Options:"); + System.out.println(" -m NUM: stop analysis after NUM matches"); + Arrays.asList(str).forEach(System.err::println); + System.exit(1); + } + + /** + * The main method for the Grep program. Run program with empty argument + * list to see possible arguments. + * + * @param args the argument list for Grep. + * @throws java.io.IOException If an I/O error occurs. + */ + public static void main(String[] args) throws IOException { + long maxCount = Long.MAX_VALUE; + if (args.length < 2) { + printUsageAndExit(); + } + int i = 0; + //parse OPTIONS + while (args[i].startsWith("-")) { + switch (args[i]) { + case "-m": + try { + maxCount = Long.parseLong(args[++i]); + } catch (NumberFormatException ex) { + printUsageAndExit(ex.toString()); + } + break; + default: + printUsageAndExit("Unexpected option " + args[i]); + } + i++; + } + //parse PATTERN + Pattern pattern = Pattern.compile(args[i++]); + if (i == args.length) { + printUsageAndExit("There are no files for input"); + } + + try { + /* + * First obtain the list of all paths. + * For a small number of arguments there is little to be gained + * by producing this list in parallel. For one argument + * there will be no parallelism. + * + * File names are converted to paths. If a path is a directory then + * Stream is populated with whole file tree of the directory by + * flatMap() method. Files are filtered from directories. + */ + List<Path> files = Arrays.stream(args, i, args.length) + .map(Paths::get) + // flatMap will ensure each I/O-based stream will be closed + .flatMap(Grep::getPathStream) + .filter(Files::isRegularFile) + .collect(toList()); + /* + * Then operate on that list in parallel. + * This is likely to give a more even distribution of work for + * parallel execution. + * + * Lines are extracted from files. Lines are filtered by pattern. + * Stream is limited by number of matches. Each remaining string is + * displayed in std output by method reference System.out::println. + */ + files.parallelStream() + // flatMap will ensure each I/O-based stream will be closed + .flatMap(Grep::path2Lines) + .filter(pattern.asPredicate()) + .limit(maxCount) + .forEachOrdered(System.out::println); + } catch (UncheckedIOException ioe) { + printUsageAndExit(ioe.toString()); + } + } + + /** + * Flattens file system hierarchy into a stream. This code is not inlined + * for the reason of Files.walk() throwing a checked IOException that must + * be caught. + * + * @param path - the file or directory + * @return Whole file tree starting from path, a stream with one element - + * the path itself - if it is a file. + */ + private static Stream<Path> getPathStream(Path path) { + try { + return Files.walk(path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Produces a stream of lines from a file. The result is a stream in order + * to close it later. This code is not inlined for the reason of + * Files.lines() throwing a checked IOException that must be caught. + * + * @param path - the file to read + * @return stream of lines from the file + */ + private static Stream<String> path2Lines(Path path) { + try { + return Files.lines(path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/darwin-x86/sample/lambda/BulkDataOperations/src/PasswordGenerator.java b/darwin-x86/sample/lambda/BulkDataOperations/src/PasswordGenerator.java new file mode 100644 index 0000000..e467798 --- /dev/null +++ b/darwin-x86/sample/lambda/BulkDataOperations/src/PasswordGenerator.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +/** + * Generates password of desired length. See {@link #usage} method + * for instructions and command line parameters. This sample shows usages of: + * <ul> + * <li>Method references.</li> + * <li>Lambda and bulk operations. A stream of random integers is mapped to + * chars, limited by desired length and printed in standard output as password + * string.</li> + * </ul> + * + */ +public class PasswordGenerator { + + private static void usage() { + System.out.println("Usage: PasswordGenerator LENGTH"); + System.out.println( + "Password Generator produces password of desired LENGTH."); + } + + private static final List<Integer> PASSWORD_CHARS = new ArrayList<>(); + + //Valid symbols. + static { + IntStream.rangeClosed('0', '9').forEach(PASSWORD_CHARS::add); // 0-9 + IntStream.rangeClosed('A', 'Z').forEach(PASSWORD_CHARS::add); // A-Z + IntStream.rangeClosed('a', 'z').forEach(PASSWORD_CHARS::add); // a-z + } + + /** + * The main method for the PasswordGenerator program. Run program with empty + * argument list to see possible arguments. + * + * @param args the argument list for PasswordGenerator. + */ + public static void main(String[] args) { + + if (args.length != 1) { + usage(); + return; + } + + long passwordLength; + try { + passwordLength = Long.parseLong(args[0]); + if (passwordLength < 1) { + printMessageAndUsage("Length has to be positive"); + return; + } + } catch (NumberFormatException ex) { + printMessageAndUsage("Unexpected number format" + args[0]); + return; + } + /* + * Stream of random integers is created containing Integer values + * in range from 0 to PASSWORD_CHARS.size(). + * The stream is limited by passwordLength. + * Valid chars are selected by generated index. + */ + new SecureRandom().ints(passwordLength, 0, PASSWORD_CHARS.size()) + .map(PASSWORD_CHARS::get) + .forEach(i -> System.out.print((char) i)); + } + + private static void printMessageAndUsage(String message) { + System.err.println(message); + usage(); + } + +} diff --git a/darwin-x86/sample/lambda/BulkDataOperations/src/WC.java b/darwin-x86/sample/lambda/BulkDataOperations/src/WC.java new file mode 100644 index 0000000..c724f15 --- /dev/null +++ b/darwin-x86/sample/lambda/BulkDataOperations/src/WC.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.function.Consumer; +import java.util.regex.Pattern; + +/** + * WC - Prints newline, word, and character counts for each file. See + * the {@link #usage} method for instructions and command line parameters. This + * sample shows usages of: + * <ul> + * <li>Lambda and bulk operations. Shows how to create a custom collector to + * gather custom statistics. Implements the collection of statistics using a + * built-in API.</li> + * <li>Constructor reference.</li> + * <li>Try-with-resources feature.</li> + * </ul> + * + */ +public class WC { + + //The number of characters that may be read. + private static final int READ_AHEAD_LIMIT = 100_000_000; + + //The pattern for splitting strings by non word characters to get words. + private static final Pattern nonWordPattern = Pattern.compile("\\W"); + + /** + * The main method for the WC program. Run the program with an empty + * argument list to see possible arguments. + * + * @param args the argument list for WC + * @throws java.io.IOException If an input exception occurred. + */ + public static void main(String[] args) throws IOException { + + if (args.length != 1) { + usage(); + return; + } + + try (BufferedReader reader = new BufferedReader( + new FileReader(args[0]))) { + reader.mark(READ_AHEAD_LIMIT); + /* + * Statistics can be gathered in four passes using a built-in API. + * The method demonstrates how separate operations can be + * implemented using a built-in API. + */ + collectInFourPasses(reader); + /* + * Usage of several passes to collect data is not the best way. + * Statistics can be gathered by a custom collector in one pass. + */ + reader.reset(); + collectInOnePass(reader); + } catch (FileNotFoundException e) { + usage(); + System.err.println(e); + } + } + + private static void collectInFourPasses(BufferedReader reader) + throws IOException { + /* + * Input is read as a stream of lines by lines(). + * Every line is turned into a stream of chars by the flatMapToInt(...) + * method. + * Length of the stream is counted by count(). + */ + System.out.println("Character count = " + + reader.lines().flatMapToInt(String::chars).count()); + /* + * Input is read as a stream of lines by lines(). + * Every line is split by nonWordPattern into words by flatMap(...) + * method. + * Empty lines are removed by the filter(...) method. + * Length of the stream is counted by count(). + */ + reader.reset(); + System.out.println("Word count = " + + reader.lines() + .flatMap(nonWordPattern::splitAsStream) + .filter(str -> !str.isEmpty()).count()); + + reader.reset(); + System.out.println("Newline count = " + reader.lines().count()); + /* + * Input is read as a stream of lines by lines(). + * Every line is mapped to its length. + * Maximum of the lengths is calculated. + */ + reader.reset(); + System.out.println("Max line length = " + + reader.lines().mapToInt(String::length).max().getAsInt()); + } + + private static void collectInOnePass(BufferedReader reader) { + /* + * The collect() method has three parameters: + * The first parameter is the {@code WCStatistic} constructor reference. + * collect() will create {@code WCStatistics} instances, where + * statistics will be aggregated. + * The second parameter shows how {@code WCStatistics} will process + * String. + * The third parameter shows how to merge two {@code WCStatistic} + * instances. + * + * Also {@code Collector} can be used, which would be more reusable + * solution. See {@code CSVProcessor} example for how {@code Collector} + * can be implemented. + * + * Note that the any performance increase when going parallel will + * depend on the size of the input (lines) and the cost per-element. + */ + WCStatistics wc = reader.lines().parallel() + .collect(WCStatistics::new, + WCStatistics::accept, + WCStatistics::combine); + System.out.println(wc); + } + + private static void usage() { + System.out.println("Usage: " + WC.class.getSimpleName() + " FILE"); + System.out.println("Print newline, word," + + " character counts and max line length for FILE."); + } + + private static class WCStatistics implements Consumer<String> { + /* + * @implNote This implementation does not need to be thread safe because + * the parallel implementation of + * {@link java.util.stream.Stream#collect Stream.collect()} + * provides the necessary partitioning and isolation for safe parallel + * execution. + */ + + private long characterCount; + private long lineCount; + private long wordCount; + private long maxLineLength; + + + /* + * Processes line. + */ + @Override + public void accept(String line) { + characterCount += line.length(); + lineCount++; + wordCount += nonWordPattern.splitAsStream(line) + .filter(str -> !str.isEmpty()).count(); + maxLineLength = Math.max(maxLineLength, line.length()); + } + + /* + * Merges two WCStatistics. + */ + public void combine(WCStatistics stat) { + wordCount += stat.wordCount; + lineCount += stat.lineCount; + characterCount += stat.characterCount; + maxLineLength = Math.max(maxLineLength, stat.maxLineLength); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("#------WCStatistic------#\n"); + sb.append("Character count = ").append(characterCount).append('\n'); + sb.append("Word count = ").append(wordCount).append('\n'); + sb.append("Newline count = ").append(lineCount).append('\n'); + sb.append("Max line length = ").append(maxLineLength).append('\n'); + return sb.toString(); + } + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/ArrayIterator.java b/darwin-x86/sample/lambda/DefaultMethods/ArrayIterator.java new file mode 100644 index 0000000..2eca801 --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/ArrayIterator.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * The code sample illustrates the usage of default methods in the JDK 8. Most + * implementations of {@link Iterator} don't provide a useful + * {@link Iterator#remove()} method, however, + * they still have to implement this method to throw + * an UnsupportedOperationException. With the default method, the same + * default behavior in interface Iterator itself can be provided. + */ +public class ArrayIterator { + + /** Close the constructor because ArrayIterator is part of the utility + * class. + */ + protected ArrayIterator() { + throw new UnsupportedOperationException(); + } + + /** + * Returns an iterator that goes over the elements in the array. + * + * @param <E> type of an array element + * @param array source array to iterate over it + * @return an iterator that goes over the elements in the array + */ + public static <E> Iterator<E> iterator(final E[] array) { + return new Iterator<E>() { + /** + * Index of the current position + * + */ + private int index = 0; + + /** + * Returns the next element in the iteration + * + * @return the next element in the iteration + * @throws NoSuchElementException if the iteration has no more + * elements + */ + @Override + public boolean hasNext() { + return (index < array.length); + } + + /** + * Returns {@code true} if the iteration has more elements. (In + * other words, returns {@code true} if {@link #next} returns + * an element, rather than throwing an exception.) + * + * @return {@code true} if the iteration has more elements + */ + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return array[index++]; + } + + /** + * This method does not need to be overwritten in JDK 8. + */ + //@Override + //public void remove() { + // throw UnsupportedOperationException( + // "Arrays don't support remove.") + //} + }; + } + + /** + * Sample usage of the ArrayIterator + * + * @param args command-line arguments + */ + public static void main(final String[] args) { + Iterator<String> it = ArrayIterator.iterator( + new String[]{"one", "two", "three"}); + + while (it.hasNext()) { + System.out.println(it.next()); + } + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/DiamondInheritance.java b/darwin-x86/sample/lambda/DefaultMethods/DiamondInheritance.java new file mode 100644 index 0000000..9214d58 --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/DiamondInheritance.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * This sample diamond interface inheritance with <b>default methods</b>. + * If there's not already a unique method implementation to inherit, + * you must provide it. The inheritance diagram is similar to the following: + * <pre> + * Animal + * / \ + * Horse Bird + * \ / + * Pegasus + * </pre> + * + * Both {@link Horse} and {@link Bird} interfaces implements the <code>go</code> + * method. The {@link Pegasus} class have to overrides the + * <code>go</code> method. + * + * The new syntax of super-call is used here: + * <pre> + * <interface_name>.super.<method>(...); + * For example: Horse.super.go(); + * </pre> So, Pegasus moves like a horse. + */ +public class DiamondInheritance { + + /** + * Base interface to illustrate the diamond inheritance. + * + * @see DiamondInheritance + */ + public interface Animal { + + /** + * Return string representation of the "go" action for concrete animal + * + * @return string representation of the "go" action for concrete animal + */ + String go(); + } + + /** + * Interface to illustrate the diamond inheritance. + * + * @see DiamondInheritance + */ + public interface Horse extends Animal { + + /** + * Return string representation of the "go" action for horse + * + * @return string representation of the "go" action for horse + */ + @Override + default String go() { + return this.getClass().getSimpleName() + " walks on four legs"; + } + } + + /** + * Interface to illustrate the diamond inheritance. + * + * @see DiamondInheritance + */ + public interface Bird extends Animal { + + /** + * Return string representation of the "go" action for bird + * + * @return string representation of the "go" action for bird + */ + @Override + default String go() { + return this.getClass().getSimpleName() + " walks on two legs"; + } + + /** + * Return string representation of the "fly" action for bird + * + * @return string representation of the "fly" action for bird + */ + default String fly() { + return "I can fly"; + } + } + + /** + * Class to illustrate the diamond inheritance. Pegasus must mix horse and + * bird behavior. + * + * @see DiamondInheritance + */ + public static class Pegasus implements Horse, Bird { + + /** + * Return string representation of the "go" action for the fictitious + * creature Pegasus + * + * @return string representation of the "go" action for the fictitious + * creature Pegasus + */ + @Override + public String go() { + return Horse.super.go(); + } + } + + /** + * Illustrate the behavior of the {@link Pegasus} class + * + * @param args command line arguments + */ + public static void main(final String[] args) { + System.out.println(new Pegasus().go()); + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/Inheritance.java b/darwin-x86/sample/lambda/DefaultMethods/Inheritance.java new file mode 100644 index 0000000..961de2c --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/Inheritance.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * The sample illustrates rules to resolve conflicts between inheritance + * candidates with <b>default methods</b>. There are two simple rules: + * <ul> + * <li>Class wins. If the superclass has a concrete or abstract declaration of + * this method, then it is preferred over all defaults.</li> + * <li>Subtype wins. If an interface extends another interface, and both provide + * a default, then the more specific interface wins. </li> + * </ul> + */ +public class Inheritance { + + /** + * The behavior of an creature that can swim + */ + public interface Swimable { + + /** + * Return string representation of the swim action for a creature that + * can swim + * + * @return string representation of the swim action for a creature + * that can swim + */ + default String swim() { + return "I can swim."; + } + } + + /** + * The abstract class that overrides {@link #swim} method + */ + public abstract static class Fish implements Swimable { + + /** + * Return string representation of the swim action for a fish + * + * @return string representation of the swim action for a fish + */ + @Override + public String swim() { + return this.getClass().getSimpleName() + " swims under water"; + } + } + + /** + * This class is used for the illustration rule of 1. See the source code + * of the {@link #main} method. + * <pre> + * System.out.println(new Tuna().swim()); //"Tuna swims under water" output is suspected here + * </pre> + */ + public static class Tuna extends Fish implements Swimable { + } + + /** + * The behavior of an creature that can dive: the interface that overrides + * {@link #swim} method (subtype of {@link Swimable}) + */ + public interface Diveable extends Swimable { + + /** + * Return string representation of the swim action for a creature that + * can dive + * + * @return string representation of the swim action for a creature + * that can dive + */ + @Override + default String swim() { + return "I can swim on the surface of the water."; + } + + /** + * Return string representation of the dive action for a creature that + * can dive + * + * @return string representation of the dive action for a creature + * that can dive + */ + default String dive() { + return "I can dive."; + } + } + + /** + * This class is used for the illustration of rule 2. See the source code + * of the {@link #main} method + * <pre> + * //"I can swim on the surface of the water." output is suspected here + * System.out.println(new Duck().swim()); + * </pre> + */ + public static class Duck implements Swimable, Diveable { + } + + /** + * Illustrate behavior of the classes: {@link Tuna} and {@link Duck} + * + * @param args command line arguments + */ + public static void main(final String[] args) { + // Illustrates rule 1. The Fish.swim() implementation wins + //"Tuna swims under water" is output + System.out.println(new Tuna().swim()); + + // Illustrates rule 2. The Diveable.swim() implementation wins + //"I can swim on the surface of the water." is output + System.out.println(new Duck().swim()); + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/MixIn.java b/darwin-x86/sample/lambda/DefaultMethods/MixIn.java new file mode 100644 index 0000000..d9ed81d --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/MixIn.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.io.IOException; +import java.lang.reflect.Field; + +/** + * The example illustrates how to use the default method for mixin. + * @see BuildType + * @see Debuggable + */ +public class MixIn { + + /** + * Implement this interface for a class that must be in debug print + */ + public interface Debuggable { + + /** + * Print the class name and all fields to a string. Uses reflection to + * obtain and access fields of this object. + * + * @return the string formatted like the following: <pre> + * State of the: <Class Name> + * <member name> : <value> + * ... + * </pre> + */ + default String toDebugString() { + StringBuilder sb = new StringBuilder(); + sb.append("State of the: ").append( + this.getClass().getSimpleName()).append("\n"); + for (Class cls = this.getClass(); + cls != null; + cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + try { + f.setAccessible(true); + sb.append(f.getName()).append(" : "). + append(f.get(this)).append("\n"); + } catch (IllegalAccessException e) { + } + } + } + return sb.toString(); + } + } + + /** + * Sample exception class to demonstrate mixin. This enum inherits the + * behavior of the {@link Debuggable} + */ + public static enum BuildType implements Debuggable { + + BUILD(0, "-build"), + PLAN(0, "-plan"), + EXCLUDE(1, "-exclude"), + TOTAL(2, "-total"); + + private final int compareOrder; + private final String pathSuffix; + + private BuildType(int compareOrder, String pathSuffix) { + this.compareOrder = compareOrder; + this.pathSuffix = pathSuffix; + } + + public int getCompareOrder() { + return compareOrder; + } + + public String getPathSuffix() { + return pathSuffix; + } + } + + /** + * Illustrate the behavior of the MixClass + * + * @param args command-line arguments + * @throws java.io.IOException internal demo error + */ + public static void main(final String[] args) throws IOException { + System.out.println(BuildType.BUILD.toDebugString()); + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/Reflection.java b/darwin-x86/sample/lambda/DefaultMethods/Reflection.java new file mode 100644 index 0000000..78424a2 --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/Reflection.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * The code sample illustrates changes in the reflection API linked + * <b>default methods</b>. Since Java SE 8, a new method is added into the class + * <b><code>java.lang.reflect.Method</code></b>, with which you can reflectively + * determine whether or not a default method provided by an interface + * (<b><code>Method.isDefault()</code></b>). + */ +public class Reflection { + + /** + * Base interface to illustrate the new reflection API. + * + * @see Dog + */ + public interface Animal { + + /** + * Return string representation of the eat action for Animal + * + * @return string representation of the eat action for Animal + */ + default String eat() { + return this.getClass().getSimpleName() + + " eats like an ordinary animal"; + } + + /** + * Return string representation of the sleep action for Animal + * + * @return string representation of the sleep action for Animal + */ + default String sleep() { + return this.getClass().getSimpleName() + + " sleeps like an ordinary animal"; + } + + /** + * Return string representation of the go action for Animal + * + * @return string representation of the go action for Animal + */ + String go(); + } + + /** + * Dog class to illustrate the new reflection API. You can see that: + * <ul> + * <li> the {@link #go} and {@link #sleep} methods are not default. + * {@link #go} is not the default implementation and the {@link #sleep} + * method implementation wins as subtype (according with {@link Inheritance} + * rule. 2) </li> + * <li> the {@link #eat} is a simple default method that is not overridden + * in this class. + * </li> + * </ul> + */ + public static class Dog implements Animal { + + /** + * Return string representation of the go action for Dog + * + * @return string representation of the go action for Dog + */ + @Override + public String go() { + return "Dog walks on four legs"; + } + + /** + * Return string representation of the sleep action for Dog + * + * @return string representation of the sleep action for Dog + */ + @Override + public String sleep() { + return "Dog sleeps"; + } + } + + /** + * Illustrate the usage of the method java.lang.reflect.Method.isDefault() + * + * @param args command-line arguments + * @throws NoSuchMethodException internal demo error + */ + public static void main(final String[] args) throws NoSuchMethodException { + Dog dog = new Dog(); + Stream.of(Dog.class.getMethod("eat"), Dog.class.getMethod("go"), Dog.class.getMethod("sleep")) + .forEach((m) -> { + System.out.println("Method name: " + m.getName()); + System.out.println(" isDefault: " + m.isDefault()); + System.out.print(" invoke: "); + try { + m.invoke(dog); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + } + System.out.println(); + }); + } +} diff --git a/darwin-x86/sample/lambda/DefaultMethods/SimplestUsage.java b/darwin-x86/sample/lambda/DefaultMethods/SimplestUsage.java new file mode 100644 index 0000000..a971858 --- /dev/null +++ b/darwin-x86/sample/lambda/DefaultMethods/SimplestUsage.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * The sample illustrates the simplest use case of the <b>default methods</b>. + */ +public class SimplestUsage { + + /** + * The Animal interface provides the default implementation + * of the {@link #eat} method. + */ + public interface Animal { + + /** + * Return string representation of the eat action for Animal + * + * @return string representation of the eat action for Animal + */ + default String eat() { + return this.getClass().getSimpleName() + + " eats like an ordinary animal"; + } + } + + /** + * The Dog class doesn't have its own implementation of the {@link #eat} + * method and uses the default implementation. + */ + public static class Dog implements Animal { + } + + /** + * The Mosquito class implements {@link #eat} method, its own implementation + * overrides the default implementation. + * + */ + public static class Mosquito implements Animal { + + /** + * Return string representation of the eat action for Mosquito + * + * @return string representation of the eat action for Mosquito + */ + @Override + public String eat() { + return "Mosquito consumes blood"; + } + } + + /** + * Illustrate behavior of the classes: {@link Dog} and {@link Mosquito} + * + * @param args command-line arguments + */ + public static void main(String[] args) { + // "Dog eats like an ordinary animal" is output + System.out.println(new Dog().eat()); + + // "Mosquito consumes blood" is output + System.out.println(new Mosquito().eat()); + } +} diff --git a/darwin-x86/sample/nbproject/project.xml b/darwin-x86/sample/nbproject/project.xml new file mode 100644 index 0000000..8417326 --- /dev/null +++ b/darwin-x86/sample/nbproject/project.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project xmlns="http://www.netbeans.org/ns/project/1"> + <type>org.netbeans.modules.ant.freeform</type> + <configuration> + <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1"> + <name>JDK Samples</name> + <view> + <items/> + </view> + <subprojects> + <project>jmx/jmx-scandir</project> + <project>scripting/scriptpad</project> + <project>webservices/EbayClient</project> + <project>webservices/EbayServer</project> + </subprojects> + </general-data> + </configuration> +</project> diff --git a/darwin-x86/sample/nio/chatserver/ChatServer.java b/darwin-x86/sample/nio/chatserver/ChatServer.java new file mode 100644 index 0000000..f807aa1 --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/ChatServer.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.StandardSocketOptions; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Implements a chat server, this class holds the list of {@code clients} connected to the server. + * It sets up a server socket using AsynchronousServerSocketChannel listening to a specified port. + */ +public class ChatServer implements Runnable { + private final List<Client> connections = Collections.synchronizedList(new ArrayList<Client>()); + private int port; + private final AsynchronousServerSocketChannel listener; + private final AsynchronousChannelGroup channelGroup; + + /** + * + * @param port to listen to + * @throws java.io.IOException when failing to start the server + */ + public ChatServer(int port) throws IOException { + channelGroup = AsynchronousChannelGroup.withFixedThreadPool(Runtime.getRuntime().availableProcessors(), + Executors.defaultThreadFactory()); + this.port = port; + listener = createListener(channelGroup); + } + + /** + * + * @return The socket address that the server is bound to + * @throws java.io.IOException if an I/O error occurs + */ + public SocketAddress getSocketAddress() throws IOException { + return listener.getLocalAddress(); + } + + /** + * Start accepting connections + */ + public void run() { + + // call accept to wait for connections, tell it to call our CompletionHandler when there + // is a new incoming connection + listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() { + @Override + public void completed(AsynchronousSocketChannel result, Void attachment) { + // request a new accept and handle the incoming connection + listener.accept(null, this); + handleNewConnection(result); + } + + @Override + public void failed(Throwable exc, Void attachment) { + } + }); + } + + /** + * Shuts down the server + * @throws InterruptedException if terminated while waiting for shutdown + * @throws IOException if failing to shutdown the channel group + */ + public void shutdown() throws InterruptedException, IOException { + channelGroup.shutdownNow(); + channelGroup.awaitTermination(1, TimeUnit.SECONDS); + } + + /* + * Creates a listener and starts accepting connections + */ + private AsynchronousServerSocketChannel createListener(AsynchronousChannelGroup channelGroup) throws IOException { + final AsynchronousServerSocketChannel listener = openChannel(channelGroup); + listener.setOption(StandardSocketOptions.SO_REUSEADDR, true); + listener.bind(new InetSocketAddress(port)); + return listener; + } + + private AsynchronousServerSocketChannel openChannel(AsynchronousChannelGroup channelGroup) throws IOException { + return AsynchronousServerSocketChannel.open(channelGroup); + } + + /** + * Creates a new client and adds it to the list of connections. + * Sets the clients handler to the initial state of NameReader + * + * @param channel the newly accepted channel + */ + private void handleNewConnection(AsynchronousSocketChannel channel) { + Client client = new Client(channel, new ClientReader(this, new NameReader(this))); + try { + channel.setOption(StandardSocketOptions.TCP_NODELAY, true); + } catch (IOException e) { + // ignore + } + connections.add(client); + client.run(); + } + + /** + * Sends a message to all clients except the source. + * The method is synchronized as it is desired that messages are sent to + * all clients in the same order as received. + * + * @param client the message source + * @param message the message to be sent + */ + public void writeMessageToClients(Client client, String message) { + synchronized (connections) { + for (Client clientConnection : connections) { + if (clientConnection != client) { + clientConnection.writeMessageFrom(client, message); + } + } + } + } + + public void removeClient(Client client) { + connections.remove(client); + } + + private static void usage() { + System.err.println("ChatServer [-port <port number>]"); + System.exit(1); + } + + public static void main(String[] args) throws IOException { + int port = 5000; + if (args.length != 0 && args.length != 2) { + usage(); + } else if (args.length == 2) { + try { + if (args[0].equals("-port")) { + port = Integer.parseInt(args[1]); + } else { + usage(); + } + } catch (NumberFormatException e) { + usage(); + } + } + System.out.println("Running on port " + port); + new ChatServer(port).run(); + } +} diff --git a/darwin-x86/sample/nio/chatserver/Client.java b/darwin-x86/sample/nio/chatserver/Client.java new file mode 100644 index 0000000..31ee034 --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/Client.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.CompletionHandler; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Client represents a remote connection to the chat server. + * It contains methods for reading and writing messages from the + * channel. + * Messages are considered to be separated by newline, so incomplete + * messages are buffered in the {@code Client}. + * + * All reads and writes are asynchronous and uses the nio2 asynchronous + * elements. + */ +class Client { + private final AsynchronousSocketChannel channel; + private AtomicReference<ClientReader> reader; + private String userName; + private final StringBuilder messageBuffer = new StringBuilder(); + + private final Queue<ByteBuffer> queue = new LinkedList<ByteBuffer>(); + private boolean writing = false; + + public Client(AsynchronousSocketChannel channel, ClientReader reader) { + this.channel = channel; + this.reader = new AtomicReference<ClientReader>(reader); + } + + /** + * Enqueues a write of the buffer to the channel. + * The call is asynchronous so the buffer is not safe to modify after + * passing the buffer here. + * + * @param buffer the buffer to send to the channel + */ + private void writeMessage(final ByteBuffer buffer) { + boolean threadShouldWrite = false; + + synchronized(queue) { + queue.add(buffer); + // Currently no thread writing, make this thread dispatch a write + if (!writing) { + writing = true; + threadShouldWrite = true; + } + } + + if (threadShouldWrite) { + writeFromQueue(); + } + } + + private void writeFromQueue() { + ByteBuffer buffer; + + synchronized (queue) { + buffer = queue.poll(); + if (buffer == null) { + writing = false; + } + } + + // No new data in buffer to write + if (writing) { + writeBuffer(buffer); + } + } + + private void writeBuffer(ByteBuffer buffer) { + channel.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() { + @Override + public void completed(Integer result, ByteBuffer buffer) { + if (buffer.hasRemaining()) { + channel.write(buffer, buffer, this); + } else { + // Go back and check if there is new data to write + writeFromQueue(); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + } + }); + } + + /** + * Sends a message + * @param string the message + */ + public void writeStringMessage(String string) { + writeMessage(ByteBuffer.wrap(string.getBytes())); + } + + /** + * Send a message from a specific client + * @param client the message is sent from + * @param message to send + */ + public void writeMessageFrom(Client client, String message) { + if (reader.get().acceptsMessages()) { + writeStringMessage(client.getUserName() + ": " + message); + } + } + + /** + * Enqueue a read + * @param completionHandler callback on completed read + */ + public void read(CompletionHandler<Integer, ? super ByteBuffer> completionHandler) { + ByteBuffer input = ByteBuffer.allocate(256); + if (!channel.isOpen()) { + return; + } + channel.read(input, input, completionHandler); + } + + /** + * Closes the channel + */ + public void close() { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Run the current states actions. + */ + public void run() { + reader.get().run(this); + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public void setReader(ClientReader reader) { + this.reader.set(reader); + } + + public String getUserName() { + return userName; + } + + public void appendMessage(String message) { + synchronized (messageBuffer) { + messageBuffer.append(message); + } + } + + /** + * @return the next newline separated message in the buffer. null is returned if the buffer + * doesn't contain any newline. + */ + public String nextMessage() { + synchronized(messageBuffer) { + int nextNewline = messageBuffer.indexOf("\n"); + if (nextNewline == -1) { + return null; + } + String message = messageBuffer.substring(0, nextNewline + 1); + messageBuffer.delete(0, nextNewline + 1); + return message; + } + } +} diff --git a/darwin-x86/sample/nio/chatserver/ClientReader.java b/darwin-x86/sample/nio/chatserver/ClientReader.java new file mode 100644 index 0000000..822125a --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/ClientReader.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; + +/** + * Handles a cycle of reading / writing on the {@code Client}. + */ +class ClientReader { + private final DataReader callback; + private final ChatServer chatServer; + + ClientReader(ChatServer chatServer, DataReader callback) { + this.chatServer = chatServer; + this.callback = callback; + } + + public boolean acceptsMessages() { + return callback.acceptsMessages(); + } + + /** + * Runs a cycle of doing a beforeRead action and then enqueuing a new + * read on the client. Handles closed channels and errors while reading. + * If the client is still connected a new round of actions are called. + */ + public void run(final Client client) { + callback.beforeRead(client); + client.read(new CompletionHandler<Integer, ByteBuffer>() { + @Override + public void completed(Integer result, ByteBuffer buffer) { + // if result is negative or zero the connection has been closed or something gone wrong + if (result < 1) { + client.close(); + System.out.println("Closing connection to " + client); + chatServer.removeClient(client); + } else { + callback.onData(client, buffer, result); + // enqueue next round of actions + client.run(); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + client.close(); + chatServer.removeClient(client); + } + }); + } +} diff --git a/darwin-x86/sample/nio/chatserver/DataReader.java b/darwin-x86/sample/nio/chatserver/DataReader.java new file mode 100644 index 0000000..8858c9f --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/DataReader.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.ByteBuffer; + +public interface DataReader { + void beforeRead(Client client); + void onData(Client client, ByteBuffer buffer, int bytes); + boolean acceptsMessages(); +} diff --git a/darwin-x86/sample/nio/chatserver/MessageReader.java b/darwin-x86/sample/nio/chatserver/MessageReader.java new file mode 100644 index 0000000..81c370b --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/MessageReader.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.ByteBuffer; + +/** + * Writes all messages in our buffer to the other clients + * and appends new data read from the socket to our buffer + */ +class MessageReader implements DataReader { + private final ChatServer chatServer; + + public MessageReader(ChatServer chatServer) { + this.chatServer = chatServer; + } + + public boolean acceptsMessages() { + return true; + } + + /** + * Write all full messages in our buffer to + * the other clients + * + * @param client the client to read messages from + */ + @Override + public void beforeRead(Client client) { + // Check if we have any messages buffered and send them + String message = client.nextMessage(); + while (message != null) { + chatServer.writeMessageToClients(client, message); + message = client.nextMessage(); + } + } + + /** + * Append the read buffer to the clients message buffer + * @param client the client to append messages to + * @param buffer the buffer we received from the socket + * @param bytes the number of bytes read into the buffer + */ + @Override + public void onData(Client client, ByteBuffer buffer, int bytes) { + buffer.flip(); + // Just append the message on the buffer + client.appendMessage(new String(buffer.array(), 0, bytes)); + } +} diff --git a/darwin-x86/sample/nio/chatserver/NameReader.java b/darwin-x86/sample/nio/chatserver/NameReader.java new file mode 100644 index 0000000..341d4da --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/NameReader.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.ByteBuffer; + +/** + * The first state a newly connected {@code Client} is in, this + * handles writing out the welcoming message and reads the response + * up to a newline. When a newline character have been received + * it changes the handler from NameReader to MessageReader on the + * client. + */ +class NameReader implements DataReader { + private final StringBuilder buffer = new StringBuilder(); + private final ChatServer chatServer; + private boolean once = true; + private static final String NEWLINE = "\n"; + + public NameReader(ChatServer chatServer) { + this.chatServer = chatServer; + } + + /** + * Writes the welcoming message to the client the first time this method + * is called. + * + * @param client the client to receive the message + */ + @Override + public void beforeRead(Client client) { + // if it is a long name that takes more than one read we only want to display Name: once. + if (once) { + client.writeStringMessage("Name: "); + once = false; + } + } + + public boolean acceptsMessages() { + return false; + } + + /** + * Receives incoming data from the socket, searches for a newline + * and tries to set the username if one is found + */ + @Override + public void onData(Client client, ByteBuffer buffer, int bytes) { + buffer.flip(); + String name; + name = this.buffer.append(new String(buffer.array(), 0, bytes)).toString(); + if (name.contains(NEWLINE)) { + onUserNameRead(client, name); + } + } + + /** + * Splits the name on the newlines, takes the first as the username + * and appends everything else to the clients message buffer. + * Sets the clients handler to MessageReader. + * + * @param client the client to set the username for + * @param name the string containing the buffered input + */ + private void onUserNameRead(Client client, String name) { + String[] strings = name.split(NEWLINE, 2); + client.setUserName(strings[0].trim()); + sendRemainingParts(client, strings); + client.setReader(new ClientReader(chatServer, new MessageReader(chatServer))); + client.writeStringMessage("Welcome " + client.getUserName() + "\n"); + } + + /** + * Appends the remaining parts to the clients message buffer + * + * @param client the client + * @param strings the messages to append to the buffer + */ + private void sendRemainingParts(Client client, String[] strings) { + for (int i = 1; i < strings.length; ++i) { + client.appendMessage(strings[i]); + } + } +} diff --git a/darwin-x86/sample/nio/chatserver/README.txt b/darwin-x86/sample/nio/chatserver/README.txt new file mode 100644 index 0000000..ec9b476 --- /dev/null +++ b/darwin-x86/sample/nio/chatserver/README.txt @@ -0,0 +1,62 @@ +A Simple Chat Server Example + +INTRODUCTION +============ +This directory contains a very simple chat server, the server takes input from a +socket ("user") and sends it to all other connected sockets ("users") along with +the provided name the user was asked for when first connecting. + +The server was written to demonstrate the asynchronous I/O API in JDK 7. +The sample assumes the reader has some familiarity with the subject matter. + +SETUP +===== + +The server must be built with version 7 (or later) of the JDK. +The server is built with: + + % mkdir build + % javac -source 7 -target 7 -d build *.java + +EXECUTION +========= + + % java -classpath build ChatServer [-port <port number>] + + Usage: ChatServer [options] + options: + -port port port number + default: 5000 + +CLIENT EXECUTION +================ + +No client binary is included in the sample. +Connections can be made using for example the telnet command or any program +that supports a raw TCP connection to a port. + +SOURCE CODE OVERVIEW +==================== +ChatServer is the main class, it handles the startup and handles incoming +connections on the listening sockets. It keeps a list of connected client +and provides methods for sending a message to them. + +Client represents a connected user, it provides methods for reading/writing +from/to the underlying socket. It also contains a buffer of input read from +the user. + +DataReader provides the interface of the two states a user can +be in. Waiting for a name (and not receiving any messages while doing so, implemented +by NameReader) and waiting for messages from the user (implemented by MessageReader). + +ClientReader contains the "main loop" for a connected client. + +NameReader is the initial state for a new client, it sends the user a string and +waits for a response before changing the state to MessageReader. + +MessageReader is the main state for a client, it checks for new messages to send to +other clients and reads messages from the client. + +FINALLY +======= +This is a sample: it is not production quality and isn't optimized for performance. diff --git a/darwin-x86/sample/nio/file/AclEdit.java b/darwin-x86/sample/nio/file/AclEdit.java new file mode 100644 index 0000000..90af865 --- /dev/null +++ b/darwin-x86/sample/nio/file/AclEdit.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.*; +import java.util.regex.Pattern; + +/** + * Sample utility for editing a file's ACL. + */ + +public class AclEdit { + + // parse string as list of ACE permissions separated by / + static Set<AclEntryPermission> parsePermissions(String permsString) { + Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>(); + String[] result = permsString.split("/"); + for (String s : result) { + if (s.equals("")) + continue; + try { + perms.add(AclEntryPermission.valueOf(s.toUpperCase())); + } catch (IllegalArgumentException x) { + System.err.format("Invalid permission '%s'\n", s); + System.exit(-1); + } + } + return perms; + } + + // parse string as list of ACE flags separated by / + static Set<AclEntryFlag> parseFlags(String flagsString) { + Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>(); + String[] result = flagsString.split("/"); + for (String s : result) { + if (s.equals("")) + continue; + try { + flags.add(AclEntryFlag.valueOf(s.toUpperCase())); + } catch (IllegalArgumentException x) { + System.err.format("Invalid flag '%s'\n", s); + System.exit(-1); + } + } + return flags; + } + + // parse ACE type + static AclEntryType parseType(String typeString) { + // FIXME: support audit and alarm types in the future + if (typeString.equalsIgnoreCase("allow")) + return AclEntryType.ALLOW; + if (typeString.equalsIgnoreCase("deny")) + return AclEntryType.DENY; + System.err.format("Invalid type '%s'\n", typeString); + System.exit(-1); + return null; // keep compiler happy + } + + /** + * Parse string of the form: + * [user|group:]<username|groupname>:<perms>[:flags]:<allow|deny> + */ + static AclEntry parseAceString(String s, + UserPrincipalLookupService lookupService) + { + String[] result = s.split(":"); + + // must have at least 3 components (username:perms:type) + if (result.length < 3) + usage(); + + int index = 0; + int remaining = result.length; + + // optional first component can indicate user or group type + boolean isGroup = false; + if (result[index].equalsIgnoreCase("user") || + result[index].equalsIgnoreCase("group")) + { + if (--remaining < 3) + usage(); + isGroup = result[index++].equalsIgnoreCase("group"); + } + + // user and permissions required + String userString = result[index++]; remaining--; + String permsString = result[index++]; remaining--; + + // flags are optional + String flagsString = ""; + String typeString = null; + if (remaining == 1) { + typeString = result[index++]; + } else { + if (remaining == 2) { + flagsString = result[index++]; + typeString = result[index++]; + } else { + usage(); + } + } + + // lookup UserPrincipal + UserPrincipal user = null; + try { + user = (isGroup) ? + lookupService.lookupPrincipalByGroupName(userString) : + lookupService.lookupPrincipalByName(userString); + } catch (UserPrincipalNotFoundException x) { + System.err.format("Invalid %s '%s'\n", + ((isGroup) ? "group" : "user"), + userString); + System.exit(-1); + } catch (IOException x) { + System.err.format("Lookup of '%s' failed: %s\n", userString, x); + System.exit(-1); + } + + // map string representation of permissions, flags, and type + Set<AclEntryPermission> perms = parsePermissions(permsString); + Set<AclEntryFlag> flags = parseFlags(flagsString); + AclEntryType type = parseType(typeString); + + // build the ACL entry + return AclEntry.newBuilder() + .setType(type) + .setPrincipal(user) + .setPermissions(perms).setFlags(flags).build(); + } + + static void usage() { + System.err.println("usage: java AclEdit [ACL-operation] file"); + System.err.println(""); + System.err.println("Example 1: Prepends access control entry to the begining of the myfile's ACL"); + System.err.println(" java AclEdit A+alice:read_data/read_attributes:allow myfile"); + System.err.println(""); + System.err.println("Example 2: Remove the entry at index 6 of myfile's ACL"); + System.err.println(" java AclEdit A6- myfile"); + System.err.println(""); + System.err.println("Example 3: Replace the entry at index 2 of myfile's ACL"); + System.err.println(" java AclEdit A2=bob:write_data/append_data:deny myfile"); + System.exit(-1); + } + + static enum Action { + PRINT, + ADD, + REMOVE, + REPLACE; + } + + /** + * Main class: parses arguments and prints or edits ACL + */ + public static void main(String[] args) throws IOException { + Action action = null; + int index = -1; + String entryString = null; + + // parse arguments + if (args.length < 1 || args[0].equals("-help") || args[0].equals("-?")) + usage(); + + if (args.length == 1) { + action = Action.PRINT; + } else { + String s = args[0]; + + // A[index]+entry + if (Pattern.matches("^A[0-9]*\\+.*", s)) { + String[] result = s.split("\\+", 2); + if (result.length == 2) { + if (result[0].length() < 2) { + index = 0; + } else { + index = Integer.parseInt(result[0].substring(1)); + } + entryString = result[1]; + action = Action.ADD; + } + } + + // Aindex- + if (Pattern.matches("^A[0-9]+\\-", s)) { + String[] result = s.split("\\-", 2); + if (result.length == 2) { + index = Integer.parseInt(result[0].substring(1)); + entryString = result[1]; + action = Action.REMOVE; + } + } + + // Aindex=entry + if (Pattern.matches("^A[0-9]+=.*", s)) { + String[] result = s.split("=", 2); + if (result.length == 2) { + index = Integer.parseInt(result[0].substring(1)); + entryString = result[1]; + action = Action.REPLACE; + } + } + } + if (action == null) + usage(); + + int fileArg = (action == Action.PRINT) ? 0 : 1; + Path file = Paths.get(args[fileArg]); + + // read file's ACL + AclFileAttributeView view = + Files.getFileAttributeView(file, AclFileAttributeView.class); + if (view == null) { + System.err.println("ACLs not supported on this platform"); + System.exit(-1); + } + List<AclEntry> acl = view.getAcl(); + + switch (action) { + // print ACL + case PRINT : { + for (int i=0; i<acl.size(); i++) { + System.out.format("%5d: %s\n", i, acl.get(i)); + } + break; + } + + // add ACE to existing ACL + case ADD: { + AclEntry entry = parseAceString(entryString, file + .getFileSystem().getUserPrincipalLookupService()); + if (index >= acl.size()) { + acl.add(entry); + } else { + acl.add(index, entry); + } + view.setAcl(acl); + break; + } + + // remove ACE + case REMOVE: { + if (index >= acl.size()) { + System.err.format("Index '%d' is invalid", index); + System.exit(-1); + } + acl.remove(index); + view.setAcl(acl); + break; + } + + // replace ACE + case REPLACE: { + if (index >= acl.size()) { + System.err.format("Index '%d' is invalid", index); + System.exit(-1); + } + AclEntry entry = parseAceString(entryString, file + .getFileSystem().getUserPrincipalLookupService()); + acl.set(index, entry); + view.setAcl(acl); + break; + } + } + } +} diff --git a/darwin-x86/sample/nio/file/Chmod.java b/darwin-x86/sample/nio/file/Chmod.java new file mode 100644 index 0000000..05c16b9 --- /dev/null +++ b/darwin-x86/sample/nio/file/Chmod.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import java.nio.file.attribute.*; +import static java.nio.file.attribute.PosixFilePermission.*; +import static java.nio.file.FileVisitResult.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample code that changes the permissions of files in a similar manner to the + * chmod(1) program. + */ + +public class Chmod { + + /** + * Compiles a list of one or more <em>symbolic mode expressions</em> that + * may be used to change a set of file permissions. This method is + * intended for use where file permissions are required to be changed in + * a manner similar to the UNIX <i>chmod</i> program. + * + * <p> The {@code exprs} parameter is a comma separated list of expressions + * where each takes the form: + * <blockquote> + * <i>who operator</i> [<i>permissions</i>] + * </blockquote> + * where <i>who</i> is one or more of the characters {@code 'u'}, {@code 'g'}, + * {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or + * all (owner, group, and others) respectively. + * + * <p> <i>operator</i> is the character {@code '+'}, {@code '-'}, or {@code + * '='} signifying how permissions are to be changed. {@code '+'} means the + * permissions are added, {@code '-'} means the permissions are removed, and + * {@code '='} means the permissions are assigned absolutely. + * + * <p> <i>permissions</i> is a sequence of zero or more of the following: + * {@code 'r'} for read permission, {@code 'w'} for write permission, and + * {@code 'x'} for execute permission. If <i>permissions</i> is omitted + * when assigned absolutely, then the permissions are cleared for + * the owner, group, or others as identified by <i>who</i>. When omitted + * when adding or removing then the expression is ignored. + * + * <p> The following examples demonstrate possible values for the {@code + * exprs} parameter: + * + * <table border="0"> + * <tr> + * <td> {@code u=rw} </td> + * <td> Sets the owner permissions to be read and write. </td> + * </tr> + * <tr> + * <td> {@code ug+w} </td> + * <td> Sets the owner write and group write permissions. </td> + * </tr> + * <tr> + * <td> {@code u+w,o-rwx} </td> + * <td> Sets the owner write, and removes the others read, others write + * and others execute permissions. </td> + * </tr> + * <tr> + * <td> {@code o=} </td> + * <td> Sets the others permission to none (others read, others write and + * others execute permissions are removed if set) </td> + * </tr> + * </table> + * + * @param exprs + * List of one or more <em>symbolic mode expressions</em> + * + * @return A {@code Changer} that may be used to changer a set of + * file permissions + * + * @throws IllegalArgumentException + * If the value of the {@code exprs} parameter is invalid + */ + public static Changer compile(String exprs) { + // minimum is who and operator (u= for example) + if (exprs.length() < 2) + throw new IllegalArgumentException("Invalid mode"); + + // permissions that the changer will add or remove + final Set<PosixFilePermission> toAdd = new HashSet<PosixFilePermission>(); + final Set<PosixFilePermission> toRemove = new HashSet<PosixFilePermission>(); + + // iterate over each of expression modes + for (String expr: exprs.split(",")) { + // minimum of who and operator + if (expr.length() < 2) + throw new IllegalArgumentException("Invalid mode"); + + int pos = 0; + + // who + boolean u = false; + boolean g = false; + boolean o = false; + boolean done = false; + for (;;) { + switch (expr.charAt(pos)) { + case 'u' : u = true; break; + case 'g' : g = true; break; + case 'o' : o = true; break; + case 'a' : u = true; g = true; o = true; break; + default : done = true; + } + if (done) + break; + pos++; + } + if (!u && !g && !o) + throw new IllegalArgumentException("Invalid mode"); + + // get operator and permissions + char op = expr.charAt(pos++); + String mask = (expr.length() == pos) ? "" : expr.substring(pos); + + // operator + boolean add = (op == '+'); + boolean remove = (op == '-'); + boolean assign = (op == '='); + if (!add && !remove && !assign) + throw new IllegalArgumentException("Invalid mode"); + + // who= means remove all + if (assign && mask.length() == 0) { + assign = false; + remove = true; + mask = "rwx"; + } + + // permissions + boolean r = false; + boolean w = false; + boolean x = false; + for (int i=0; i<mask.length(); i++) { + switch (mask.charAt(i)) { + case 'r' : r = true; break; + case 'w' : w = true; break; + case 'x' : x = true; break; + default: + throw new IllegalArgumentException("Invalid mode"); + } + } + + // update permissions set + if (add) { + if (u) { + if (r) toAdd.add(OWNER_READ); + if (w) toAdd.add(OWNER_WRITE); + if (x) toAdd.add(OWNER_EXECUTE); + } + if (g) { + if (r) toAdd.add(GROUP_READ); + if (w) toAdd.add(GROUP_WRITE); + if (x) toAdd.add(GROUP_EXECUTE); + } + if (o) { + if (r) toAdd.add(OTHERS_READ); + if (w) toAdd.add(OTHERS_WRITE); + if (x) toAdd.add(OTHERS_EXECUTE); + } + } + if (remove) { + if (u) { + if (r) toRemove.add(OWNER_READ); + if (w) toRemove.add(OWNER_WRITE); + if (x) toRemove.add(OWNER_EXECUTE); + } + if (g) { + if (r) toRemove.add(GROUP_READ); + if (w) toRemove.add(GROUP_WRITE); + if (x) toRemove.add(GROUP_EXECUTE); + } + if (o) { + if (r) toRemove.add(OTHERS_READ); + if (w) toRemove.add(OTHERS_WRITE); + if (x) toRemove.add(OTHERS_EXECUTE); + } + } + if (assign) { + if (u) { + if (r) toAdd.add(OWNER_READ); + else toRemove.add(OWNER_READ); + if (w) toAdd.add(OWNER_WRITE); + else toRemove.add(OWNER_WRITE); + if (x) toAdd.add(OWNER_EXECUTE); + else toRemove.add(OWNER_EXECUTE); + } + if (g) { + if (r) toAdd.add(GROUP_READ); + else toRemove.add(GROUP_READ); + if (w) toAdd.add(GROUP_WRITE); + else toRemove.add(GROUP_WRITE); + if (x) toAdd.add(GROUP_EXECUTE); + else toRemove.add(GROUP_EXECUTE); + } + if (o) { + if (r) toAdd.add(OTHERS_READ); + else toRemove.add(OTHERS_READ); + if (w) toAdd.add(OTHERS_WRITE); + else toRemove.add(OTHERS_WRITE); + if (x) toAdd.add(OTHERS_EXECUTE); + else toRemove.add(OTHERS_EXECUTE); + } + } + } + + // return changer + return new Changer() { + @Override + public Set<PosixFilePermission> change(Set<PosixFilePermission> perms) { + perms.addAll(toAdd); + perms.removeAll(toRemove); + return perms; + } + }; + } + + /** + * A task that <i>changes</i> a set of {@link PosixFilePermission} elements. + */ + public interface Changer { + /** + * Applies the changes to the given set of permissions. + * + * @param perms + * The set of permissions to change + * + * @return The {@code perms} parameter + */ + Set<PosixFilePermission> change(Set<PosixFilePermission> perms); + } + + /** + * Changes the permissions of the file using the given Changer. + */ + static void chmod(Path file, Changer changer) { + try { + Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file); + Files.setPosixFilePermissions(file, changer.change(perms)); + } catch (IOException x) { + System.err.println(x); + } + } + + /** + * Changes the permission of each file and directory visited + */ + static class TreeVisitor implements FileVisitor<Path> { + private final Changer changer; + + TreeVisitor(Changer changer) { + this.changer = changer; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + chmod(dir, changer); + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + chmod(file, changer); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + if (exc != null) + System.err.println("WARNING: " + exc); + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) { + System.err.println("WARNING: " + exc); + return CONTINUE; + } + } + + static void usage() { + System.err.println("java Chmod [-R] symbolic-mode-list file..."); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length < 2) + usage(); + int argi = 0; + int maxDepth = 0; + if (args[argi].equals("-R")) { + if (args.length < 3) + usage(); + argi++; + maxDepth = Integer.MAX_VALUE; + } + + // compile the symbolic mode expressions + Changer changer = compile(args[argi++]); + TreeVisitor visitor = new TreeVisitor(changer); + + Set<FileVisitOption> opts = Collections.emptySet(); + while (argi < args.length) { + Path file = Paths.get(args[argi]); + Files.walkFileTree(file, opts, maxDepth, visitor); + argi++; + } + } +} diff --git a/darwin-x86/sample/nio/file/Copy.java b/darwin-x86/sample/nio/file/Copy.java new file mode 100644 index 0000000..0d61ef3 --- /dev/null +++ b/darwin-x86/sample/nio/file/Copy.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import static java.nio.file.StandardCopyOption.*; +import java.nio.file.attribute.*; +import static java.nio.file.FileVisitResult.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample code that copies files in a similar manner to the cp(1) program. + */ + +public class Copy { + + /** + * Returns {@code true} if okay to overwrite a file ("cp -i") + */ + static boolean okayToOverwrite(Path file) { + String answer = System.console().readLine("overwrite %s (yes/no)? ", file); + return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); + } + + /** + * Copy source file to target location. If {@code prompt} is true then + * prompt user to overwrite target if it exists. The {@code preserve} + * parameter determines if file attributes should be copied/preserved. + */ + static void copyFile(Path source, Path target, boolean prompt, boolean preserve) { + CopyOption[] options = (preserve) ? + new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } : + new CopyOption[] { REPLACE_EXISTING }; + if (!prompt || Files.notExists(target) || okayToOverwrite(target)) { + try { + Files.copy(source, target, options); + } catch (IOException x) { + System.err.format("Unable to copy: %s: %s%n", source, x); + } + } + } + + /** + * A {@code FileVisitor} that copies a file-tree ("cp -r") + */ + static class TreeCopier implements FileVisitor<Path> { + private final Path source; + private final Path target; + private final boolean prompt; + private final boolean preserve; + + TreeCopier(Path source, Path target, boolean prompt, boolean preserve) { + this.source = source; + this.target = target; + this.prompt = prompt; + this.preserve = preserve; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + // before visiting entries in a directory we copy the directory + // (okay if directory already exists). + CopyOption[] options = (preserve) ? + new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0]; + + Path newdir = target.resolve(source.relativize(dir)); + try { + Files.copy(dir, newdir, options); + } catch (FileAlreadyExistsException x) { + // ignore + } catch (IOException x) { + System.err.format("Unable to create: %s: %s%n", newdir, x); + return SKIP_SUBTREE; + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + copyFile(file, target.resolve(source.relativize(file)), + prompt, preserve); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + // fix up modification time of directory when done + if (exc == null && preserve) { + Path newdir = target.resolve(source.relativize(dir)); + try { + FileTime time = Files.getLastModifiedTime(dir); + Files.setLastModifiedTime(newdir, time); + } catch (IOException x) { + System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x); + } + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) { + if (exc instanceof FileSystemLoopException) { + System.err.println("cycle detected: " + file); + } else { + System.err.format("Unable to copy: %s: %s%n", file, exc); + } + return CONTINUE; + } + } + + static void usage() { + System.err.println("java Copy [-ip] source... target"); + System.err.println("java Copy -r [-ip] source-dir... target"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + boolean recursive = false; + boolean prompt = false; + boolean preserve = false; + + // process options + int argi = 0; + while (argi < args.length) { + String arg = args[argi]; + if (!arg.startsWith("-")) + break; + if (arg.length() < 2) + usage(); + for (int i=1; i<arg.length(); i++) { + char c = arg.charAt(i); + switch (c) { + case 'r' : recursive = true; break; + case 'i' : prompt = true; break; + case 'p' : preserve = true; break; + default : usage(); + } + } + argi++; + } + + // remaining arguments are the source files(s) and the target location + int remaining = args.length - argi; + if (remaining < 2) + usage(); + Path[] source = new Path[remaining-1]; + int i=0; + while (remaining > 1) { + source[i++] = Paths.get(args[argi++]); + remaining--; + } + Path target = Paths.get(args[argi]); + + // check if target is a directory + boolean isDir = Files.isDirectory(target); + + // copy each source file/directory to target + for (i=0; i<source.length; i++) { + Path dest = (isDir) ? target.resolve(source[i].getFileName()) : target; + + if (recursive) { + // follow links when copying files + EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve); + Files.walkFileTree(source[i], opts, Integer.MAX_VALUE, tc); + } else { + // not recursive so source must not be a directory + if (Files.isDirectory(source[i])) { + System.err.format("%s: is a directory%n", source[i]); + continue; + } + copyFile(source[i], dest, prompt, preserve); + } + } + } +} diff --git a/darwin-x86/sample/nio/file/DiskUsage.java b/darwin-x86/sample/nio/file/DiskUsage.java new file mode 100644 index 0000000..7d30bdf --- /dev/null +++ b/darwin-x86/sample/nio/file/DiskUsage.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Example utility that works like the df(1M) program to print out disk space + * information + */ + +public class DiskUsage { + + static final long K = 1024; + + static void printFileStore(FileStore store) throws IOException { + long total = store.getTotalSpace() / K; + long used = (store.getTotalSpace() - store.getUnallocatedSpace()) / K; + long avail = store.getUsableSpace() / K; + + String s = store.toString(); + if (s.length() > 20) { + System.out.println(s); + s = ""; + } + System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail); + } + + public static void main(String[] args) throws IOException { + System.out.format("%-20s %12s %12s %12s\n", "Filesystem", "kbytes", "used", "avail"); + if (args.length == 0) { + FileSystem fs = FileSystems.getDefault(); + for (FileStore store: fs.getFileStores()) { + printFileStore(store); + } + } else { + for (String file: args) { + FileStore store = Files.getFileStore(Paths.get(file)); + printFileStore(store); + } + } + } +} diff --git a/darwin-x86/sample/nio/file/FileType.java b/darwin-x86/sample/nio/file/FileType.java new file mode 100644 index 0000000..d001d60 --- /dev/null +++ b/darwin-x86/sample/nio/file/FileType.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import java.io.IOException; + +public class FileType { + public static void main(String[] args) throws IOException { + if (args.length == 0) { + System.err.println("usage: java FileType file..."); + System.exit(-1); + } + for (String arg: args) { + Path file = Paths.get(arg); + String type; + if (Files.isDirectory(file)) { + type = "directory"; + } else { + type = Files.probeContentType(file); + if (type == null) + type = "<not recognized>"; + } + System.out.format("%s\t%s%n", file, type); + } + } +} diff --git a/darwin-x86/sample/nio/file/WatchDir.java b/darwin-x86/sample/nio/file/WatchDir.java new file mode 100644 index 0000000..4c73820 --- /dev/null +++ b/darwin-x86/sample/nio/file/WatchDir.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKinds.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Example to watch a directory (or tree) for changes to files. + */ + +public class WatchDir { + + private final WatchService watcher; + private final boolean recursive; + private boolean trace = false; + private int count; + + @SuppressWarnings("unchecked") + static <T> WatchEvent<T> cast(WatchEvent<?> event) { + return (WatchEvent<T>)event; + } + + /** + * Register the given directory with the WatchService + */ + private void register(Path dir) throws IOException { + WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + count++; + if (trace) + System.out.format("register: %s\n", dir); + } + + /** + * Register the given directory, and all its sub-directories, with the + * WatchService. + */ + private void registerAll(final Path start) throws IOException { + // register directory and sub-directories + Files.walkFileTree(start, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException + { + register(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + /** + * Creates a WatchService and registers the given directory + */ + WatchDir(Path dir, boolean recursive) throws IOException { + this.watcher = FileSystems.getDefault().newWatchService(); + this.recursive = recursive; + + if (recursive) { + System.out.format("Scanning %s ...\n", dir); + registerAll(dir); + System.out.println("Done."); + } else { + register(dir); + } + + // enable trace after initial registration + this.trace = true; + } + + /** + * Process all events for keys queued to the watcher + */ + void processEvents() { + for (;;) { + + // wait for key to be signalled + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + return; + } + + for (WatchEvent<?> event: key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + + // TBD - provide example of how OVERFLOW event is handled + if (kind == OVERFLOW) { + continue; + } + + // Context for directory entry event is the file name of entry + WatchEvent<Path> ev = cast(event); + Path name = ev.context(); + Path child = ((Path)key.watchable()).resolve(name); + + // print out event + System.out.format("%s: %s\n", event.kind().name(), child); + + // if directory is created, and watching recursively, then + // register it and its sub-directories + if (recursive && (kind == ENTRY_CREATE)) { + try { + if (Files.isDirectory(child, NOFOLLOW_LINKS)) { + registerAll(child); + } + } catch (IOException x) { + // ignore to keep sample readbale + } + } + } + + // reset key + boolean valid = key.reset(); + if (!valid) { + // directory no longer accessible + count--; + if (count == 0) + break; + } + } + } + + static void usage() { + System.err.println("usage: java WatchDir [-r] dir"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // parse arguments + if (args.length == 0 || args.length > 2) + usage(); + boolean recursive = false; + int dirArg = 0; + if (args[0].equals("-r")) { + if (args.length < 2) + usage(); + recursive = true; + dirArg++; + } + + // register directory and process its events + Path dir = Paths.get(args[dirArg]); + new WatchDir(dir, recursive).processEvents(); + } +} diff --git a/darwin-x86/sample/nio/file/Xdd.java b/darwin-x86/sample/nio/file/Xdd.java new file mode 100644 index 0000000..c0c7f87 --- /dev/null +++ b/darwin-x86/sample/nio/file/Xdd.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + +/** + * Example code to list/set/get/delete the user-defined attributes of a file. + */ + +public class Xdd { + + static void usage() { + System.out.println("Usage: java Xdd <file>"); + System.out.println(" java Xdd -set <name>=<value> <file>"); + System.out.println(" java Xdd -get <name> <file>"); + System.out.println(" java Xdd -del <name> <file>"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // one or three parameters + if (args.length != 1 && args.length != 3) + usage(); + + Path file = (args.length == 1) ? + Paths.get(args[0]) : Paths.get(args[2]); + + // check that user defined attributes are supported by the file store + FileStore store = Files.getFileStore(file); + if (!store.supportsFileAttributeView(UserDefinedFileAttributeView.class)) { + System.err.format("UserDefinedFileAttributeView not supported on %s\n", store); + System.exit(-1); + + } + UserDefinedFileAttributeView view = + Files.getFileAttributeView(file, UserDefinedFileAttributeView.class); + + // list user defined attributes + if (args.length == 1) { + System.out.println(" Size Name"); + System.out.println("-------- --------------------------------------"); + for (String name: view.list()) { + System.out.format("%8d %s\n", view.size(name), name); + } + return; + } + + // Add/replace a file's user defined attribute + if (args[0].equals("-set")) { + // name=value + String[] s = args[1].split("="); + if (s.length != 2) + usage(); + String name = s[0]; + String value = s[1]; + view.write(name, Charset.defaultCharset().encode(value)); + return; + } + + // Print out the value of a file's user defined attribute + if (args[0].equals("-get")) { + String name = args[1]; + int size = view.size(name); + ByteBuffer buf = ByteBuffer.allocateDirect(size); + view.read(name, buf); + buf.flip(); + System.out.println(Charset.defaultCharset().decode(buf).toString()); + return; + } + + // Delete a file's user defined attribute + if (args[0].equals("-del")) { + view.delete(args[1]); + return; + } + + // option not recognized + usage(); + } + } diff --git a/darwin-x86/sample/nio/multicast/MulticastAddress.java b/darwin-x86/sample/nio/multicast/MulticastAddress.java new file mode 100644 index 0000000..05f5ca5 --- /dev/null +++ b/darwin-x86/sample/nio/multicast/MulticastAddress.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2007, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.net.SocketException; + +/** + * Parses and represents a multicast address. + */ + +class MulticastAddress { + private final InetAddress group; + private final int port; + private final NetworkInterface interf; + + private MulticastAddress(InetAddress group, int port, NetworkInterface interf) { + this.group = group; + this.port = port; + this.interf = interf; + } + + InetAddress group() { + return group; + } + + int port() { + return port; + } + + /** + * @return The network interface, may be {@code null} + */ + NetworkInterface interf() { + return interf; + } + + /** + * Parses a string of the form "group:port[@interface]", returning + * a MulticastAddress representing the address + */ + static MulticastAddress parse(String s) { + String[] components = s.split("@"); + if (components.length > 2) + throw new IllegalArgumentException("At most one '@' expected"); + + // get group and port + String target = components[0]; + int len = components[0].length(); + int colon = components[0].lastIndexOf(':'); + if ((colon < 1) || (colon > (len-2))) + throw new IllegalArgumentException("group:port expected"); + String groupString = target.substring(0, colon); + int port = -1; + try { + port = Integer.parseInt(target.substring(colon+1, len)); + } catch (NumberFormatException x) { + throw new IllegalArgumentException(x); + } + + // handle IPv6 literal address + if (groupString.charAt(0) == '[') { + len = groupString.length(); + if (groupString.charAt(len-1) != ']') + throw new IllegalArgumentException("missing ']'"); + groupString = groupString.substring(1,len-1); + if (groupString.length() == 0) + throw new IllegalArgumentException("missing IPv6 address"); + } + + // get group address + InetAddress group = null; + try { + group = InetAddress.getByName(groupString); + } catch (UnknownHostException x) { + throw new IllegalArgumentException(x); + } + if (!group.isMulticastAddress()) { + throw new IllegalArgumentException("'" + group.getHostAddress() + + "' is not multicast address"); + } + + // optional interface + NetworkInterface interf = null; + if (components.length == 2) { + try { + interf = NetworkInterface.getByName(components[1]); + } catch (SocketException x) { + throw new IllegalArgumentException(x); + } + if (interf == null) { + throw new IllegalArgumentException("'" + components[1] + + "' is not valid interface"); + } + } + return new MulticastAddress(group, port, interf); + } +} diff --git a/darwin-x86/sample/nio/multicast/Reader.java b/darwin-x86/sample/nio/multicast/Reader.java new file mode 100644 index 0000000..303c356 --- /dev/null +++ b/darwin-x86/sample/nio/multicast/Reader.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2007, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.channels.*; +import java.nio.charset.*; +import java.nio.ByteBuffer; +import java.net.*; +import java.io.IOException; +import java.util.*; + +public class Reader { + + static void usage() { + System.err.println("usage: java Reader group:port@interf [-only source...] [-block source...]"); + System.exit(-1); + } + + static void printDatagram(SocketAddress sa, ByteBuffer buf) { + System.out.format("-- datagram from %s --\n", + ((InetSocketAddress)sa).getAddress().getHostAddress()); + System.out.println(Charset.defaultCharset().decode(buf)); + } + + static void parseAddessList(String s, List<InetAddress> list) + throws UnknownHostException + { + String[] sources = s.split(","); + for (int i=0; i<sources.length; i++) { + list.add(InetAddress.getByName(sources[i])); + } + } + + public static void main(String[] args) throws IOException { + if (args.length == 0) + usage(); + + // first parameter is the multicast address (interface required) + MulticastAddress target = MulticastAddress.parse(args[0]); + if (target.interf() == null) + usage(); + + // addition arguments are source addresses to include or exclude + List<InetAddress> includeList = new ArrayList<InetAddress>(); + List<InetAddress> excludeList = new ArrayList<InetAddress>(); + int argc = 1; + while (argc < args.length) { + String option = args[argc++]; + if (argc >= args.length) + usage(); + String value = args[argc++]; + if (option.equals("-only")) { + parseAddessList(value, includeList); + continue; + } + if (option.equals("-block")) { + parseAddessList(value, excludeList); + continue; + } + usage(); + } + if (!includeList.isEmpty() && !excludeList.isEmpty()) { + usage(); + } + + // create and bind socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) { + family = StandardProtocolFamily.INET6; + } + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOptions.SO_REUSEADDR, true) + .bind(new InetSocketAddress(target.port())); + + if (includeList.isEmpty()) { + // join group and block addresses on the exclude list + MembershipKey key = dc.join(target.group(), target.interf()); + for (InetAddress source: excludeList) { + key.block(source); + } + } else { + // join with source-specific membership for each source + for (InetAddress source: includeList) { + dc.join(target.group(), target.interf(), source); + } + } + + // register socket with Selector + Selector sel = Selector.open(); + dc.configureBlocking(false); + dc.register(sel, SelectionKey.OP_READ); + + // print out each datagram that we receive + ByteBuffer buf = ByteBuffer.allocateDirect(4096); + for (;;) { + int updated = sel.select(); + if (updated > 0) { + Iterator<SelectionKey> iter = sel.selectedKeys().iterator(); + while (iter.hasNext()) { + SelectionKey sk = iter.next(); + iter.remove(); + + DatagramChannel ch = (DatagramChannel)sk.channel(); + SocketAddress sa = ch.receive(buf); + if (sa != null) { + buf.flip(); + printDatagram(sa, buf); + buf.rewind(); + buf.limit(buf.capacity()); + } + } + } + } + } +} diff --git a/darwin-x86/sample/nio/multicast/Sender.java b/darwin-x86/sample/nio/multicast/Sender.java new file mode 100644 index 0000000..f8685f6 --- /dev/null +++ b/darwin-x86/sample/nio/multicast/Sender.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.channels.*; +import java.nio.charset.Charset; +import java.net.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample multicast sender to send a message in a multicast datagram + * to a given group. + */ + +public class Sender { + + private static void usage() { + System.err.println("usage: java Sender group:port[@interface] message"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length < 2) + usage(); + + MulticastAddress target = MulticastAddress.parse(args[0]); + + // create socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) + family = StandardProtocolFamily.INET6; + DatagramChannel dc = DatagramChannel.open(family).bind(new InetSocketAddress(0)); + if (target.interf() != null) { + dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, target.interf()); + } + + // send multicast packet + dc.send(Charset.defaultCharset().encode(args[1]), + new InetSocketAddress(target.group(), target.port())); + dc.close(); + } + +} diff --git a/darwin-x86/sample/nio/server/AcceptHandler.java b/darwin-x86/sample/nio/server/AcceptHandler.java new file mode 100644 index 0000000..41c2570 --- /dev/null +++ b/darwin-x86/sample/nio/server/AcceptHandler.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; +import javax.net.ssl.*; + +/** + * A single threaded Handler that performs accepts SocketChannels and + * registers the Channels with the read/write Selector. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class AcceptHandler implements Handler { + + private ServerSocketChannel channel; + private Dispatcher dsp; + + private SSLContext sslContext; + + AcceptHandler(ServerSocketChannel ssc, Dispatcher dsp, + SSLContext sslContext) { + channel = ssc; + this.dsp = dsp; + this.sslContext = sslContext; + } + + public void handle(SelectionKey sk) throws IOException { + + if (!sk.isAcceptable()) + return; + + SocketChannel sc = channel.accept(); + if (sc == null) { + return; + } + + ChannelIO cio = (sslContext != null ? + ChannelIOSecure.getInstance( + sc, false /* non-blocking */, sslContext) : + ChannelIO.getInstance( + sc, false /* non-blocking */)); + + RequestHandler rh = new RequestHandler(cio); + dsp.register(cio.getSocketChannel(), SelectionKey.OP_READ, rh); + } +} diff --git a/darwin-x86/sample/nio/server/Acceptor.java b/darwin-x86/sample/nio/server/Acceptor.java new file mode 100644 index 0000000..cfdaf0e --- /dev/null +++ b/darwin-x86/sample/nio/server/Acceptor.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; +import javax.net.ssl.*; + +/** + * A Runnable class which sits in a loop accepting SocketChannels, + * then registers the Channels with the read/write Selector. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class Acceptor implements Runnable { + + private ServerSocketChannel ssc; + private Dispatcher d; + + private SSLContext sslContext; + + Acceptor(ServerSocketChannel ssc, Dispatcher d, SSLContext sslContext) { + this.ssc = ssc; + this.d = d; + this.sslContext = sslContext; + } + + public void run() { + for (;;) { + try { + SocketChannel sc = ssc.accept(); + + ChannelIO cio = (sslContext != null ? + ChannelIOSecure.getInstance( + sc, false /* non-blocking */, sslContext) : + ChannelIO.getInstance( + sc, false /* non-blocking */)); + + RequestHandler rh = new RequestHandler(cio); + + d.register(cio.getSocketChannel(), SelectionKey.OP_READ, rh); + + } catch (IOException x) { + x.printStackTrace(); + break; + } + } + } +} diff --git a/darwin-x86/sample/nio/server/B1.java b/darwin-x86/sample/nio/server/B1.java new file mode 100644 index 0000000..c6d7e90 --- /dev/null +++ b/darwin-x86/sample/nio/server/B1.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.channels.*; + +/** + * A blocking/single-threaded server which completely services + * each connection before moving to the next. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public class B1 extends Server { + + B1(int port, int backlog, boolean secure) throws Exception { + super(port, backlog, secure); + } + + void runServer() throws Exception { + for (;;) { + + SocketChannel sc = ssc.accept(); + + ChannelIO cio = (sslContext != null ? + ChannelIOSecure.getInstance( + sc, true /* blocking */, sslContext) : + ChannelIO.getInstance( + sc, true /* blocking */)); + + RequestServicer svc = new RequestServicer(cio); + svc.run(); + } + } +} diff --git a/darwin-x86/sample/nio/server/BN.java b/darwin-x86/sample/nio/server/BN.java new file mode 100644 index 0000000..c765a8b --- /dev/null +++ b/darwin-x86/sample/nio/server/BN.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; + +/** + * A Blocking/Multi-threaded Server which creates a new thread for each + * connection. This is not efficient for large numbers of connections. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public class BN extends Server { + + BN(int port, int backlog, boolean secure) throws Exception { + super(port, backlog, secure); + } + + void runServer() throws IOException { + for (;;) { + + SocketChannel sc = ssc.accept(); + + ChannelIO cio = (sslContext != null ? + ChannelIOSecure.getInstance( + sc, true /* blocking */, sslContext) : + ChannelIO.getInstance( + sc, true /* blocking */)); + + RequestServicer svc = new RequestServicer(cio); + Thread th = new Thread(svc); + th.start(); + } + } +} diff --git a/darwin-x86/sample/nio/server/BP.java b/darwin-x86/sample/nio/server/BP.java new file mode 100644 index 0000000..9540f1c --- /dev/null +++ b/darwin-x86/sample/nio/server/BP.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.channels.*; +import java.util.concurrent.*; + +/** + * A multi-threaded server which creates a pool of threads for use + * by the server. The Thread pool decides how to schedule those threads. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public class BP extends Server { + + private static final int POOL_MULTIPLE = 4; + + BP(int port, int backlog, boolean secure) throws Exception { + super(port, backlog, secure); + } + + void runServer() throws Exception { + + ExecutorService xec = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors() * POOL_MULTIPLE); + + for (;;) { + + SocketChannel sc = ssc.accept(); + + ChannelIO cio = (sslContext != null ? + ChannelIOSecure.getInstance( + sc, true /* blocking */, sslContext) : + ChannelIO.getInstance( + sc, true /* blocking */)); + + RequestServicer svc = new RequestServicer(cio); + xec.execute(svc); + } + } +} diff --git a/darwin-x86/sample/nio/server/ChannelIO.java b/darwin-x86/sample/nio/server/ChannelIO.java new file mode 100644 index 0000000..7d1ca18 --- /dev/null +++ b/darwin-x86/sample/nio/server/ChannelIO.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; + +/** + * A helper class for properly sizing inbound byte buffers and + * redirecting I/O calls to the proper SocketChannel call. + * <P> + * Many of these calls may seem unnecessary until you consider + * that they are placeholders for the secure variant, which is much + * more involved. See ChannelIOSecure for more information. + * + * @author Brad R. Wetmore + * @author Mark Reinhold + */ +class ChannelIO { + + protected SocketChannel sc; + + /* + * All of the inbound request data lives here until we determine + * that we've read everything, then we pass that data back to the + * caller. + */ + protected ByteBuffer requestBB; + static private int requestBBSize = 4096; + + protected ChannelIO(SocketChannel sc, boolean blocking) + throws IOException { + this.sc = sc; + sc.configureBlocking(blocking); + } + + static ChannelIO getInstance(SocketChannel sc, boolean blocking) + throws IOException { + ChannelIO cio = new ChannelIO(sc, blocking); + cio.requestBB = ByteBuffer.allocate(requestBBSize); + + return cio; + } + + SocketChannel getSocketChannel() { + return sc; + } + + /* + * Return a ByteBuffer with "remaining" space to work. If you have to + * reallocate the ByteBuffer, copy the existing info into the new buffer. + */ + protected void resizeRequestBB(int remaining) { + if (requestBB.remaining() < remaining) { + // Expand buffer for large request + ByteBuffer bb = ByteBuffer.allocate(requestBB.capacity() * 2); + requestBB.flip(); + bb.put(requestBB); + requestBB = bb; + } + } + + /* + * Perform any handshaking processing. + * <P> + * This variant is for Servers without SelectionKeys (e.g. + * blocking). + * <P> + * return true when we're done with handshaking. + */ + boolean doHandshake() throws IOException { + return true; + } + + /* + * Perform any handshaking processing. + * <P> + * This variant is for Servers with SelectionKeys, so that + * we can register for selectable operations (e.g. selectable + * non-blocking). + * <P> + * return true when we're done with handshaking. + */ + boolean doHandshake(SelectionKey sk) throws IOException { + return true; + } + + /* + * Resize (if necessary) the inbound data buffer, and then read more + * data into the read buffer. + */ + int read() throws IOException { + /* + * Allocate more space if less than 5% remains + */ + resizeRequestBB(requestBBSize/20); + return sc.read(requestBB); + } + + /* + * All data has been read, pass back the request in one buffer. + */ + ByteBuffer getReadBuf() { + return requestBB; + } + + /* + * Write the src buffer into the socket channel. + */ + int write(ByteBuffer src) throws IOException { + return sc.write(src); + } + + /* + * Perform a FileChannel.TransferTo on the socket channel. + */ + long transferTo(FileChannel fc, long pos, long len) throws IOException { + return fc.transferTo(pos, len, sc); + } + + /* + * Flush any outstanding data to the network if possible. + * <P> + * This isn't really necessary for the insecure variant, but needed + * for the secure one where intermediate buffering must take place. + * <P> + * Return true if successful. + */ + boolean dataFlush() throws IOException { + return true; + } + + /* + * Start any connection shutdown processing. + * <P> + * This isn't really necessary for the insecure variant, but needed + * for the secure one where intermediate buffering must take place. + * <P> + * Return true if successful, and the data has been flushed. + */ + boolean shutdown() throws IOException { + return true; + } + + /* + * Close the underlying connection. + */ + void close() throws IOException { + sc.close(); + } + +} diff --git a/darwin-x86/sample/nio/server/ChannelIOSecure.java b/darwin-x86/sample/nio/server/ChannelIOSecure.java new file mode 100644 index 0000000..7508966 --- /dev/null +++ b/darwin-x86/sample/nio/server/ChannelIOSecure.java @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; + +/** + * A helper class which performs I/O using the SSLEngine API. + * <P> + * Each connection has a SocketChannel and a SSLEngine that is + * used through the lifetime of the Channel. We allocate byte buffers + * for use as the outbound and inbound network buffers. + * + * <PRE> + * Application Data + * src requestBB + * | ^ + * | | | + * v | | + * +----+-----|-----+----+ + * | | | + * | SSL|Engine | + * wrap() | | | unwrap() + * | OUTBOUND | INBOUND | + * | | | + * +----+-----|-----+----+ + * | | ^ + * | | | + * v | + * outNetBB inNetBB + * Net data + * </PRE> + * + * These buffers handle all of the intermediary data for the SSL + * connection. To make things easy, we'll require outNetBB be + * completely flushed before trying to wrap any more data, but we + * could certainly remove that restriction by using larger buffers. + * <P> + * There are many, many ways to handle compute and I/O strategies. + * What follows is a relatively simple one. The reader is encouraged + * to develop the strategy that best fits the application. + * <P> + * In most of the non-blocking operations in this class, we let the + * Selector tell us when we're ready to attempt an I/O operation (by the + * application repeatedly calling our methods). Another option would be + * to attempt the operation and return from the method when no forward + * progress can be made. + * <P> + * There's lots of room for enhancements and improvement in this example. + * <P> + * We're checking for SSL/TLS end-of-stream truncation attacks via + * sslEngine.closeInbound(). When you reach the end of a input stream + * via a read() returning -1 or an IOException, we call + * sslEngine.closeInbound() to signal to the sslEngine that no more + * input will be available. If the peer's close_notify message has not + * yet been received, this could indicate a trucation attack, in which + * an attacker is trying to prematurely close the connection. The + * closeInbound() will throw an exception if this condition were + * present. + * + * @author Brad R. Wetmore + * @author Mark Reinhold + */ +class ChannelIOSecure extends ChannelIO { + + private SSLEngine sslEngine = null; + + private int appBBSize; + private int netBBSize; + + /* + * All I/O goes through these buffers. + * <P> + * It might be nice to use a cache of ByteBuffers so we're + * not alloc/dealloc'ing ByteBuffer's for each new SSLEngine. + * <P> + * We use our superclass' requestBB for our application input buffer. + * Outbound application data is supplied to us by our callers. + */ + private ByteBuffer inNetBB; + private ByteBuffer outNetBB; + + /* + * An empty ByteBuffer for use when one isn't available, say + * as a source buffer during initial handshake wraps or for close + * operations. + */ + private static ByteBuffer hsBB = ByteBuffer.allocate(0); + + /* + * The FileChannel we're currently transferTo'ing (reading). + */ + private ByteBuffer fileChannelBB = null; + + /* + * During our initial handshake, keep track of the next + * SSLEngine operation that needs to occur: + * + * NEED_WRAP/NEED_UNWRAP + * + * Once the initial handshake has completed, we can short circuit + * handshake checks with initialHSComplete. + */ + private HandshakeStatus initialHSStatus; + private boolean initialHSComplete; + + /* + * We have received the shutdown request by our caller, and have + * closed our outbound side. + */ + private boolean shutdown = false; + + /* + * Constructor for a secure ChannelIO variant. + */ + protected ChannelIOSecure(SocketChannel sc, boolean blocking, + SSLContext sslc) throws IOException { + super(sc, blocking); + + /* + * We're a server, so no need to use host/port variant. + * + * The first call for a server is a NEED_UNWRAP. + */ + sslEngine = sslc.createSSLEngine(); + sslEngine.setUseClientMode(false); + initialHSStatus = HandshakeStatus.NEED_UNWRAP; + initialHSComplete = false; + + // Create a buffer using the normal expected packet size we'll + // be getting. This may change, depending on the peer's + // SSL implementation. + netBBSize = sslEngine.getSession().getPacketBufferSize(); + inNetBB = ByteBuffer.allocate(netBBSize); + outNetBB = ByteBuffer.allocate(netBBSize); + outNetBB.position(0); + outNetBB.limit(0); + } + + /* + * Static factory method for creating a secure ChannelIO object. + * <P> + * We need to allocate different sized application data buffers + * based on whether we're secure or not. We can't determine + * this until our sslEngine is created. + */ + static ChannelIOSecure getInstance(SocketChannel sc, boolean blocking, + SSLContext sslc) throws IOException { + + ChannelIOSecure cio = new ChannelIOSecure(sc, blocking, sslc); + + // Create a buffer using the normal expected application size we'll + // be getting. This may change, depending on the peer's + // SSL implementation. + cio.appBBSize = cio.sslEngine.getSession().getApplicationBufferSize(); + cio.requestBB = ByteBuffer.allocate(cio.appBBSize); + + return cio; + } + + /* + * Calls up to the superclass to adjust the buffer size + * by an appropriate increment. + */ + protected void resizeRequestBB() { + resizeRequestBB(appBBSize); + } + + /* + * Adjust the inbount network buffer to an appropriate size. + */ + private void resizeResponseBB() { + ByteBuffer bb = ByteBuffer.allocate(netBBSize); + inNetBB.flip(); + bb.put(inNetBB); + inNetBB = bb; + } + + /* + * Writes bb to the SocketChannel. + * <P> + * Returns true when the ByteBuffer has no remaining data. + */ + private boolean tryFlush(ByteBuffer bb) throws IOException { + super.write(bb); + return !bb.hasRemaining(); + } + + /* + * Perform any handshaking processing. + * <P> + * This variant is for Servers without SelectionKeys (e.g. + * blocking). + */ + boolean doHandshake() throws IOException { + return doHandshake(null); + } + + /* + * Perform any handshaking processing. + * <P> + * If a SelectionKey is passed, register for selectable + * operations. + * <P> + * In the blocking case, our caller will keep calling us until + * we finish the handshake. Our reads/writes will block as expected. + * <P> + * In the non-blocking case, we just received the selection notification + * that this channel is ready for whatever the operation is, so give + * it a try. + * <P> + * return: + * true when handshake is done. + * false while handshake is in progress + */ + boolean doHandshake(SelectionKey sk) throws IOException { + + SSLEngineResult result; + + if (initialHSComplete) { + return initialHSComplete; + } + + /* + * Flush out the outgoing buffer, if there's anything left in + * it. + */ + if (outNetBB.hasRemaining()) { + + if (!tryFlush(outNetBB)) { + return false; + } + + // See if we need to switch from write to read mode. + + switch (initialHSStatus) { + + /* + * Is this the last buffer? + */ + case FINISHED: + initialHSComplete = true; + // Fall-through to reregister need for a Read. + + case NEED_UNWRAP: + if (sk != null) { + sk.interestOps(SelectionKey.OP_READ); + } + break; + } + + return initialHSComplete; + } + + + switch (initialHSStatus) { + + case NEED_UNWRAP: + if (sc.read(inNetBB) == -1) { + sslEngine.closeInbound(); + return initialHSComplete; + } + +needIO: + while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) { + resizeRequestBB(); // expected room for unwrap + inNetBB.flip(); + result = sslEngine.unwrap(inNetBB, requestBB); + inNetBB.compact(); + + initialHSStatus = result.getHandshakeStatus(); + + switch (result.getStatus()) { + + case OK: + switch (initialHSStatus) { + case NOT_HANDSHAKING: + throw new IOException( + "Not handshaking during initial handshake"); + + case NEED_TASK: + initialHSStatus = doTasks(); + break; + + case FINISHED: + initialHSComplete = true; + break needIO; + } + + break; + + case BUFFER_UNDERFLOW: + // Resize buffer if needed. + netBBSize = sslEngine.getSession().getPacketBufferSize(); + if (netBBSize > inNetBB.capacity()) { + resizeResponseBB(); + } + + /* + * Need to go reread the Channel for more data. + */ + if (sk != null) { + sk.interestOps(SelectionKey.OP_READ); + } + break needIO; + + case BUFFER_OVERFLOW: + // Reset the application buffer size. + appBBSize = + sslEngine.getSession().getApplicationBufferSize(); + break; + + default: //CLOSED: + throw new IOException("Received" + result.getStatus() + + "during initial handshaking"); + } + } // "needIO" block. + + /* + * Just transitioned from read to write. + */ + if (initialHSStatus != HandshakeStatus.NEED_WRAP) { + break; + } + + // Fall through and fill the write buffers. + + case NEED_WRAP: + /* + * The flush above guarantees the out buffer to be empty + */ + outNetBB.clear(); + result = sslEngine.wrap(hsBB, outNetBB); + outNetBB.flip(); + + initialHSStatus = result.getHandshakeStatus(); + + switch (result.getStatus()) { + case OK: + + if (initialHSStatus == HandshakeStatus.NEED_TASK) { + initialHSStatus = doTasks(); + } + + if (sk != null) { + sk.interestOps(SelectionKey.OP_WRITE); + } + + break; + + default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED: + throw new IOException("Received" + result.getStatus() + + "during initial handshaking"); + } + break; + + default: // NOT_HANDSHAKING/NEED_TASK/FINISHED + throw new RuntimeException("Invalid Handshaking State" + + initialHSStatus); + } // switch + + return initialHSComplete; + } + + /* + * Do all the outstanding handshake tasks in the current Thread. + */ + private SSLEngineResult.HandshakeStatus doTasks() { + + Runnable runnable; + + /* + * We could run this in a separate thread, but + * do in the current for now. + */ + while ((runnable = sslEngine.getDelegatedTask()) != null) { + runnable.run(); + } + return sslEngine.getHandshakeStatus(); + } + + /* + * Read the channel for more information, then unwrap the + * (hopefully application) data we get. + * <P> + * If we run out of data, we'll return to our caller (possibly using + * a Selector) to get notification that more is available. + * <P> + * Each call to this method will perform at most one underlying read(). + */ + int read() throws IOException { + SSLEngineResult result; + + if (!initialHSComplete) { + throw new IllegalStateException(); + } + + int pos = requestBB.position(); + + if (sc.read(inNetBB) == -1) { + sslEngine.closeInbound(); // probably throws exception + return -1; + } + + do { + resizeRequestBB(); // expected room for unwrap + inNetBB.flip(); + result = sslEngine.unwrap(inNetBB, requestBB); + inNetBB.compact(); + + /* + * Could check here for a renegotation, but we're only + * doing a simple read/write, and won't have enough state + * transitions to do a complete handshake, so ignore that + * possibility. + */ + switch (result.getStatus()) { + + case BUFFER_OVERFLOW: + // Reset the application buffer size. + appBBSize = sslEngine.getSession().getApplicationBufferSize(); + break; + + case BUFFER_UNDERFLOW: + // Resize buffer if needed. + netBBSize = sslEngine.getSession().getPacketBufferSize(); + if (netBBSize > inNetBB.capacity()) { + resizeResponseBB(); + + break; // break, next read will support larger buffer. + } + case OK: + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + doTasks(); + } + break; + + default: + throw new IOException("sslEngine error during data read: " + + result.getStatus()); + } + } while ((inNetBB.position() != 0) && + result.getStatus() != Status.BUFFER_UNDERFLOW); + + return (requestBB.position() - pos); + } + + /* + * Try to write out as much as possible from the src buffer. + */ + int write(ByteBuffer src) throws IOException { + + if (!initialHSComplete) { + throw new IllegalStateException(); + } + + return doWrite(src); + } + + /* + * Try to flush out any existing outbound data, then try to wrap + * anything new contained in the src buffer. + * <P> + * Return the number of bytes actually consumed from the buffer, + * but the data may actually be still sitting in the output buffer, + * waiting to be flushed. + */ + private int doWrite(ByteBuffer src) throws IOException { + int retValue = 0; + + if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) { + return retValue; + } + + /* + * The data buffer is empty, we can reuse the entire buffer. + */ + outNetBB.clear(); + + SSLEngineResult result = sslEngine.wrap(src, outNetBB); + retValue = result.bytesConsumed(); + + outNetBB.flip(); + + switch (result.getStatus()) { + + case OK: + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + doTasks(); + } + break; + + default: + throw new IOException("sslEngine error during data write: " + + result.getStatus()); + } + + /* + * Try to flush the data, regardless of whether or not + * it's been selected. Odds of a write buffer being full + * is less than a read buffer being empty. + */ + if (outNetBB.hasRemaining()) { + tryFlush(outNetBB); + } + + return retValue; + } + + /* + * Perform a FileChannel.TransferTo on the socket channel. + * <P> + * We have to copy the data into an intermediary app ByteBuffer + * first, then send it through the SSLEngine. + * <P> + * We return the number of bytes actually read out of the + * filechannel. However, the data may actually be stuck + * in the fileChannelBB or the outNetBB. The caller + * is responsible for making sure to call dataFlush() + * before shutting down. + */ + long transferTo(FileChannel fc, long pos, long len) throws IOException { + + if (!initialHSComplete) { + throw new IllegalStateException(); + } + + if (fileChannelBB == null) { + fileChannelBB = ByteBuffer.allocate(appBBSize); + fileChannelBB.limit(0); + } + + fileChannelBB.compact(); + int fileRead = fc.read(fileChannelBB); + fileChannelBB.flip(); + + /* + * We ignore the return value here, we return the + * number of bytes actually consumed from the the file. + * We'll flush the output buffer before we start shutting down. + */ + doWrite(fileChannelBB); + + return fileRead; + } + + /* + * Flush any remaining data. + * <P> + * Return true when the fileChannelBB and outNetBB are empty. + */ + boolean dataFlush() throws IOException { + boolean fileFlushed = true; + + if ((fileChannelBB != null) && fileChannelBB.hasRemaining()) { + doWrite(fileChannelBB); + fileFlushed = !fileChannelBB.hasRemaining(); + } else if (outNetBB.hasRemaining()) { + tryFlush(outNetBB); + } + + return (fileFlushed && !outNetBB.hasRemaining()); + } + + /* + * Begin the shutdown process. + * <P> + * Close out the SSLEngine if not already done so, then + * wrap our outgoing close_notify message and try to send it on. + * <P> + * Return true when we're done passing the shutdown messsages. + */ + boolean shutdown() throws IOException { + + if (!shutdown) { + sslEngine.closeOutbound(); + shutdown = true; + } + + if (outNetBB.hasRemaining() && tryFlush(outNetBB)) { + return false; + } + + /* + * By RFC 2616, we can "fire and forget" our close_notify + * message, so that's what we'll do here. + */ + outNetBB.clear(); + SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB); + if (result.getStatus() != Status.CLOSED) { + throw new SSLException("Improper close state"); + } + outNetBB.flip(); + + /* + * We won't wait for a select here, but if this doesn't work, + * we'll cycle back through on the next select. + */ + if (outNetBB.hasRemaining()) { + tryFlush(outNetBB); + } + + return (!outNetBB.hasRemaining() && + (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); + } + + /* + * close() is not overridden + */ +} diff --git a/darwin-x86/sample/nio/server/Content.java b/darwin-x86/sample/nio/server/Content.java new file mode 100644 index 0000000..52e06fa --- /dev/null +++ b/darwin-x86/sample/nio/server/Content.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +/** + * An Sendable interface extension that adds additional + * methods for additional information, such as Files + * or Strings. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +interface Content extends Sendable { + + String type(); + + // Returns -1 until prepare() invoked + long length(); + +} diff --git a/darwin-x86/sample/nio/server/Dispatcher.java b/darwin-x86/sample/nio/server/Dispatcher.java new file mode 100644 index 0000000..9474c12 --- /dev/null +++ b/darwin-x86/sample/nio/server/Dispatcher.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; + +/** + * Base class for the Dispatchers. + * <P> + * Servers use these to obtain ready status, and then to dispatch jobs. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +interface Dispatcher extends Runnable { + + void register(SelectableChannel ch, int ops, Handler h) + throws IOException; + +} diff --git a/darwin-x86/sample/nio/server/Dispatcher1.java b/darwin-x86/sample/nio/server/Dispatcher1.java new file mode 100644 index 0000000..533e4b8 --- /dev/null +++ b/darwin-x86/sample/nio/server/Dispatcher1.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; +import java.util.*; + +/** + * A single-threaded dispatcher. + * <P> + * When a SelectionKey is ready, it dispatches the job in this + * thread. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class Dispatcher1 implements Dispatcher { + + private Selector sel; + + Dispatcher1() throws IOException { + sel = Selector.open(); + } + + // Doesn't really need to be runnable + public void run() { + for (;;) { + try { + dispatch(); + } catch (IOException x) { + x.printStackTrace(); + } + } + } + + private void dispatch() throws IOException { + sel.select(); + for (Iterator i = sel.selectedKeys().iterator(); i.hasNext(); ) { + SelectionKey sk = (SelectionKey)i.next(); + i.remove(); + Handler h = (Handler)sk.attachment(); + h.handle(sk); + } + } + + public void register(SelectableChannel ch, int ops, Handler h) + throws IOException { + ch.register(sel, ops, h); + } +} diff --git a/darwin-x86/sample/nio/server/DispatcherN.java b/darwin-x86/sample/nio/server/DispatcherN.java new file mode 100644 index 0000000..7b601b0 --- /dev/null +++ b/darwin-x86/sample/nio/server/DispatcherN.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; +import java.util.*; + +/** + * A Multi-threaded dispatcher. + * <P> + * In this example, one thread does accepts, and the second + * does read/writes. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class DispatcherN implements Dispatcher { + + private Selector sel; + + DispatcherN() throws IOException { + sel = Selector.open(); + } + + public void run() { + for (;;) { + try { + dispatch(); + } catch (IOException x) { + x.printStackTrace(); + } + } + } + + private Object gate = new Object(); + + private void dispatch() throws IOException { + sel.select(); + for (Iterator i = sel.selectedKeys().iterator(); i.hasNext(); ) { + SelectionKey sk = (SelectionKey)i.next(); + i.remove(); + Handler h = (Handler)sk.attachment(); + h.handle(sk); + } + synchronized (gate) { } + } + + public void register(SelectableChannel ch, int ops, Handler h) + throws IOException { + synchronized (gate) { + sel.wakeup(); + ch.register(sel, ops, h); + } + } + +} diff --git a/darwin-x86/sample/nio/server/FileContent.java b/darwin-x86/sample/nio/server/FileContent.java new file mode 100644 index 0000000..82c44a9 --- /dev/null +++ b/darwin-x86/sample/nio/server/FileContent.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.net.*; +import java.nio.channels.*; +import java.nio.charset.*; + +/** + * A Content type that provides for transferring files. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class FileContent implements Content { + + private static File ROOT = new File("root"); + + private File fn; + + FileContent(URI uri) { + fn = new File(ROOT, + uri.getPath() + .replace('/', + File.separatorChar)); + } + + private String type = null; + + public String type() { + if (type != null) + return type; + String nm = fn.getName(); + if (nm.endsWith(".html")) + type = "text/html; charset=iso-8859-1"; + else if ((nm.indexOf('.') < 0) || nm.endsWith(".txt")) + type = "text/plain; charset=iso-8859-1"; + else + type = "application/octet-stream"; + return type; + } + + private FileChannel fc = null; + private long length = -1; + private long position = -1; // NB only; >= 0 if transferring + + public long length() { + return length; + } + + public void prepare() throws IOException { + if (fc == null) + fc = new RandomAccessFile(fn, "r").getChannel(); + length = fc.size(); + position = 0; // NB only + } + + public boolean send(ChannelIO cio) throws IOException { + if (fc == null) + throw new IllegalStateException(); + if (position < 0) // NB only + throw new IllegalStateException(); + + /* + * Short-circuit if we're already done. + */ + if (position >= length) { + return false; + } + + position += cio.transferTo(fc, position, length - position); + return (position < length); + } + + public void release() throws IOException { + if (fc != null) { + fc.close(); + fc = null; + } + } +} diff --git a/darwin-x86/sample/nio/server/Handler.java b/darwin-x86/sample/nio/server/Handler.java new file mode 100644 index 0000000..110feb7 --- /dev/null +++ b/darwin-x86/sample/nio/server/Handler.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.channels.*; + +/** + * Base class for the Handlers. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +interface Handler { + + void handle(SelectionKey sk) throws IOException; + +} diff --git a/darwin-x86/sample/nio/server/MalformedRequestException.java b/darwin-x86/sample/nio/server/MalformedRequestException.java new file mode 100644 index 0000000..89b0db6 --- /dev/null +++ b/darwin-x86/sample/nio/server/MalformedRequestException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +/** + * Exception class used when a request can't be properly parsed. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class MalformedRequestException extends Exception { + + MalformedRequestException() { } + + MalformedRequestException(String msg) { + super(msg); + } + + MalformedRequestException(Exception x) { + super(x); + } +} diff --git a/darwin-x86/sample/nio/server/N1.java b/darwin-x86/sample/nio/server/N1.java new file mode 100644 index 0000000..d02bc93 --- /dev/null +++ b/darwin-x86/sample/nio/server/N1.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.nio.channels.*; + +/** + * A non-blocking/single-threaded server. All accept() and + * read()/write() operations are performed by a single thread, but only + * after being selected for those operations by a Selector. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public class N1 extends Server { + + N1(int port, int backlog, boolean secure) throws Exception { + super(port, backlog, secure); + ssc.configureBlocking(false); + } + + void runServer() throws Exception { + Dispatcher d = new Dispatcher1(); + d.register(ssc, SelectionKey.OP_ACCEPT, + new AcceptHandler(ssc, d, sslContext)); + d.run(); + } +} diff --git a/darwin-x86/sample/nio/server/N2.java b/darwin-x86/sample/nio/server/N2.java new file mode 100644 index 0000000..2a21612 --- /dev/null +++ b/darwin-x86/sample/nio/server/N2.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +/** + * A non-blocking/dual-threaded which performs accept()s in one thread, + * and services requests in a second. Both threads use select(). + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public class N2 extends Server { + + N2(int port, int backlog, boolean secure) throws Exception { + super(port, backlog, secure); + } + + void runServer() throws Exception { + Dispatcher d = new DispatcherN(); + Acceptor a = new Acceptor(ssc, d, sslContext); + new Thread(a).start(); + d.run(); + } +} diff --git a/darwin-x86/sample/nio/server/README.txt b/darwin-x86/sample/nio/server/README.txt new file mode 100644 index 0000000..aa803e8 --- /dev/null +++ b/darwin-x86/sample/nio/server/README.txt @@ -0,0 +1,279 @@ + A Simple NIO-based HTTP/HTTPS Server Example + + +INTRODUCTION +============ +This directory contains a simple HTTP/HTTPS server. HTTP/HTTPS are two +common network protocols that provide for data transfer, and are more +fully described in RFC 2616 and RFC 2818 (Available at +http://www.ietf.org ). HTTPS is essentially HTTP after the connection +has been secured with SSL/TLS. TLS is the successor to SSL, and is +described in RFC 2246. + +This server was written to demonstrate some of the functionality new to +the Java 2 platform. The demo is not meant to be a full tutorial, and +assumes the reader has some familiarity with the subject matter. + +In particular, it shows: + + New I/O (java.nio, java.nio.channels, java.util.regex, java.nio.charset) + + Introduced in version 1.4 of the platform, NIO was designed to + overcome some of the scalability limitations found in the + existing blocking java.net.* API's, and to address other + concepts such as Regular Expression parsing and Character + Sets. + + This server demonstrates: + + ByteBuffer + Blocking and Non-Blocking I/O + SocketChannel + ServerSocketChannel + Selector + CharacterSet + Pattern matching using Regular Expressions + + JSSE (javax.net.ssl) + + Introduced in version 1.4 of the platform, JSSE provides + network security using SSL/TLS for java.net.Socket-based + traffic. In version 1.5, the SSLEngine API was introduced + which separates the SSL/TLS functionality from the underlying + I/O model. By making this separation, applications can adapt + I/O and compute strategies to best fit their circumstances. + + This server demonstrates: + + Using SSLEngine to create a HTTPS server + Creating simple key material for use with HTTPS + + Concurrency Library (java.util.concurrent) + + Introduced in version 1.5 of the platform, the concurrency + library provides a mechanism which decouples task submission + from the mechanics of how each task will be run. + + This server demonstrates: + + A ThreadPool with a fixed number of threads, which is + based on the number of available processors. + + +SETUP +===== + +The server must be built on version 1.5 (or later) of the platform. +Invoking the following should be sufficient: + + % mkdir build + % javac -source 1.5 -target 1.5 -d build *.java + +The following creates the document root: + + % mkdir root + +All documents should be placed in this directory. + +For HTTPS, the server authenticates itself to clients by using simple +Public Key Infrastructure (PKI) credentials in the form of +X509Certificates. You must create the server's credentials before +attempting to run the server in "-secure" mode. The server is +currently hardcoded to look for its credentials in a file called +"testkeys". + +In this example, we'll create credentials for a fictional widget web +site owned by the ubiquitous "Xyzzy, Inc.". When you run this in your +own environment, replace "widgets.xyzzy.com" with the hostname of your +server. + +The easiest way to create the SSL/TLS credentials is to use the +java keytool, by doing the following: + + (<CR> represents your end-of-line key) + + % keytool -genkey -keyalg rsa -keystore testkeys -alias widgets + Enter keystore password: passphrase + What is your first and last name? + [Unknown]: widgets.xyzzy.com<CR> + What is the name of your organizational unit? + [Unknown]: Consumer Widgets Group<CR> + What is the name of your organization? + [Unknown]: Xyzzy, Inc.<CR> + What is the name of your City or Locality? + [Unknown]: Arcata<CR> + What is the name of your State or Province? + [Unknown]: CA<CR> + What is the two-letter country code for this unit? + [Unknown]: US<CR> + Is CN=widgets.xyzzy.com, OU=Consumer Widgets Group, O="Xyzzy, Inc.", + L=Arcata, ST=CA, C=US correct? + [no]: yes<CR> + + Enter key password for <mykey> + (RETURN if same as keystore password): <CR> + +This directory also contain a very simple URL reader (URLDumper), which +connects to a specified URL and places all output into a specified file. + + +SERVER EXECUTION +================ + + % java -classpath build Server N1 + + Usage: Server <type> [options] + type: + B1 Blocking/Single-threaded Server + BN Blocking/Multi-threaded Server + BP Blocking/Pooled-thread Server + N1 Nonblocking/Single-threaded Server + N2 Nonblocking/Dual-threaded Server + + options: + -port port port number + default: 8000 + -backlog backlog backlog + default: 1024 + -secure encrypt with SSL/TLS + default is insecure + +"http://" URLs should be used with insecure mode, and +"https://" for secure mode. + +The "B*" servers use classic blocking I/O: in other words, calls to +read()/write() will not return until the I/O operation has completed. The +"N*" servers use non-blocking mode and Selectors to determine which +Channels are ready to perform I/O. + +B1: A single-threaded server which completely services each + connection before moving to the next. + +B2: A multi-threaded server which creates a new thread for each + connection. This is not efficient for large numbers of + connections. + +BP: A multi-threaded server which creates a pool of threads for use + by the server. The Thread pool decides how to schedule those + threads. + +N1: A single-threaded server. All accept() and read()/write() + operations are performed by a single thread, but only after + being selected for those operations by a Selector. + +N2: A dual-threaded server which performs accept()s in one thread, and + services requests in a second. Both threads use select(). + + +CLIENT EXECUTION +================ +You can test the server using any standard browser such as Internet +Explorer or Mozilla, but since the browser will not trust the +credentials you just created, you may need to accept the credentials +via the browser's pop-up dialog box. + +Alternatively, to use the certificates using the simple included JSSE +client URLDumper, export the server certificate into a new truststore, +and then run the application using the new truststore. + + % keytool -export -keystore testkeys -alias widgets -file widgets.cer + Enter keystore password: passphrase<CR> + Certificate stored in file <widgets.cer> + + % keytool -import -keystore trustCerts -alias widgetServer \ + -file widgets.cer + Enter keystore password: passphrase<CR> + Owner: CN=widgets.xyzzy.com, OU=Consumer, O="xyzzy, inc.", L=Arcata, + ST=CA, C=US + Issuer: CN=widgets.xyzzy.com, OU=Consumer, O="xyzzy, inc.", + L=Arcata, ST=CA, C=US + Serial number: 4086cc7a + Valid from: Wed Apr 21 12:33:14 PDT 2004 until: Tue Jul 20 12:33:14 + PDT 2004 + Certificate fingerprints: + MD5: 39:71:42:CD:BF:0D:A9:8C:FB:8B:4A:CD:F8:6D:19:1F + SHA1: 69:5D:38:E9:F4:6C:E5:A7:4C:EA:45:8E:FB:3E:F3:9A:84:01:6F:22 + Trust this certificate? [no]: yes<CR> + Certificate was added to keystore + + % java -classpath build -Djavax.net.ssl.trustStore=trustCerts \ + -Djavax.net.ssl.TrustStorePassword=passphrase \ + URLDumper https://widgets.xyzzy.com:8000/ outputFile + +NOTE: The server must be run with "-secure" in order to receive +"https://" URLs. + +WARNING: This is just a simple example for code exposition, you should +spend more time understanding PKI security concerns. + + +SOURCE CODE OVERVIEW +==================== + +The main class is Server, which handles program startup, and is +subclassed by the "B*" and "N*" server classes. + +Following a successful accept(), the "B*" variants each create a +RequestServicer object to perform the actual request/reply operations. The +primary differences between the different "B*" servers is how the +RequestServicer is actually run: + + B1: RequestServicer.run() is directly called. + BN: A new thread is started, and the thread calls RequestServicer.run(). + BP: A ThreadPool is created, and the pool framework is given Runnable + tasks to complete. + +In the "N*" variations, a Dispatcher object is created, which is +responsible for performing the select, and then issuing the +corresponding handler: + + N1: A single thread is used for all accept()/read()/write() operations + N2: Similar to N1, but a separate thread is used for the accept() + operations. + +In all cases, once the connection has been accepted, a ChannelIO object +is created to handle all I/O. In the insecure case, the corresponding +SocketChannel methods are directly called. However in the secure case, +more manipulations are needed to first secure the channel, then +encrypt/decrypt the data, and finally properly send any shutdown +messages. ChannelIOSecure extends ChannelIO, and provides the secure +variants of the corresponding ChannelIO calls. + +RequestServicer and RequestHandler are the main drivers for the +blocking and non-blocking variants, respectively. They are responsible +for: + + Performing any initial handshaking + + Reading the request data + All data is stored in a local buffer in the ChannelIO + structure. + + Parsing the request + The request data is obtained from the ChannelIO object, and + is processed by Request class, which represents the + parsed URI address. + + Locating/preparing/sending the data or reporting error conditions. + A Reply object is created which represents the entire object to send, + including the HTTP/HTTPS headers. + + Shutdown/closing the channel. + + +CLOSING THOUGHTS +================ +This example represents a simple server: it is not production quality. +It was primarily meant to demonstrate the new APIs in versions 1.4 and +1.5 of the platform. + +This example could certainly be expanded to address other areas of +concern: for example, assigning multiple threads to handle the selected +Channels, or delegating SSLEngine tasks to multiple threads. There are +so many ways to implement compute and I/O strategies, we encourage you +to experiment and find what works best for your situation. + +To steal a phrase from many textbooks: + + "It is left as an exercise for the reader..." + diff --git a/darwin-x86/sample/nio/server/Reply.java b/darwin-x86/sample/nio/server/Reply.java new file mode 100644 index 0000000..c128ee8 --- /dev/null +++ b/darwin-x86/sample/nio/server/Reply.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; +import java.nio.charset.*; + +/** + * An object used for sending Content to the requestor. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class Reply implements Sendable { + + /** + * A helper class which define the HTTP response codes + */ + static class Code { + + private int number; + private String reason; + private Code(int i, String r) { number = i; reason = r; } + public String toString() { return number + " " + reason; } + + static Code OK = new Code(200, "OK"); + static Code BAD_REQUEST = new Code(400, "Bad Request"); + static Code NOT_FOUND = new Code(404, "Not Found"); + static Code METHOD_NOT_ALLOWED = new Code(405, "Method Not Allowed"); + + } + + private Code code; + private Content content; + private boolean headersOnly; + + Reply(Code rc, Content c) { + this(rc, c, null); + } + + Reply(Code rc, Content c, Request.Action head) { + code = rc; + content = c; + headersOnly = (head == Request.Action.HEAD); + } + + private static String CRLF = "\r\n"; + private static Charset ascii = Charset.forName("US-ASCII"); + + private ByteBuffer hbb = null; + + private ByteBuffer headers() { + CharBuffer cb = CharBuffer.allocate(1024); + for (;;) { + try { + cb.put("HTTP/1.0 ").put(code.toString()).put(CRLF); + cb.put("Server: niossl/0.1").put(CRLF); + cb.put("Content-type: ").put(content.type()).put(CRLF); + cb.put("Content-length: ") + .put(Long.toString(content.length())).put(CRLF); + cb.put(CRLF); + break; + } catch (BufferOverflowException x) { + assert(cb.capacity() < (1 << 16)); + cb = CharBuffer.allocate(cb.capacity() * 2); + continue; + } + } + cb.flip(); + return ascii.encode(cb); + } + + public void prepare() throws IOException { + content.prepare(); + hbb = headers(); + } + + public boolean send(ChannelIO cio) throws IOException { + + if (hbb == null) + throw new IllegalStateException(); + + if (hbb.hasRemaining()) { + if (cio.write(hbb) <= 0) + return true; + } + + if (!headersOnly) { + if (content.send(cio)) + return true; + } + + if (!cio.dataFlush()) + return true; + + return false; + } + + public void release() throws IOException { + content.release(); + } +} diff --git a/darwin-x86/sample/nio/server/Request.java b/darwin-x86/sample/nio/server/Request.java new file mode 100644 index 0000000..fa36d1e --- /dev/null +++ b/darwin-x86/sample/nio/server/Request.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.net.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.regex.*; + +/** + * An encapsulation of the request received. + * <P> + * The static method parse() is responsible for creating this + * object. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class Request { + + /** + * A helper class for parsing HTTP command actions. + */ + static class Action { + + private String name; + private Action(String name) { this.name = name; } + public String toString() { return name; } + + static Action GET = new Action("GET"); + static Action PUT = new Action("PUT"); + static Action POST = new Action("POST"); + static Action HEAD = new Action("HEAD"); + + static Action parse(String s) { + if (s.equals("GET")) + return GET; + if (s.equals("PUT")) + return PUT; + if (s.equals("POST")) + return POST; + if (s.equals("HEAD")) + return HEAD; + throw new IllegalArgumentException(s); + } + } + + private Action action; + private String version; + private URI uri; + + Action action() { return action; } + String version() { return version; } + URI uri() { return uri; } + + private Request(Action a, String v, URI u) { + action = a; + version = v; + uri = u; + } + + public String toString() { + return (action + " " + version + " " + uri); + } + + static boolean isComplete(ByteBuffer bb) { + int p = bb.position() - 4; + if (p < 0) + return false; + return (((bb.get(p + 0) == '\r') && + (bb.get(p + 1) == '\n') && + (bb.get(p + 2) == '\r') && + (bb.get(p + 3) == '\n'))); + } + + private static Charset ascii = Charset.forName("US-ASCII"); + + /* + * The expected message format is first compiled into a pattern, + * and is then compared against the inbound character buffer to + * determine if there is a match. This convienently tokenizes + * our request into usable pieces. + * + * This uses Matcher "expression capture groups" to tokenize + * requests like: + * + * GET /dir/file HTTP/1.1 + * Host: hostname + * + * into: + * + * group[1] = "GET" + * group[2] = "/dir/file" + * group[3] = "1.1" + * group[4] = "hostname" + * + * The text in between the parens are used to captured the regexp text. + */ + private static Pattern requestPattern + = Pattern.compile("\\A([A-Z]+) +([^ ]+) +HTTP/([0-9\\.]+)$" + + ".*^Host: ([^ ]+)$.*\r\n\r\n\\z", + Pattern.MULTILINE | Pattern.DOTALL); + + static Request parse(ByteBuffer bb) throws MalformedRequestException { + + CharBuffer cb = ascii.decode(bb); + Matcher m = requestPattern.matcher(cb); + if (!m.matches()) + throw new MalformedRequestException(); + Action a; + try { + a = Action.parse(m.group(1)); + } catch (IllegalArgumentException x) { + throw new MalformedRequestException(); + } + URI u; + try { + u = new URI("http://" + + m.group(4) + + m.group(2)); + } catch (URISyntaxException x) { + throw new MalformedRequestException(); + } + return new Request(a, m.group(3), u); + } +} diff --git a/darwin-x86/sample/nio/server/RequestHandler.java b/darwin-x86/sample/nio/server/RequestHandler.java new file mode 100644 index 0000000..91d2bda --- /dev/null +++ b/darwin-x86/sample/nio/server/RequestHandler.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; + +/** + * Primary driver class used by non-blocking Servers to receive, + * prepare, send, and shutdown requests. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class RequestHandler implements Handler { + + private ChannelIO cio; + private ByteBuffer rbb = null; + + private boolean requestReceived = false; + private Request request = null; + private Reply reply = null; + + private static int created = 0; + + RequestHandler(ChannelIO cio) { + this.cio = cio; + + // Simple heartbeat to let user know we're alive. + synchronized (RequestHandler.class) { + created++; + if ((created % 50) == 0) { + System.out.println("."); + created = 0; + } else { + System.out.print("."); + } + } + } + + // Returns true when request is complete + // May expand rbb if more room required + // + private boolean receive(SelectionKey sk) throws IOException { + ByteBuffer tmp = null; + + if (requestReceived) { + return true; + } + + if (!cio.doHandshake(sk)) { + return false; + } + + if ((cio.read() < 0) || Request.isComplete(cio.getReadBuf())) { + rbb = cio.getReadBuf(); + return (requestReceived = true); + } + return false; + } + + // When parse is successfull, saves request and returns true + // + private boolean parse() throws IOException { + try { + request = Request.parse(rbb); + return true; + } catch (MalformedRequestException x) { + reply = new Reply(Reply.Code.BAD_REQUEST, + new StringContent(x)); + } + return false; + } + + // Ensures that reply field is non-null + // + private void build() throws IOException { + Request.Action action = request.action(); + if ((action != Request.Action.GET) && + (action != Request.Action.HEAD)) { + reply = new Reply(Reply.Code.METHOD_NOT_ALLOWED, + new StringContent(request.toString())); + } + reply = new Reply(Reply.Code.OK, + new FileContent(request.uri()), action); + } + + public void handle(SelectionKey sk) throws IOException { + try { + + if (request == null) { + if (!receive(sk)) + return; + rbb.flip(); + if (parse()) + build(); + try { + reply.prepare(); + } catch (IOException x) { + reply.release(); + reply = new Reply(Reply.Code.NOT_FOUND, + new StringContent(x)); + reply.prepare(); + } + if (send()) { + // More bytes remain to be written + sk.interestOps(SelectionKey.OP_WRITE); + } else { + // Reply completely written; we're done + if (cio.shutdown()) { + cio.close(); + reply.release(); + } + } + } else { + if (!send()) { // Should be rp.send() + if (cio.shutdown()) { + cio.close(); + reply.release(); + } + } + } + } catch (IOException x) { + String m = x.getMessage(); + if (!m.equals("Broken pipe") && + !m.equals("Connection reset by peer")) { + System.err.println("RequestHandler: " + x.toString()); + } + + try { + /* + * We had a failure here, so we'll try to be nice + * before closing down and send off a close_notify, + * but if we can't get the message off with one try, + * we'll just shutdown. + */ + cio.shutdown(); + } catch (IOException e) { + // ignore + } + + cio.close(); + if (reply != null) { + reply.release(); + } + } + + } + + private boolean send() throws IOException { + try { + return reply.send(cio); + } catch (IOException x) { + if (x.getMessage().startsWith("Resource temporarily")) { + System.err.println("## RTA"); + return true; + } + throw x; + } + } +} diff --git a/darwin-x86/sample/nio/server/RequestServicer.java b/darwin-x86/sample/nio/server/RequestServicer.java new file mode 100644 index 0000000..88d40b5 --- /dev/null +++ b/darwin-x86/sample/nio/server/RequestServicer.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; + +/** + * Primary driver class used by blocking Servers to receive, + * prepare, send, and shutdown requests. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class RequestServicer implements Runnable { + + private ChannelIO cio; + + private static int created = 0; + + RequestServicer(ChannelIO cio) { + this.cio = cio; + + // Simple heartbeat to let user know we're alive. + synchronized (RequestServicer.class) { + created++; + if ((created % 50) == 0) { + System.out.println("."); + created = 0; + } else { + System.out.print("."); + } + } + } + + private void service() throws IOException { + Reply rp = null; + try { + ByteBuffer rbb = receive(); // Receive + Request rq = null; + try { // Parse + rq = Request.parse(rbb); + } catch (MalformedRequestException x) { + rp = new Reply(Reply.Code.BAD_REQUEST, + new StringContent(x)); + } + if (rp == null) rp = build(rq); // Build + do {} while (rp.send(cio)); // Send + do {} while (!cio.shutdown()); + cio.close(); + rp.release(); + } catch (IOException x) { + String m = x.getMessage(); + if (!m.equals("Broken pipe") && + !m.equals("Connection reset by peer")) { + System.err.println("RequestHandler: " + x.toString()); + } + + try { + /* + * We had a failure here, so we'll try to be nice + * before closing down and send off a close_notify, + * but if we can't get the message off with one try, + * we'll just shutdown. + */ + cio.shutdown(); + } catch (IOException e) { + // ignore + } + + cio.close(); + if (rp != null) { + rp.release(); + } + } + } + + public void run() { + try { + service(); + } catch (IOException x) { + x.printStackTrace(); + } + } + + ByteBuffer receive() throws IOException { + + do {} while (!cio.doHandshake()); + + for (;;) { + int read = cio.read(); + ByteBuffer bb = cio.getReadBuf(); + if ((read < 0) || (Request.isComplete(bb))) { + bb.flip(); + return bb; + } + } + } + + Reply build(Request rq) throws IOException { + + Reply rp = null; + Request.Action action = rq.action(); + if ((action != Request.Action.GET) && + (action != Request.Action.HEAD)) + rp = new Reply(Reply.Code.METHOD_NOT_ALLOWED, + new StringContent(rq.toString())); + else + rp = new Reply(Reply.Code.OK, + new FileContent(rq.uri()), action); + try { + rp.prepare(); + } catch (IOException x) { + rp.release(); + rp = new Reply(Reply.Code.NOT_FOUND, + new StringContent(x)); + rp.prepare(); + } + return rp; + } +} diff --git a/darwin-x86/sample/nio/server/Sendable.java b/darwin-x86/sample/nio/server/Sendable.java new file mode 100644 index 0000000..44ac848 --- /dev/null +++ b/darwin-x86/sample/nio/server/Sendable.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; + +/** + * Method definitions used for preparing, sending, and release + * content. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +interface Sendable { + + void prepare() throws IOException; + + // Sends (some) content to the given channel. + // Returns true if more bytes remain to be written. + // Throws IllegalStateException if not prepared. + // + boolean send(ChannelIO cio) throws IOException; + + void release() throws IOException; +} diff --git a/darwin-x86/sample/nio/server/Server.java b/darwin-x86/sample/nio/server/Server.java new file mode 100644 index 0000000..1ac6421 --- /dev/null +++ b/darwin-x86/sample/nio/server/Server.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.net.*; +import java.nio.channels.*; +import java.security.*; +import javax.net.ssl.*; + +/** + * The main server base class. + * <P> + * This class is responsible for setting up most of the server state + * before the actual server subclasses take over. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +public abstract class Server { + + ServerSocketChannel ssc; + SSLContext sslContext = null; + + static private int PORT = 8000; + static private int BACKLOG = 1024; + static private boolean SECURE = false; + + Server(int port, int backlog, + boolean secure) throws Exception { + + if (secure) { + createSSLContext(); + } + + ssc = ServerSocketChannel.open(); + ssc.socket().setReuseAddress(true); + ssc.socket().bind(new InetSocketAddress(port), backlog); + } + + /* + * If this is a secure server, we now setup the SSLContext we'll + * use for creating the SSLEngines throughout the lifetime of + * this process. + */ + private void createSSLContext() throws Exception { + + char[] passphrase = "passphrase".toCharArray(); + + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(new FileInputStream("testkeys"), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ks); + + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } + + abstract void runServer() throws Exception; + + static private void usage() { + System.out.println( + "Usage: Server <type> [options]\n" + + " type:\n" + + " B1 Blocking/Single-threaded Server\n" + + " BN Blocking/Multi-threaded Server\n" + + " BP Blocking/Pooled-Thread Server\n" + + " N1 Nonblocking/Single-threaded Server\n" + + " N2 Nonblocking/Dual-threaded Server\n" + + "\n" + + " options:\n" + + " -port port port number\n" + + " default: " + PORT + "\n" + + " -backlog backlog backlog\n" + + " default: " + BACKLOG + "\n" + + " -secure encrypt with SSL/TLS"); + System.exit(1); + } + + /* + * Parse the arguments, decide what type of server to run, + * see if there are any defaults to change. + */ + static private Server createServer(String args[]) throws Exception { + if (args.length < 1) { + usage(); + } + + int port = PORT; + int backlog = BACKLOG; + boolean secure = SECURE; + + for (int i = 1; i < args.length; i++) { + if (args[i].equals("-port")) { + checkArgs(i, args.length); + port = Integer.valueOf(args[++i]); + } else if (args[i].equals("-backlog")) { + checkArgs(i, args.length); + backlog = Integer.valueOf(args[++i]); + } else if (args[i].equals("-secure")) { + secure = true; + } else { + usage(); + } + } + + Server server = null; + + if (args[0].equals("B1")) { + server = new B1(port, backlog, secure); + } else if (args[0].equals("BN")) { + server = new BN(port, backlog, secure); + } else if (args[0].equals("BP")) { + server = new BP(port, backlog, secure); + } else if (args[0].equals("N1")) { + server = new N1(port, backlog, secure); + } else if (args[0].equals("N2")) { + server = new N2(port, backlog, secure); + } + + return server; + } + + static private void checkArgs(int i, int len) { + if ((i + 1) >= len) { + usage(); + } + } + + static public void main(String args[]) throws Exception { + Server server = createServer(args); + + if (server == null) { + usage(); + } + + System.out.println("Server started."); + server.runServer(); + } +} diff --git a/darwin-x86/sample/nio/server/StringContent.java b/darwin-x86/sample/nio/server/StringContent.java new file mode 100644 index 0000000..267b338 --- /dev/null +++ b/darwin-x86/sample/nio/server/StringContent.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.nio.*; +import java.nio.charset.*; + +/** + * A Content type that provides for transferring Strings. + * + * @author Mark Reinhold + * @author Brad R. Wetmore + */ +class StringContent implements Content { + + private static Charset ascii = Charset.forName("US-ASCII"); + + private String type; // MIME type + private String content; + + StringContent(CharSequence c, String t) { + content = c.toString(); + if (!content.endsWith("\n")) + content += "\n"; + type = t + "; charset=iso-8859-1"; + } + + StringContent(CharSequence c) { + this(c, "text/plain"); + } + + StringContent(Exception x) { + StringWriter sw = new StringWriter(); + x.printStackTrace(new PrintWriter(sw)); + type = "text/plain; charset=iso-8859-1"; + content = sw.toString(); + } + + public String type() { + return type; + } + + private ByteBuffer bb = null; + + private void encode() { + if (bb == null) + bb = ascii.encode(CharBuffer.wrap(content)); + } + + public long length() { + encode(); + return bb.remaining(); + } + + public void prepare() { + encode(); + bb.rewind(); + } + + public boolean send(ChannelIO cio) throws IOException { + if (bb == null) + throw new IllegalStateException(); + cio.write(bb); + + return bb.hasRemaining(); + } + + public void release() throws IOException { + } +} diff --git a/darwin-x86/sample/nio/server/URLDumper.java b/darwin-x86/sample/nio/server/URLDumper.java new file mode 100644 index 0000000..30166e7 --- /dev/null +++ b/darwin-x86/sample/nio/server/URLDumper.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004, 2011, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +import java.io.*; +import java.net.*; + +/** + * A simple example to illustrate using a URL to access a resource + * and then store the result to a File. + * <P> + * Any type of URL can be used: http, https, ftp, etc. + * + * @author Brad R. Wetmore + * @author Mark Reinhold + */ +public class URLDumper { + public static void main(String[] args) throws Exception { + + if (args.length != 2) { + System.out.println("Usage: URLDumper <URL> <file>"); + System.exit(1); + } + + String location = args[0]; + String file = args[1]; + + URL url = new URL(location); + FileOutputStream fos = new FileOutputStream(file); + + byte [] bytes = new byte [4096]; + + InputStream is = url.openStream(); + + int read; + + while ((read = is.read(bytes)) != -1) { + fos.write(bytes, 0, read); + } + + is.close(); + fos.close(); + } +} diff --git a/darwin-x86/sample/scripting/scriptpad/README.txt b/darwin-x86/sample/scripting/scriptpad/README.txt new file mode 100644 index 0000000..ab4bd5f --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/README.txt @@ -0,0 +1,122 @@ +Scriptpad Sample + +* Introduction + +Scriptpad is a notepad like editor to open/edit/save and run +script (JavaScript) files. This sample demonstrates the use of +javax.script (JSR-223) API and JavaScript engine that is bundled +with JDK 6. + +Scriptpad sample demonstrates how to use Javascript to use Java +classes and objects to perform various tasks such as to modify, +customize Swing GUI or to connect to a running application and +monitor it using JMX (Java Management Extensions) API. + +* How to run Scriptpad? + +Scriptpad can be run with the following command: + + java -jar ./build/scriptpad.jar + +(be sure to use the correct version of java). You can +open/edit/save scripts using menu items under "File" menu. +To run currently edited script, you can use "Tools->Run" menu. + +For example, you may enter + + alert("hello, world"); + +in the editor and run the same with "Tools->Run" menu. +You will see an alert box with the message "hello, world". + +In addition to being a simple script editor/runner, scriptpad +can be used to connect to a JMX MBean server ("Tools->JMX Connect" +menu). User can specify JMX hostname and port. After connecting, +user can use "monitoring and management" script functions defined +in "mm.js" (see below). + +* Scriptpad Sources + +com.sun.demo.scriptpad.Main class is the entry point of this +sample. This class creates ScriptEngine and evaluates few +JavaScript "files" -- which are stored as resources (please +refer to src/resources/*.js). Actual code for the scriptpad's +main functionality lives in these JavaScript files. + +1. conc.js + -- simple concurrency utilities for JavaScript + +2. gui.js + -- simple GUI utilities for JavaScript + +3. mm.js + -- Monitoring and Management utilities for JavaScript + +4. scriptpad.js + -- This creates main "notepad"-like GUI for open/edit/save + and run script files + +5. Main.js + -- This script file can be used under "jrunscript" tool. + jrunscript is an experimental tool shipped with JDK (under + $JDK_HOME/bin directory). The scriptpad application can be + run by the following commands: + + cd ./src/resources + $JDK_HOME/bin/jrunscript -f Main.js -f - + + +* Extending Scriptpad: + +It is possible to extend scriptpad using scripts. There is a global +object called "application". This object has 2 fields and a method. + + Fields of the application object: + + frame -> JFrame of the scriptpad + editor -> editor pane of the scriptpad + + Method of the application object: + + addTool -> adds a menu item under "Tools" menu + + Example script to add "Tools->Hello" menu item: + + application.addTool("Hello", + function() { alert("hello, world"); }); + +After running the above script, you can click Tools->Hello menu item +and you'll see an alert box. + +Scriptpad customization may also be done by defining a file named +"scriptpad.js" under your home directory,. If this file is found, +scriptpad loads this file just after initializating everything. +In your initialization file, you can additional script functions +by "load" function. + +* Script Samples: + +On clicking the menu items under "Examples" menu, scriptpad shows +built-in examples in the editor. Also, there are few script samples +under the ./src/scripts directory. + +* Monitoring and Management with Scriptpad: + +(1) Start the application with the JMX agent - here's an example of + how the Java2D demo is started + + java -Dcom.sun.management.jmxremote.port=1090 \ + -Dcom.sun.management.jmxremote.ssl=false \ + -Dcom.sun.management.jmxremote.authenticate=false \ + -jar $JDK_HOME/demo/jfc/Font2DTest/Font2DTest.jar + +(2) Start scriptpad and click on "Tools->JMX Connect" menu. + In the prompt, enter "localhost:1090" to connect to the above + program. + +After connecting to a MBeanServer (using "Tools->JMX Connect"), +you can run any script that uses functions defined in "mm.js". +For example, it is possible to load and run management scripts that +are part of JConsole script shell plugin under the directory: + + $JDK_HOME/demo/scripting/jconsole-plugin/src/scripts diff --git a/darwin-x86/sample/scripting/scriptpad/build.properties b/darwin-x86/sample/scripting/scriptpad/build.properties new file mode 100644 index 0000000..efcd591 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/build.properties @@ -0,0 +1,22 @@ +main.dir=. + +src.dir=${main.dir}/src + +build.dir=build +classes.dir=${build.dir}/classes +jar=${build.dir}/scriptpad.jar +javadoc.dir=${build.dir}/javadoc + +build.sysclasspath=ignore +# E.g.: cp=lib/x.jar:lib/y.jar +cp= +extra.run.cp= + +main.class=com.sun.sample.scriptpad.Main + +run.cp=${cp}:${classes.dir}:${extra.run.cp} + +debug=true +deprecation=false + +nbjdk.home=${basedir}/../../.. diff --git a/darwin-x86/sample/scripting/scriptpad/build.xml b/darwin-x86/sample/scripting/scriptpad/build.xml new file mode 100644 index 0000000..5f203d5 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/build.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + + +<!-- + This is ant (http://ant.apache.org) build script to build the + "Scriptpad" sample. Either this build.xml can be used standalone + with "ant" tool or can be opened as a project with NetBeans IDE + (http://www.netbeans.org). +--> + +<project name="Scriptpad" default="jar" basedir="."> + + <import file="nbproject/jdk.xml"/> + + <target name="-prop-init"> + <property file="user.build.properties"/> + <property file="build.properties"/> + </target> + + <target name="-init" depends="-prop-init,-jdk-init"/> + + <target name="compile" depends="-init" description="Compile main sources."> + <mkdir dir="${classes.dir}"/> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="${debug}" deprecation="${deprecation}"> + <classpath path="${cp}"/> + </javac> + <copy todir="${classes.dir}"> + <fileset dir="${src.dir}"/> + </copy> + </target> + + <target name="jar" depends="compile" description="Build JAR file for main sources."> + <jar jarfile="${jar}" compress="true"> + <manifest> + <attribute name="Main-Class" value="${main.class}"/> + </manifest> + <fileset dir="${classes.dir}"/> + </jar> + </target> + + <target name="run" depends="compile" description="Run application."> + <fail unless="main.class">Must set property 'main.class' (e.g. in build.properties)</fail> + <java classname="${main.class}" fork="true" failonerror="true"> + <classpath path="${run.cp}"/> + </java> + </target> + + <target name="javadoc" depends="-init" description="Build Javadoc."> + <mkdir dir="${javadoc.dir}"/> + <javadoc destdir="${javadoc.dir}"> + <classpath path="${cp}"/> + <sourcepath> + <pathelement location="${src.dir}"/> + </sourcepath> + <fileset dir="${src.dir}"/> + </javadoc> + </target> + + <target name="clean" depends="-init" description="Clean build products."> + <delete dir="${build.dir}"/> + <delete file="${jar}"/> + </target> + + <target name="profile"> + <ant antfile="nbproject/netbeans-targets.xml" target="profile"/> + </target> +</project> diff --git a/darwin-x86/sample/scripting/scriptpad/nbproject/file-targets.xml b/darwin-x86/sample/scripting/scriptpad/nbproject/file-targets.xml new file mode 100644 index 0000000..0904977 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/nbproject/file-targets.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project basedir=".." name="scriptpad/file"> + + <import file="../build.xml"/> + + <target name="compile-selected" depends="-init"> + <fail unless="includes">Must set property 'includes'</fail> + <mkdir dir="${classes.dir}"/> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="${debug}" deprecation="${deprecation}" includes="${includes}"> + <classpath path="${cp}"/> + </javac> + </target> + +</project> diff --git a/darwin-x86/sample/scripting/scriptpad/nbproject/jdk.xml b/darwin-x86/sample/scripting/scriptpad/nbproject/jdk.xml new file mode 100644 index 0000000..2b85b77 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/nbproject/jdk.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project name="jdk" basedir="."> + + <target name="-jdk-preinit"> + <condition property=".exe" value=".exe"> + <os family="windows"/> + </condition> + <property name=".exe" value=""/> + <property name="nbjdk.javac" value="${nbjdk.home}/bin/javac${.exe}"/> + <property name="nbjdk.java" value="${nbjdk.home}/bin/java${.exe}"/> + <property name="nbjdk.javadoc" value="${nbjdk.home}/bin/javadoc${.exe}"/> + <property name="nbjdk.appletviewer" value="${nbjdk.home}/bin/appletviewer${.exe}"/> + <property name="nbjdk.bootclasspath" value="${nbjdk.home}/jre/lib/rt.jar"/> + </target> + + <target name="-jdk-presetdef-basic" depends="-jdk-preinit" unless="nbjdk.presetdef.basic.done"> + <macrodef name="javac-presetdef"> + <attribute name="javacval"/> + <sequential> + <presetdef name="javac"> + <javac fork="yes" executable="@{javacval}"/> + </presetdef> + </sequential> + </macrodef> + <javac-presetdef javacval="${nbjdk.javac}"/> + <macrodef name="java-presetdef"> + <attribute name="javaval"/> + <sequential> + <presetdef name="java"> + <java fork="yes" jvm="@{javaval}"/> + </presetdef> + </sequential> + </macrodef> + <java-presetdef javaval="${nbjdk.java}"/> + <macrodef name="javadoc-presetdef"> + <attribute name="javadocval"/> + <sequential> + <presetdef name="javadoc"> + <javadoc executable="@{javadocval}"/> + </presetdef> + </sequential> + </macrodef> + <javadoc-presetdef javadocval="${nbjdk.javadoc}"/> + <property name="nbjdk.presetdef.basic.done" value="true"/> + </target> + + <target name="-jdk-presetdef-nbjpdastart" depends="-jdk-preinit" unless="nbjdk.presetdef.nbjpdastart.done"> + <macrodef name="nbjpdastart-presetdef"> + <attribute name="bootcpval"/> + <sequential> + <presetdef name="nbjpdastart"> + <nbjpdastart> + <bootclasspath> + <path path="@{bootcpval}"/> + </bootclasspath> + </nbjpdastart> + </presetdef> + </sequential> + </macrodef> + <nbjpdastart-presetdef bootcpval="${nbjdk.bootclasspath}"/> + <property name="nbjdk.presetdef.nbjpdastart.done" value="true"/> + </target> + + <target name="-jdk-init" depends="-jdk-preinit,-jdk-presetdef-basic"/> + +</project> diff --git a/darwin-x86/sample/scripting/scriptpad/nbproject/netbeans-targets.xml b/darwin-x86/sample/scripting/scriptpad/nbproject/netbeans-targets.xml new file mode 100644 index 0000000..b53c34d --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/nbproject/netbeans-targets.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project basedir=".." name="scriptpad/NB"> + + <import file="../build.xml"/> + + <target name="debug" depends="compile,-jdk-presetdef-nbjpdastart"> + <nbjpdastart addressproperty="jpda.address" name="scriptpad" transport="dt_socket"> + <classpath path="${run.cp}"/> + </nbjpdastart> + <java classname="${main.class}" failonerror="true" fork="true"> + <classpath path="${run.cp}"/> + <jvmarg value="-Xdebug"/> + <jvmarg value="-Xnoagent"/> + <jvmarg value="-Djava.compiler=none"/> + <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> + </java> + </target> + + <target name="debug-fix" depends="-init"> + <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="true" deprecation="${deprecation}"> + <classpath path="${cp}"/> + <include name="${class}.java"/> + </javac> + <nbjpdareload> + <fileset dir="${classes.dir}"> + <include name="${class}.class"/> + </fileset> + </nbjpdareload> + </target> + + <target name="show-javadoc" depends="javadoc"> + <nbbrowse file="${javadoc.dir}/index.html"/> + </target> + + <target name="profile" depends="compile"> + <nbprofiledirect> + <classpath path="${run.cp}"/> + </nbprofiledirect> + <property environment="env"/> + <java classname="${main.class}" fork="true" failonerror="true" dir="${profiler.session.working.dir}" jvm="${profiler.info.jvm}"> + <classpath path="${run.cp}"/> + <jvmarg value="${profiler.info.jvmargs.agent}"/> + <jvmarg line="${profiler.info.jvmargs}"/> + <env key="LD_LIBRARY_PATH" path="${profiler.info.agentpath}:${env.LD_LIBRARY_PATH}"/> + <env key="Path" path="${profiler.info.agentpath}:${env.Path}"/> + </java> + </target> + +</project> diff --git a/darwin-x86/sample/scripting/scriptpad/nbproject/project.xml b/darwin-x86/sample/scripting/scriptpad/nbproject/project.xml new file mode 100644 index 0000000..32135c7 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/nbproject/project.xml @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright (c) 2006, 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. +--> + +<project xmlns="http://www.netbeans.org/ns/project/1"> + <type>org.netbeans.modules.ant.freeform</type> + <configuration> + <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1"> + <name>Scriptpad</name> + <properties> + <property-file>user.build.properties</property-file> + <property-file>build.properties</property-file> + <property name="nbjdk.bootclasspath">${nbjdk.home}/jre/lib/rt.jar</property> + </properties> + <folders> + <source-folder> + <label>JDK Demo</label> + <location>${main.dir}</location> + </source-folder> + <source-folder> + <label>Sources</label> + <type>java</type> + <location>${src.dir}</location> + </source-folder> + <build-folder> + <location>${build.dir}</location> + </build-folder> + </folders> + <ide-actions> + <action name="build"> + <target>jar</target> + </action> + <action name="clean"> + <target>clean</target> + </action> + <action name="rebuild"> + <target>clean</target> + <target>jar</target> + </action> + <action name="run"> + <target>run</target> + </action> + <action name="javadoc"> + <script>nbproject/netbeans-targets.xml</script> + <target>show-javadoc</target> + </action> + <action name="debug"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug</target> + </action> + <action name="compile.single"> + <script>nbproject/file-targets.xml</script> + <target>compile-selected</target> + <context> + <property>includes</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>relative-path</format> + <arity> + <separated-files>,</separated-files> + </arity> + </context> + </action> + <action name="run.single"> + <target>run</target> + <context> + <property>main.class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>java-name</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + <action name="debug.single"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug</target> + <context> + <property>main.class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>java-name</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + <action name="debug.fix"> + <script>nbproject/netbeans-targets.xml</script> + <target>debug-fix</target> + <context> + <property>class</property> + <folder>${src.dir}</folder> + <pattern>\.java$</pattern> + <format>relative-path-noext</format> + <arity> + <one-file-only/> + </arity> + </context> + </action> + </ide-actions> + <export> + <type>jar</type> + <location>${jar}</location> + <build-target>jar</build-target> + <clean-target>clean</clean-target> + </export> + <view> + <items> + <source-folder style="packages"> + <label>Sources</label> + <location>${src.dir}</location> + </source-folder> + <source-file> + <location>${main.dir}/README.txt</location> + </source-file> + </items> + <context-menu> + <ide-action name="build"/> + <ide-action name="rebuild"/> + <ide-action name="clean"/> + <ide-action name="javadoc"/> + <separator/> + <ide-action name="run"/> + <ide-action name="debug"/> + </context-menu> + </view> + <subprojects/> + </general-data> + <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2"> + <compilation-unit> + <package-root>${src.dir}</package-root> + <classpath mode="compile">${cp}</classpath> + <classpath mode="execute">${run.cp}</classpath> + <classpath mode="boot">${nbjdk.bootclasspath}</classpath> + <built-to>${classes.dir}</built-to> + <built-to>${jar}</built-to> + <javadoc-built-to>${javadoc.dir}</javadoc-built-to> + <source-level>1.5</source-level> + </compilation-unit> + </java-data> + </configuration> +</project> diff --git a/darwin-x86/sample/scripting/scriptpad/src/META-INF/manifest.mf b/darwin-x86/sample/scripting/scriptpad/src/META-INF/manifest.mf new file mode 100644 index 0000000..76eda30 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/META-INF/manifest.mf @@ -0,0 +1,2 @@ +Main-Class: com.sun.sample.scriptpad.Main + diff --git a/darwin-x86/sample/scripting/scriptpad/src/com/sun/sample/scriptpad/Main.java b/darwin-x86/sample/scripting/scriptpad/src/com/sun/sample/scriptpad/Main.java new file mode 100644 index 0000000..aaeb58d --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/com/sun/sample/scriptpad/Main.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +package com.sun.sample.scriptpad; + +import javax.script.*; +import java.io.*; + +/** + * This is the entry point of "Scriptpad" sample. This class creates + * ScriptEngine and evaluates few JavaScript "files" -- which are stored + * as resources (please refer to src/resources/*.js). Actual code for the + * scriptpad's main functionality lives in these JavaScript files. + */ +public class Main { + public static void main(String[] args) throws Exception { + + // create a ScriptEngineManager + ScriptEngineManager m = new ScriptEngineManager(); + // get an instance of JavaScript script engine + ScriptEngine engine = m.getEngineByName("js"); + + // expose the current script engine as a global variable + engine.put("engine", engine); + + // evaluate few scripts that are bundled in "resources" + eval(engine, "conc.js"); + eval(engine, "gui.js"); + eval(engine, "scriptpad.js"); + eval(engine, "mm.js"); + } + + private static void eval(ScriptEngine engine, String name) + throws Exception { + /* + * This class is compiled into a jar file. The jar file + * contains few scripts under /resources URL. + */ + InputStream is = Main.class.getResourceAsStream("/resources/" + name); + // current script file name for better error messages + engine.put(ScriptEngine.FILENAME, name); + // evaluate the script in the InputStream + engine.eval(new InputStreamReader(is)); + } +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/resources/Main.js b/darwin-x86/sample/scripting/scriptpad/src/resources/Main.js new file mode 100644 index 0000000..a1c332d --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/resources/Main.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script can be loaded in jrunscript to start scriptpad. + * + * jrunscript -f Main.js -f - + */ + +load("conc.js"); +load("gui.js"); +load("scriptpad.js"); +load("mm.js"); diff --git a/darwin-x86/sample/scripting/scriptpad/src/resources/conc.js b/darwin-x86/sample/scripting/scriptpad/src/resources/conc.js new file mode 100644 index 0000000..aaca49a --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/resources/conc.js @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * Concurrency utilities for JavaScript. These are based on + * java.lang and java.util.concurrent API. The following functions + * provide a simpler API for scripts. Instead of directly using java.lang + * and java.util.concurrent classes, scripts can use functions and + * objects exported from here. + */ + +// shortcut for j.u.c lock classes +var Lock = java.util.concurrent.locks.ReentrantLock; +var RWLock = java.util.concurrent.locks.ReentrantReadWriteLock; + +// check if there is a build in sync function, define one if missing +if (typeof sync === "undefined") { + var sync = function(func, obj) { + if (arguments.length < 1 || arguments.length > 2 ) { + throw "sync(function [,object]) parameter count mismatch"; + } + + var syncobj = (arguments.length == 2 ? obj : this); + + if (!syncobj._syncLock) { + syncobj._syncLock = new Lock(); + } + + return function() { + syncobj._syncLock.lock(); + try { + func.apply(null, arguments); + } finally { + syncobj._syncLock.unlock(); + } + }; + }; + sync.docString = "synchronize a function, optionally on an object"; +} + +/** + * Wrapper for java.lang.Object.wait + * + * can be called only within a sync method + */ +function wait(object) { + var objClazz = java.lang.Class.forName('java.lang.Object'); + var waitMethod = objClazz.getMethod('wait', null); + waitMethod.invoke(object, null); +} +wait.docString = "convenient wrapper for java.lang.Object.wait method"; + +/** + * Wrapper for java.lang.Object.notify + * + * can be called only within a sync method + */ +function notify(object) { + var objClazz = java.lang.Class.forName('java.lang.Object'); + var notifyMethod = objClazz.getMethod('notify', null); + notifyMethod.invoke(object, null); +} +notify.docString = "convenient wrapper for java.lang.Object.notify method"; + +/** + * Wrapper for java.lang.Object.notifyAll + * + * can be called only within a sync method + */ +function notifyAll(object) { + var objClazz = java.lang.Class.forName('java.lang.Object'); + var notifyAllMethod = objClazz.getMethod('notifyAll', null); + notifyAllMethod.invoke(object, null); +} +notifyAll.docString = "convenient wrapper for java.lang.Object.notifyAll method"; + +/** + * Creates a java.lang.Runnable from a given script + * function. + */ +Function.prototype.runnable = function() { + var args = arguments; + var func = this; + return new java.lang.Runnable() { + run: function() { + func.apply(null, args); + } + } +}; + +/** + * Executes the function on a new Java Thread. + */ +Function.prototype.thread = function() { + var t = new java.lang.Thread(this.runnable.apply(this, arguments)); + t.start(); + return t; +}; + +/** + * Executes the function on a new Java daemon Thread. + */ +Function.prototype.daemon = function() { + var t = new java.lang.Thread(this.runnable.apply(this, arguments)); + t.setDaemon(true); + t.start(); + return t; +}; + +/** + * Creates a java.util.concurrent.Callable from a given script + * function. + */ +Function.prototype.callable = function() { + var args = arguments; + var func = this; + return new java.util.concurrent.Callable() { + call: function() { return func.apply(null, args); } + } +}; + +/** + * Registers the script function so that it will be called exit. + */ +Function.prototype.atexit = function () { + var args = arguments; + java.lang.Runtime.getRuntime().addShutdownHook( + new java.lang.Thread(this.runnable.apply(this, args))); +}; + +/** + * Executes the function asynchronously. + * + * @return a java.util.concurrent.FutureTask + */ +Function.prototype.future = (function() { + // default executor for future + var juc = java.util.concurrent; + var theExecutor = juc.Executors.newSingleThreadExecutor(); + // clean-up the default executor at exit + (function() { theExecutor.shutdown(); }).atexit(); + return function() { + return theExecutor.submit(this.callable.apply(this, arguments)); + }; +})(); + +/** + * Executes a function after acquiring given lock. On return, + * (normal or exceptional), lock is released. + * + * @param lock lock that is locked and unlocked + */ +Function.prototype.sync = function (lock) { + if (arguments.length == 0) { + throw "lock is missing"; + } + var res = new Array(arguments.length - 1); + for (var i = 0; i < res.length; i++) { + res[i] = arguments[i + 1]; + } + lock.lock(); + try { + this.apply(null, res); + } finally { + lock.unlock(); + } +}; + +/** + * Causes current thread to sleep for specified + * number of milliseconds + * + * @param interval in milliseconds + */ +function sleep(interval) { + java.lang.Thread.sleep(interval); +} +sleep.docString = "wrapper for java.lang.Thread.sleep method"; + +/** + * Schedules a task to be executed once in N milliseconds specified. + * + * @param callback function or expression to evaluate + * @param interval in milliseconds to sleep + * @return timeout ID (which is nothing but Thread instance) + */ +function setTimeout(callback, interval) { + if (! (callback instanceof Function)) { + callback = new Function(callback); + } + + // start a new thread that sleeps given time + // and calls callback in an infinite loop + return (function() { + try { + sleep(interval); + } catch (x) { } + callback(); + }).daemon(); +} +setTimeout.docString = "calls given callback once after specified interval"; + +/** + * Cancels a timeout set earlier. + * @param tid timeout ID returned from setTimeout + */ +function clearTimeout(tid) { + // we just interrupt the timer thread + tid.interrupt(); +} +clearTimeout.docString = "interrupt a setTimeout timer"; + +/** + * Schedules a task to be executed once in + * every N milliseconds specified. + * + * @param callback function or expression to evaluate + * @param interval in milliseconds to sleep + * @return timeout ID (which is nothing but Thread instance) + */ +function setInterval(callback, interval) { + if (! (callback instanceof Function)) { + callback = new Function(callback); + } + + // start a new thread that sleeps given time + // and calls callback in an infinite loop + return (function() { + while (true) { + try { + sleep(interval); + } catch (x) { + break; + } + callback(); + } + }).daemon(); +} +setInterval.docString = "calls given callback every specified interval"; + +/** + * Cancels a timeout set earlier. + * @param tid timeout ID returned from setTimeout + */ +function clearInterval(tid) { + // we just interrupt the timer thread + tid.interrupt(); +} +clearInterval.docString = "interrupt a setInterval timer"; + +/** + * Simple access to thread local storage. + * + * Script sample: + * + * __thread.x = 44; + * function f() { + * __thread.x = 'hello'; + * print(__thread.x); + * } + * f.thread(); // prints 'hello' + * print(__thread.x); // prints 44 in main thread + */ +var __thread = (function () { + var map = new Object(); + return new JSAdapter({ + __has__: function(name) { + return map[name] != undefined; + }, + __get__: function(name) { + if (map[name] != undefined) { + return map[name].get(); + } else { + return undefined; + } + }, + __put__: sync(function(name, value) { + if (map[name] == undefined) { + var tmp = new java.lang.ThreadLocal(); + tmp.set(value); + map[name] = tmp; + } else { + map[name].set(value); + } + }), + __delete__: function(name) { + if (map[name] != undefined) { + map[name].set(null); + } + } + }); +})(); + diff --git a/darwin-x86/sample/scripting/scriptpad/src/resources/gui.js b/darwin-x86/sample/scripting/scriptpad/src/resources/gui.js new file mode 100644 index 0000000..d62b92f --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/resources/gui.js @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * Few user interface utilities. + */ + +if (this.window === undefined) { + this.window = null; +} + +/** + * Swing invokeLater - invokes given function in AWT event thread + */ +Function.prototype.invokeLater = function() { + var SwingUtilities = javax.swing.SwingUtilities; + var func = this; + var args = arguments; + SwingUtilities.invokeLater(new java.lang.Runnable() { + run: function() { + func.apply(func, args); + } + }); +}; + +/** + * Swing invokeAndWait - invokes given function in AWT event thread + * and waits for it's completion + */ +Function.prototype.invokeAndWait = function() { + var SwingUtilities = javax.swing.SwingUtilities; + var func = this; + var args = arguments; + SwingUtilities.invokeAndWait(new java.lang.Runnable() { + run: function() { + func.apply(func, args); + } + }); +}; + +/** + * Am I running in AWT event dispatcher thread? + */ +function isEventThread() { + var SwingUtilities = javax.swing.SwingUtilities; + return SwingUtilities.isEventDispatchThread(); +} +isEventThread.docString = "returns whether the current thread is GUI thread"; + +/** + * Opens a file dialog box + * + * @param curDir current directory [optional] + * @param save flag tells whether this is a save dialog or not + * @return selected file or else null + */ +function fileDialog(curDir, save) { + var result; + function _fileDialog() { + if (curDir == undefined) { + curDir = new java.io.File("."); + } + + var JFileChooser = javax.swing.JFileChooser; + var dialog = new JFileChooser(curDir); + var res = save ? dialog.showSaveDialog(window): + dialog.showOpenDialog(window); + + if (res == JFileChooser.APPROVE_OPTION) { + result = dialog.getSelectedFile(); + } else { + result = null; + } + } + + if (isEventThread()) { + _fileDialog(); + } else { + _fileDialog.invokeAndWait(); + } + + return result; +} +fileDialog.docString = "show a file dialog box"; + +/** + * Opens a color chooser dialog box + * + * @param title of the dialog box [optional] + * @param color default color [optional] + * @return chosen color or default color + */ +function colorDialog(title, color) { + var result; + + function _colorDialog() { + if (title == undefined) { + title = "Choose Color"; + } + + if (color == undefined) { + color = java.awt.Color.BLACK; + } + + var chooser = new javax.swing.JColorChooser(); + var res = chooser.showDialog(window, title, color); + result = res ? res : color; + } + + if (isEventThread()) { + _colorDialog(); + } else { + _colorDialog.invokeAndWait(); + } + + return result; +} +colorDialog.docString = "shows a color chooser dialog box"; + +/** + * Shows a message box + * + * @param msg message to be shown + * @param title title of message box [optional] + * @param msgType type of message box [constants in JOptionPane] + */ +function msgBox(msg, title, msgType) { + function _msgBox() { + var JOptionPane = javax.swing.JOptionPane; + if (msg === undefined) msg = "undefined"; + if (msg === null) msg = "null"; + if (title == undefined) title = msg; + if (msgType == undefined) msgType = JOptionPane.INFORMATION_MESSAGE; + JOptionPane.showMessageDialog(window, msg, title, msgType); + } + + if (isEventThread()) { + _msgBox(); + } else { + _msgBox.invokeAndWait(); + } +} +msgBox.docString = "shows MessageBox to the user"; + +/** + * Shows an information alert box + * + * @param msg message to be shown + * @param title title of message box [optional] + */ +function alert(msg, title) { + var JOptionPane = javax.swing.JOptionPane; + msgBox(msg, title, JOptionPane.INFORMATION_MESSAGE); +} +alert.docString = "shows an alert message box to the user"; + +/** + * Shows an error alert box + * + * @param msg message to be shown + * @param title title of message box [optional] + */ +function error(msg, title) { + var JOptionPane = javax.swing.JOptionPane; + msgBox(msg, title, JOptionPane.ERROR_MESSAGE); +} +error.docString = "shows an error message box to the user"; + +/** + * Shows a warning alert box + * + * @param msg message to be shown + * @param title title of message box [optional] + */ +function warn(msg, title) { + var JOptionPane = javax.swing.JOptionPane; + msgBox(msg, title, JOptionPane.WARNING_MESSAGE); +} +warn.docString = "shows a warning message box to the user"; + +/** + * Shows a prompt dialog box + * + * @param question question to be asked + * @param answer default answer suggested [optional] + * @return answer given by user + */ +function prompt(question, answer) { + var result; + function _prompt() { + var JOptionPane = javax.swing.JOptionPane; + if (answer == undefined) answer = ""; + result = JOptionPane.showInputDialog(window, question, answer); + } + + if (isEventThread()) { + _prompt(); + } else { + _prompt.invokeAndWait(); + } + + return result; +} +prompt.docString = "shows a prompt box to the user and returns the answer"; + +/** + * Shows a confirmation dialog box + * + * @param msg message to be shown + * @param title title of message box [optional] + * @return boolean (yes->true, no->false) + */ +function confirm(msg, title) { + var result; + var JOptionPane = javax.swing.JOptionPane; + + function _confirm() { + if (title == undefined) title = msg; + var optionType = JOptionPane.YES_NO_OPTION; + result = JOptionPane.showConfirmDialog(window, msg, title, optionType); + } + + if (isEventThread()) { + _confirm(); + } else { + _confirm.invokeAndWait(); + } + + return result == JOptionPane.YES_OPTION; +} +confirm.docString = "shows a confirmation message box to the user"; + +/** + * Exit the process after confirmation from user + * + * @param exitCode return code to OS [optional] + */ +function exit(exitCode) { + if (exitCode == undefined) exitCode = 0; + if (confirm("Do you really want to exit?")) { + java.lang.System.exit(exitCode); + } +} +exit.docString = "exits jconsole"; + +// synonym to exit +var quit = exit; + +// if echo function is not defined, define it as synonym +// for println function +if (this.echo == undefined) { + function echo(str) { + println(str); + } +} + diff --git a/darwin-x86/sample/scripting/scriptpad/src/resources/mm.js b/darwin-x86/sample/scripting/scriptpad/src/resources/mm.js new file mode 100644 index 0000000..07efad2 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/resources/mm.js @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This is a collection of utilities for Monitoring + * and management API. + * + * File dependency: + * conc.js -> for concurrency utilities + */ + +// At any time, we maintain atmost one MBeanServer +// connection. And so, we store the same as a global +// variable. +var mmConnection = null; + +function jmxConnect(hostport) { + if (mmConnection != null) { + // close the existing connection + try { + mmConnection.close(); + } catch (e) { + } + } + + var JMXServiceURL = javax.management.remote.JMXServiceURL; + var JMXConnectorFactory = javax.management.remote.JMXConnectorFactory; + + var urlPath = "/jndi/rmi://" + hostport + "/jmxrmi"; + var url = new JMXServiceURL("rmi", "", 0, urlPath); + var jmxc = JMXConnectorFactory.connect(url); + // note that the "mmConnection" is a global variable! + mmConnection = jmxc.getMBeanServerConnection(); +} +jmxConnect.docString = "connects to the given host, port (specified as name:port)"; + +function mbeanConnection() { + if (mmConnection == null) { + throw "Not connected to MBeanServer yet!"; + } + + return mmConnection; +} +mbeanConnection.docString = "returns the current MBeanServer connection"; + +/** + * Returns a platform MXBean proxy for given MXBean name and interface class + */ +function newPlatformMXBeanProxy(name, intf) { + var factory = java.lang.management.ManagementFactory; + return factory.newPlatformMXBeanProxy(mbeanConnection(), name, intf); +} +newPlatformMXBeanProxy.docString = "returns a proxy for a platform MXBean"; + +/** + * Wraps a string to ObjectName if needed. + */ +function objectName(objName) { + var ObjectName = Packages.javax.management.ObjectName; + if (objName instanceof ObjectName) { + return objName; + } else { + return new ObjectName(objName); + } +} +objectName.docString = "creates JMX ObjectName for a given String"; + +/** + * Creates a new (M&M) Attribute object + * + * @param name name of the attribute + * @param value value of the attribute + */ +function attribute(name, value) { + var Attribute = Packages.javax.management.Attribute; + return new Attribute(name, value); +} +attribute.docString = "returns a new JMX Attribute using name and value given"; + +/** + * Returns MBeanInfo for given ObjectName. Strings are accepted. + */ +function mbeanInfo(objName) { + objName = objectName(objName); + return mbeanConnection().getMBeanInfo(objName); +} +mbeanInfo.docString = "returns MBeanInfo of a given ObjectName"; + +/** + * Returns ObjectInstance for a given ObjectName. + */ +function objectInstance(objName) { + objName = objectName(objName); + return mbeanConnection().objectInstance(objectName); +} +objectInstance.docString = "returns ObjectInstance for a given ObjectName"; + +/** + * Queries with given ObjectName and QueryExp. + * QueryExp may be null. + * + * @return set of ObjectNames. + */ +function queryNames(objName, query) { + objName = objectName(objName); + if (query == undefined) query = null; + return mbeanConnection().queryNames(objName, query); +} +queryNames.docString = "returns QueryNames using given ObjectName and optional query"; + +/** + * Queries with given ObjectName and QueryExp. + * QueryExp may be null. + * + * @return set of ObjectInstances. + */ +function queryMBeans(objName, query) { + objName = objectName(objName); + if (query == undefined) query = null; + return mbeanConnection().queryMBeans(objName, query); +} +queryMBeans.docString = "return MBeans using given ObjectName and optional query"; + +// wraps a script array as java.lang.Object[] +function objectArray(array) { + return Java.to(array, "java.lang.Object[]"); +} + +// wraps a script (string) array as java.lang.String[] +function stringArray(array) { + return Java.to(array, "java.lang.String[]"); +} + +// script array to Java List +function toAttrList(array) { + var AttributeList = Packages.javax.management.AttributeList; + if (array instanceof AttributeList) { + return array; + } + var list = new AttributeList(array.length); + for (var index = 0; index < array.length; index++) { + list.add(array[index]); + } + return list; +} + +// Java Collection (Iterable) to script array +function toArray(collection) { + if (collection instanceof Array) { + return collection; + } + var itr = collection.iterator(); + var array = new Array(); + while (itr.hasNext()) { + array[array.length] = itr.next(); + } + return array; +} + +// gets MBean attributes +function getMBeanAttributes(objName, attributeNames) { + objName = objectName(objName); + return mbeanConnection().getAttributes(objName,stringArray(attributeNames)); +} +getMBeanAttributes.docString = "returns specified Attributes of given ObjectName"; + +// gets MBean attribute +function getMBeanAttribute(objName, attrName) { + objName = objectName(objName); + return mbeanConnection().getAttribute(objName, attrName); +} +getMBeanAttribute.docString = "returns a single Attribute of given ObjectName"; + +// sets MBean attributes +function setMBeanAttributes(objName, attrList) { + objName = objectName(objName); + attrList = toAttrList(attrList); + return mbeanConnection().setAttributes(objName, attrList); +} +setMBeanAttributes.docString = "sets specified Attributes of given ObjectName"; + +// sets MBean attribute +function setMBeanAttribute(objName, attrName, attrValue) { + var Attribute = Packages.javax.management.Attribute; + objName = objectName(objName); + mbeanConnection().setAttribute(objName, new Attribute(attrName, attrValue)); +} +setMBeanAttribute.docString = "sets a single Attribute of given ObjectName"; + +// invokes an operation on given MBean +function invokeMBean(objName, operation, params, signature) { + objName = objectName(objName); + params = objectArray(params); + signature = stringArray(signature); + return mbeanConnection().invoke(objName, operation, params, signature); +} +invokeMBean.docString = "invokes MBean operation on given ObjectName"; + +/** + * Wraps a MBean specified by ObjectName as a convenient + * script object -- so that setting/getting MBean attributes + * and invoking MBean method can be done with natural syntax. + * + * @param objName ObjectName of the MBean + * @param async asynchornous mode [optional, default is false] + * @return script wrapper for MBean + * + * With async mode, all field, operation access is async. Results + * will be of type FutureTask. When you need value, call 'get' on it. + */ +function mbean(objName, async) { + var index; + objName = objectName(objName); + var info = mbeanInfo(objName); + var attrs = info.attributes; + var attrMap = new Object; + for (index in attrs) { + attrMap[attrs[index].name] = attrs[index]; + } + var opers = info.operations; + var operMap = new Object; + for (index in opers) { + operMap[opers[index].name] = opers[index]; + } + + function isAttribute(name) { + return name in attrMap; + } + + function isOperation(name) { + return name in operMap; + } + + return new JSAdapter() { + __has__: function (name) { + return isAttribute(name) || isOperation(name); + }, + __get__: function (name) { + if (isAttribute(name)) { + if (async) { + return getMBeanAttribute.future(objName, name); + } else { + return getMBeanAttribute(objName, name); + } + } else { + return undefined; + } + }, + __call__: function(name) { + if (isOperation(name)) { + var oper = operMap[name]; + + var params = []; + for (var j = 1; j < arguments.length; j++) { + params[j-1]= arguments[j]; + } + + var sigs = oper.signature; + + var sigNames = new Array(sigs.length); + for (var index in sigs) { + sigNames[index] = sigs[index].getType(); + } + + if (async) { + return invokeMBean.future(objName, name, params, sigNames); + } else { + return invokeMBean(objName, name, params, sigNames); + } + } else { + return undefined; + } + }, + __put__: function (name, value) { + if (isAttribute(name)) { + if (async) { + setMBeanAttribute.future(objName, name, value); + } else { + setMBeanAttribute(objName, name, value); + } + } else { + return undefined; + } + } + }; +} +mbean.docString = "returns a conveninent script wrapper for a MBean of given ObjectName"; + +if (this.application != undefined) { + this.application.addTool("JMX Connect", + // connect to a JMX MBean Server + function () { + var url = prompt("Connect to JMX server (host:port)"); + if (url != null) { + try { + jmxConnect(url); + alert("connected!"); + } catch (e) { + error(e, "Can not connect to " + url); + } + } + }); +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/resources/scriptpad.js b/darwin-x86/sample/scripting/scriptpad/src/resources/scriptpad.js new file mode 100644 index 0000000..807d05e --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/resources/scriptpad.js @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script creates a simple Notepad-like interface, which + * serves as a simple script editor, runner. + * + * File dependency: + * + * gui.js -> for basic GUI functions + */ + +/* + * globalThis is used for actionHelpGlobals() and showFrame(). + */ +var globalThis = this; + +/* + * JavaImporter helps in avoiding pollution of JavaScript + * global namespace. We can import multiple Java packages + * with this and use the JavaImporter object with "with" + * statement. + */ +var guiPkgs = new JavaImporter(java.awt, java.awt.event, + javax.swing, javax.swing.undo, + javax.swing.event, javax.swing.text); + +// main entry point of the scriptpad application +var main = function() { + function createEditor() { + var c = new guiPkgs.JTextArea(); + c.setDragEnabled(true); + c.setFont(new guiPkgs.Font("monospaced", guiPkgs.Font.PLAIN, 12)); + return c; + } + + /*const*/ var titleSuffix = "- Scriptpad"; + /*const*/ var defaultTitle = "Untitled" + titleSuffix; + + // Scriptpad's main frame + var frame; + // Scriptpad's main editor + var editor; + + // To track the current file name + var curFileName = null; + + // To track whether the current document + // has been modified or not + var docChanged = false; + + // check and alert user for unsaved + // but modified document + function checkDocChanged() { + if (docChanged) { + // ignore zero-content untitled document + if (curFileName == null && + editor.document.length == 0) { + return; + } + + if (confirm("Do you want to save the changes?", + "The document has changed")) { + actionSave(); + } + } + } + + // set a document listener to track + // whether that is modified or not + function setDocListener() { + var doc = editor.getDocument(); + docChanged = false; + doc.addDocumentListener( new guiPkgs.DocumentListener() { + equals: function(o) { + return this === o; }, + toString: function() { + return "doc listener"; }, + changeUpdate: function() { + docChanged = true; }, + insertUpdate: function() { + docChanged = true; }, + removeUpdate: function() { + docChanged = true; } + }); + } + + // menu action functions + + // "File" menu + + // create a "new" document + function actionNew() { + checkDocChanged(); + curFileName = null; + editor.setDocument(new guiPkgs.PlainDocument()); + setDocListener(); + frame.setTitle(defaultTitle); + editor.revalidate(); + } + + // open an existing file + function actionOpen() { + checkDocChanged(); + var f = fileDialog(); + if (f == null) { + return; + } + + if (f.isFile() && f.canRead()) { + frame.setTitle(f.getName() + titleSuffix); + editor.setDocument(new guiPkgs.PlainDocument()); + var progress = new guiPkgs.JProgressBar(); + progress.setMinimum(0); + progress.setMaximum(f.length()); + var doc = editor.getDocument(); + var inp = new java.io.FileReader(f); + var buff = java.lang.reflect.Array.newInstance( + java.lang.Character.TYPE, 4096); + var nch; + while ((nch = inp.read(buff, 0, buff.length)) != -1) { + doc.insertString(doc.getLength(), + new java.lang.String(buff, 0, nch), null); + progress.setValue(progress.getValue() + nch); + } + inp.close(); + curFileName = f.getAbsolutePath(); + setDocListener(); + } else { + error("Can not open file: " + f, + "Error opening file: " + f); + } + } + + // open script from a URL + function actionOpenURL() { + checkDocChanged(); + var url = prompt("Address:"); + if (url == null) { + return; + } + + try { + var u = new java.net.URL(url); + editor.setDocument(new guiPkgs.PlainDocument()); + frame.setTitle(url + titleSuffix); + var progress = new guiPkgs.JProgressBar(); + progress.setMinimum(0); + progress.setIndeterminate(true); + var doc = editor.getDocument(); + var inp = new java.io.InputStreamReader(u.openStream()); + var buff = java.lang.reflect.Array.newInstance( + java.lang.Character.TYPE, 4096); + var nch; + while ((nch = inp.read(buff, 0, buff.length)) != -1) { + doc.insertString(doc.getLength(), + new java.lang.String(buff, 0, nch), null); + progress.setValue(progress.getValue() + nch); + } + curFileName = null; + setDocListener(); + } catch (e) { + error("Error opening URL: " + e, + "Can not open URL: " + url); + } + } + + // factored out "save" function used by + // save, save as menu actions + function save(file) { + var doc = editor.getDocument(); + frame.setTitle(file.getName() + titleSuffix); + curFileName = file; + var progress = new guiPkgs.JProgressBar(); + progress.setMinimum(0); + progress.setMaximum(file.length()); + var out = new java.io.FileWriter(file); + var text = new guiPkgs.Segment(); + text.setPartialReturn(true); + var charsLeft = doc.getLength(); + var offset = 0; + var min; + + while (charsLeft > 0) { + doc.getText(offset, Math.min(4096, charsLeft), text); + out.write(text.array, text.offset, text.count); + charsLeft -= text.count; + offset += text.count; + progress.setValue(offset); + java.lang.Thread.sleep(10); + } + + out.flush(); + out.close(); + docChanged = false; + } + + // file-save as menu + function actionSaveAs() { + var ret = fileDialog(null, true); + if (ret == null) { + return; + } + save(ret); + } + + // file-save menu + function actionSave() { + if (curFileName) { + save(new java.io.File(curFileName)); + } else { + actionSaveAs(); + } + } + + // exit from scriptpad + function actionExit() { + checkDocChanged(); + java.lang.System.exit(0); + } + + // "Edit" menu + + // cut the currently selected text + function actionCut() { + editor.cut(); + } + + // copy the currently selected text to clipboard + function actionCopy() { + editor.copy(); + } + + // paste clipboard content to document + function actionPaste() { + editor.paste(); + } + + // select all the text in editor + function actionSelectAll() { + editor.selectAll(); + } + + // "Tools" menu + + // run the current document as JavaScript + function actionRun() { + var doc = editor.getDocument(); + var script = doc.getText(0, doc.getLength()); + var oldFile = engine.get(javax.script.ScriptEngine.FILENAME); + try { + if (engine == undefined) { + var m = new javax.script.ScriptEngineManager(); + engine = m.getEngineByName("nashorn"); + } + engine.put(javax.script.ScriptEngine.FILENAME, frame.title); + engine.eval(script, context); + } catch (e) { + error(e, "Script Error"); + e.printStackTrace(); + } finally { + engine.put(javax.script.ScriptEngine.FILENAME, oldFile); + } + } + + // "Examples" menu + + // show given script as new document + function showScript(title, str) { + actionNew(); + frame.setTitle("Example - " + title + titleSuffix); + var doc = editor.document; + doc.insertString(0, str, null); + } + + // "hello world" + function actionHello() { + showScript(actionEval.title, + "alert('Hello, world');"); + } + actionHello.title = "Hello, World"; + + // eval the "hello world"! + function actionEval() { + showScript(actionEval.title, + "eval(\"alert('Hello, world')\");"); + } + actionEval.title = "Eval"; + + // show how to access Java static methods + function actionJavaStatic() { + showScript(arguments.callee.title, + "// Just use Java syntax\n" + + "var props = java.lang.System.getProperties();\n" + + "alert(props.get('os.name'));"); + } + actionJavaStatic.title = "Java Static Calls"; + + // show how to access Java classes, methods + function actionJavaAccess() { + showScript(arguments.callee.title, + "// just use new JavaClass();\n" + + "var fr = new javax.swing.JFrame();\n" + + "// call all public methods as in Java\n" + + "fr.setTitle('hello');\n" + + "fr.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);\n" + + "fr.setSize(200, 200);\n" + + "fr.setVisible(true);"); + } + actionJavaAccess.title = "Java Object Access"; + + // show how to use Java bean conventions + function actionJavaBean() { + showScript(arguments.callee.title, + "var fr = new javax.swing.JFrame();\n" + + "fr.setSize(200, 200);\n" + + "// access public get/set methods as fields\n" + + "fr.defaultCloseOperation = javax.swing.WindowConstants.DISPOSE_ON_CLOSE;\n" + + "fr.title = 'hello';\n" + + "fr.visible = true;"); + } + actionJavaBean.title = "Java Beans"; + + // show how to implement Java interface + function actionJavaInterface() { + showScript(arguments.callee.title, + "// use Java anonymizer class-like syntax!\n" + + "var r = new java.lang.Runnable() {\n" + + " run: function() {\n" + + " alert('hello');\n" + + " }\n" + + " };\n" + + "// use the above Runnable to create a Thread\n" + + "new java.lang.Thread(r).start();\n" + + "// For simple one method interfaces, just pass script function\n" + + "new java.lang.Thread(function() { alert('world'); }).start();"); + } + actionJavaInterface.title = "Java Interfaces"; + + // show how to import Java classes, packages + function actionJavaImport() { + showScript(arguments.callee.title, + "// use Java-like import *...\n" + + "// importPackage(java.io);\n" + + "// or import a specific class\n" + + "// importClass(java.io.File);\n" + + "// or better - import just within a scope!\n" + + "var ioPkgs = JavaImporter(java.io);\n" + + "with (ioPkgs) { alert(new File('.').absolutePath); }"); + } + actionJavaImport.title = "Java Import"; + + // "Help" menu + + /* + * Shows a one liner help message for each + * global function. Note that this function + * depends on docString meta-data for each + * function. + */ + function actionHelpGlobals() { + var names = new java.util.ArrayList(); + for (var i in globalThis) { + var func = globalThis[i]; + if (typeof(func) == "function" && + ("docString" in func)) { + names.add(i); + } + } + java.util.Collections.sort(names); + var helpDoc = new java.lang.StringBuffer(); + helpDoc.append("<table border='1'>"); + var itr = names.iterator(); + while (itr.hasNext()) { + var name = itr.next(); + helpDoc.append("<tr><td>"); + helpDoc.append(name); + helpDoc.append("</td><td>"); + helpDoc.append(globalThis[name].docString); + helpDoc.append("</td></tr>"); + } + helpDoc.append("</table>"); + + var helpEditor = new guiPkgs.JEditorPane(); + helpEditor.setContentType("text/html"); + helpEditor.setEditable(false); + helpEditor.setText(helpDoc.toString()); + + var scroller = new guiPkgs.JScrollPane(); + var port = scroller.getViewport(); + port.add(helpEditor); + + var helpFrame = new guiPkgs.JFrame("Help - Global Functions"); + helpFrame.getContentPane().add("Center", scroller); + helpFrame.setDefaultCloseOperation(guiPkgs.WindowConstants.DISPOSE_ON_CLOSE); + helpFrame.pack(); + helpFrame.setSize(500, 600); + helpFrame.setVisible(true); + } + + // show a simple about message for scriptpad + function actionAbout() { + alert("Scriptpad\nVersion 1.1", "Scriptpad"); + } + + /* + * This data is used to construct menu bar. + * This way adding a menu is easier. Just add + * top level menu or add an item to an existing + * menu. "action" should be a function that is + * called back on clicking the correponding menu. + */ + var menuData = [ + { + menu: "File", + items: [ + { name: "New", action: actionNew , accel: guiPkgs.KeyEvent.VK_N }, + { name: "Open...", action: actionOpen, accel: guiPkgs.KeyEvent.VK_O }, + { name: "Open URL...", action: actionOpenURL, accel: guiPkgs.KeyEvent.VK_U }, + { name: "Save", action: actionSave, accel: guiPkgs.KeyEvent.VK_S }, + { name: "Save As...", action: actionSaveAs }, + { name: "-" }, + { name: "Exit", action: actionExit, accel: guiPkgs.KeyEvent.VK_Q } + ] + }, + + { + menu: "Edit", + items: [ + { name: "Cut", action: actionCut, accel: guiPkgs.KeyEvent.VK_X }, + { name: "Copy", action: actionCopy, accel: guiPkgs.KeyEvent.VK_C }, + { name: "Paste", action: actionPaste, accel: guiPkgs.KeyEvent.VK_V }, + { name: "-" }, + { name: "Select All", action: actionSelectAll, accel: guiPkgs.KeyEvent.VK_A } + ] + }, + + { + menu: "Tools", + items: [ + { name: "Run", action: actionRun, accel: guiPkgs.KeyEvent.VK_R } + ] + }, + + { + menu: "Examples", + items: [ + { name: actionHello.title, action: actionHello }, + { name: actionEval.title, action: actionEval }, + { name: actionJavaStatic.title, action: actionJavaStatic }, + { name: actionJavaAccess.title, action: actionJavaAccess }, + { name: actionJavaBean.title, action: actionJavaBean }, + { name: actionJavaInterface.title, action: actionJavaInterface }, + { name: actionJavaImport.title, action: actionJavaImport } + ] + }, + + { + menu: "Help", + items: [ + { name: "Global Functions", action: actionHelpGlobals }, + { name: "-" }, + { name: "About Scriptpad", action: actionAbout } + ] + } + ]; + + function setMenuAccelerator(mi, accel) { + var keyStroke = guiPkgs.KeyStroke.getKeyStroke(accel, + guiPkgs.Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); + mi.setAccelerator(keyStroke); + } + + // create a menubar using the above menu data + function createMenubar() { + var mb = new guiPkgs.JMenuBar(); + for (var m in menuData) { + var items = menuData[m].items; + var menu = new guiPkgs.JMenu(menuData[m].menu); + + for (var i in items) { + if (items[i].name.equals("-")) { + menu.addSeparator(); + } else { + var mi = new guiPkgs.JMenuItem(items[i].name); + var action = items[i].action; + mi.addActionListener(action); + var accel = items[i].accel; + if (accel) { + setMenuAccelerator(mi, accel); + } + menu.add(mi); + } + } + + mb.add(menu); + } + + return mb; + } + + // function to add a new menu item under "Tools" menu + function addTool(menuItem, action, accel) { + if (typeof(action) != "function") { + return; + } + + var toolsIndex = -1; + // find the index of the "Tools" menu + for (var i in menuData) { + if (menuData[i].menu.equals("Tools")) { + toolsIndex = i; + break; + } + } + if (toolsIndex == -1) { + return; + } + var toolsMenu = frame.getJMenuBar().getMenu(toolsIndex); + var mi = new guiPkgs.JMenuItem(menuItem); + mi.addActionListener(action); + if (accel) { + setMenuAccelerator(mi, accel); + } + toolsMenu.add(mi); + } + + // create Scriptpad frame + function createFrame() { + frame = new guiPkgs.JFrame(); + frame.setTitle(defaultTitle); + frame.setBackground(guiPkgs.Color.lightGray); + frame.getContentPane().setLayout(new guiPkgs.BorderLayout()); + + // create notepad panel + var notepad = new guiPkgs.JPanel(); + notepad.setBorder(guiPkgs.BorderFactory.createEtchedBorder()); + notepad.setLayout(new guiPkgs.BorderLayout()); + + // create editor + editor = createEditor(); + var scroller = new guiPkgs.JScrollPane(); + var port = scroller.getViewport(); + port.add(editor); + + // add editor to notepad panel + var panel = new guiPkgs.JPanel(); + panel.setLayout(new guiPkgs.BorderLayout()); + panel.add("Center", scroller); + notepad.add("Center", panel); + + // add notepad panel to frame + frame.getContentPane().add("Center", notepad); + + // set menu bar to frame and show the frame + frame.setJMenuBar(createMenubar()); + frame.setDefaultCloseOperation(guiPkgs.JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setSize(500, 600); + } + + // show Scriptpad frame + function showFrame() { + // set global variable by the name "window" + globalThis.window = frame; + + // open new document + actionNew(); + + frame.setVisible(true); + } + + // create and show Scriptpad frame + createFrame(); + showFrame(); + + /* + * Application object has two fields "frame", "editor" + * which are current JFrame and editor and a method + * called "addTool" to add new menu item to "Tools" menu. + */ + return { + frame: frame, + editor: editor, + addTool: addTool + }; +}; + +/* + * Call the main and store Application object + * in a global variable named "application". + */ +var application = main(); + +if (this.load == undefined) { + function load(file) { + var ioPkgs = new JavaImporter(java.io); + with (ioPkgs) { + var stream = new FileInputStream(file); + var bstream = new BufferedInputStream(stream); + var reader = new BufferedReader(new InputStreamReader(bstream)); + var oldFilename = engine.get(engine.FILENAME); + engine.put(engine.FILENAME, file); + try { + engine.eval(reader, context); + } finally { + engine.put(engine.FILENAME, oldFilename); + } + stream.close(); + } + } + load.docString = "loads the given script file"; +} + +/* + * Load user specific init file under home dir, if found. + */ +function loadUserInit() { + var home = java.lang.System.getProperty("user.home"); + var f = new java.io.File(home, "scriptpad.js"); + if (f.exists()) { + engine.eval(new java.io.FileReader(f)); + } +} + +loadUserInit(); diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/README.txt b/darwin-x86/sample/scripting/scriptpad/src/scripts/README.txt new file mode 100644 index 0000000..72e162d --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/README.txt @@ -0,0 +1,52 @@ +Sample scripts: + +(1) browse.js + + -- Open and run this script in scriptpad. You will see + Tools->Browse menu. Using this you can start your + desktop default browser with the given URL. + +(2) insertfile.js + + -- Open and run this script in scriptpad. You will see + "Tools->Insert File..." menu. Using this you can start + insert content of a selected file into currently + edited document + +(3) linewrap.js + + -- Open and run this script in scriptpad. You will see + "Tools->Line Wrap" menu. Using this you can toggle + the line wrapping mode of the editor + +(4) mail.js + + -- Open and run this script in scriptpad. You will see + Tools->Mail menu. Using this you can start your + desktop default mail client with the given "To" mail id. + +(5) memmonitor.js + + -- This is a simple Monitoring & Management script. To use this, + you need an application to monitor. You can use memory.bat + or memory.sh in the current directory to start an application + that will be monitored. After that please follow these steps: + + 1. Start the target application using memory.sh or memory.bat + 2. Start scriptpad + 3. Use "Tools->JMX Connect" menu and specify "localhost:1090" + to connect + 4. Open "memmonitor.js" and run it (using "Tools->Run") + in scriptpad + 5. A new "Tools-Memory Monitor" menu appears. Use this menu + and specify 4 and 500 as threshold and interval values. + 6. In the target application shell (where memory.bat/.sh was + started), enter an integer value and press "enter". + 7. You'll see an alert box from scriptpad -- alerting you for + memory threshold exceeded! + +(6) textcolor.js + + -- Open and run this script in scriptpad. You will see + "Tools->Selected Text Color..." menu. Using this you + change the color of "selected text" in the editor. diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/browse.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/browse.js new file mode 100644 index 0000000..fbe50e1 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/browse.js @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This function uses new Swing Desktop API in JDK 6. + * To use this with scriptpad, open this in scriptpad + * and use "Tools->Run Script" menu. + */ +function browse() { + var desktop = null; + // Before more Desktop API is used, first check + // whether the API is supported by this particular + // virtual machine (VM) on this particular host. + if (java.awt.Desktop.isDesktopSupported()) { + desktop = java.awt.Desktop.getDesktop(); + } else { + alert("no desktop support"); + return; + } + + if (desktop.isSupported(java.awt.Desktop.Action.BROWSE)) { + var url = prompt("Address:"); + if (url != null) { + desktop.browse(new java.net.URI(url)); + } + } else { + alert("no browser support"); + } +} + +if (this.application != undefined) { + // add "Browse" menu item under "Tools" menu + this.application.addTool("Browse", browse); +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/insertfile.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/insertfile.js new file mode 100644 index 0000000..07a7ac2 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/insertfile.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script adds "Insert File" mode menu item to "Tools" menu. + * When selected, this menu shows a file dialog box and inserts + * contents of the selected file into current document (at the + * current caret position). + */ +if (this.application) { + application.addTool("Insert File...", + function() { + var file = fileDialog(); + + if (file) { + var reader = new java.io.FileReader(file); + var arr = java.lang.reflect.Array.newInstance( + java.lang.Character.TYPE, 8*1024); // 8K at a time + var buf = new java.lang.StringBuffer(); + var numChars; + + while ((numChars = reader.read(arr, 0, arr.length)) > 0) { + buf.append(arr, 0, numChars); + } + + var pos = application.editor.caretPosition; + var doc = application.editor.document; + + doc.insertString(pos, buf.toString(), null); + } + }); +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/linewrap.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/linewrap.js new file mode 100644 index 0000000..989473a --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/linewrap.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script adds "Line Wrap" mode menu item to "Tools" menu. + * When selected, this menu toggles the current word wrap mode + * of the editor. + */ + +function toggleLineWrap() { + var wrap = application.editor.lineWrap; + application.editor.lineWrap = !wrap; +} + +application.addTool("Line Wrap", toggleLineWrap); diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/mail.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/mail.js new file mode 100644 index 0000000..cabe5c4 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/mail.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This function uses new Swing Desktop API in JDK 6. + * To use this with scriptpad, open this in scriptpad + * and use "Tools->Run Script" menu. + */ +function mail() { + var desktop = null; + // Before more Desktop API is used, first check + // whether the API is supported by this particular + // virtual machine (VM) on this particular host. + if (java.awt.Desktop.isDesktopSupported()) { + desktop = java.awt.Desktop.getDesktop(); + } else { + alert("no desktop support"); + return; + } + + if (desktop.isSupported(java.awt.Desktop.Action.MAIL)) { + var mailTo = prompt("Mail To:"); + if (mailTo != null) { + desktop.mail(new java.net.URI("mailto", mailTo, null)); + } + } +} + +if (this.application != undefined) { + // add "Mail" menu item under "Tools" menu + this.application.addTool("Mail", mail); +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/memmonitor.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/memmonitor.js new file mode 100644 index 0000000..0744e30 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/memmonitor.js @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +// this checker function runs asynchronously +function memoryChecker(memoryBean, threshold, interval) { + while (true) { + var memUsage = memoryBean.HeapMemoryUsage; + var usage = memUsage.get("used") / (1024 * 1024); + + println("usage: " + usage); + + if (usage > threshold) { + alert("Hey! heap usage threshold exceeded!"); + // after first alert just return. + return; + } + + java.lang.Thread.sleep(interval); + } +} + +// add "Tools->Memory Monitor" menu item +if (this.application != undefined) { + this.application.addTool("Memory Monitor", + function () { + // show threshold box with default of 50 MB + var threshold = prompt("Threshold (mb)", 50); + + // show interval box with default of 1000 millisec. + var interval = prompt("Sample Interval (ms):", 1000); + var memoryBean = mbean("java.lang:type=Memory"); + + // ".future" makes the function to be called + // asynchronously in a separate thread. + memoryChecker.future(memoryBean, threshold, interval); + }); +} diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.bat b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.bat new file mode 100644 index 0000000..9478c09 --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.bat @@ -0,0 +1,35 @@ +@echo off +REM +REM Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions +REM are met: +REM +REM - Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM +REM - Redistributions in binary form must reproduce the above copyright +REM notice, this list of conditions and the following disclaimer in the +REM documentation and/or other materials provided with the distribution. +REM +REM - Neither the name of Oracle nor the names of its +REM contributors may be used to endorse or promote products derived +REM from this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +REM IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +REM THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +REM PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +REM CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +REM EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +REM PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +REM PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +REM LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +REM NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +REM + + +jrunscript -J-Dcom.sun.management.jmxremote.port=1090 -J-Dcom.sun.management.jmxremote.ssl=false -J-Dcom.sun.management.jmxremote.authenticate=false memory.js + diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.js new file mode 100644 index 0000000..b8252fb --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.js @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script serves as a simple "monitored application". + * Start this script using memory.bat or memory.sh in the + * current directory. + */ + +java.lang.System.out.print("Enter a number and press enter:"); +var input = java.lang.System["in"].read(); + +// allocate an integer array of "big enough" size! +var a = java.lang.reflect.Array.newInstance( + java.lang.Integer.TYPE, input * 1024 * 1024); + +// sleep some time... +java.lang.Thread.sleep(10*60*1000); diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.sh b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.sh new file mode 100644 index 0000000..8da155b --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/memory.sh @@ -0,0 +1,32 @@ +# +# Copyright (c) 2006, 2013, 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. +# + +jrunscript -J-Dcom.sun.management.jmxremote.port=1090 -J-Dcom.sun.management.jmxremote.ssl=false -J-Dcom.sun.management.jmxremote.authenticate=false memory.js diff --git a/darwin-x86/sample/scripting/scriptpad/src/scripts/textcolor.js b/darwin-x86/sample/scripting/scriptpad/src/scripts/textcolor.js new file mode 100644 index 0000000..b9d86cc --- /dev/null +++ b/darwin-x86/sample/scripting/scriptpad/src/scripts/textcolor.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006, 2013, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +/* + * This script adds "Selected Text Color" menu item to "Tools" menu. + * When selected, this menu changes the "selected text" color. + */ +if (this.application) { + application.addTool("Selected Text Color...", + function() { + var color = application.editor.selectedTextColor; + color = colorDialog("Selected Text Color", color); + application.editor.selectedTextColor = color; + }); +} diff --git a/darwin-x86/sample/try-with-resources/index.html b/darwin-x86/sample/try-with-resources/index.html new file mode 100644 index 0000000..ff237d8 --- /dev/null +++ b/darwin-x86/sample/try-with-resources/index.html @@ -0,0 +1,36 @@ +<!DOCTYPE html>
+
+<html>
+<head>
+ <title>Try-with-Resources Feature Demo</title>
+</head>
+<body>
+<h2>Try-with-Resources Feature Demo</h2>
+
+<p>
+ This demo shows how to use the try-with-resources feature introduced in JDK7.
+</p>
+
+<ul>
+ <li><h3>Custom AutoCloseable.</h3>
+
+ <p>
+ Shows how to use a custom resource with the try-with-resources construct.
+ For more information, see the source file.
+ </p>
+ Source: <a href="src/CustomAutoCloseableSample.java">src/CustomAutoCloseableSample.java</a>
+
+ <li><h3>Unzip</h3>
+
+ <p>
+ Extracts archived files. For more information, see the source file.
+ </p>
+ Source: <a href="src/Unzip.java">src/Unzip.java</a>
+ <li><h3>ZipCat</h3>
+
+ <p>Prints data about a specified file from an archive. For more information, see the source file.</p>
+ Source: <a href="src/ZipCat.java">src/ZipCat.java</a>
+
+</ul>
+</body>
+</html>
\ No newline at end of file diff --git a/darwin-x86/sample/try-with-resources/src/CustomAutoCloseableSample.java b/darwin-x86/sample/try-with-resources/src/CustomAutoCloseableSample.java new file mode 100644 index 0000000..9bbe09a --- /dev/null +++ b/darwin-x86/sample/try-with-resources/src/CustomAutoCloseableSample.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * This sample demonstrates the ability to create custom resource that + * implements the {@code AutoCloseable} interface. This resource can be used in + * the try-with-resources construct. + */ +public class CustomAutoCloseableSample { + + /** + * The main method for the CustomAutoCloseableSample program. + * + * @param args is not used. + */ + public static void main(String[] args) { + /* + * TeeStream will be closed automatically after the try block. + */ + try (TeeStream teeStream = new TeeStream(System.out, Paths.get("out.txt")); + PrintStream out = new PrintStream(teeStream)) { + out.print("Hello, world"); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + /** + * Passes the output through to the specified output stream while copying it into a file. + * The TeeStream functionality is similar to the Unix tee utility. + * TeeStream implements AutoCloseable interface. See OutputStream for details. + */ + public static class TeeStream extends OutputStream { + + private final OutputStream fileStream; + private final OutputStream outputStream; + + /** + * Creates a TeeStream. + * + * @param outputStream an output stream. + * @param outputFile an path to file. + * @throws IOException If an I/O error occurs. + */ + public TeeStream(OutputStream outputStream, Path outputFile) throws IOException { + this.fileStream = new BufferedOutputStream(Files.newOutputStream(outputFile)); + this.outputStream = outputStream; + } + + /** + * Writes the specified byte to the specified output stream + * and copies it to the file. + * + * @param b the byte to be written. + * @throws IOException If an I/O error occurs. + */ + @Override + public void write(int b) throws IOException { + fileStream.write(b); + outputStream.write(b); + } + + /** + * Flushes this output stream and forces any buffered output bytes + * to be written out. + * The <code>flush</code> method of <code>TeeStream</code> flushes + * the specified output stream and the file output stream. + * + * @throws IOException if an I/O error occurs. + */ + @Override + public void flush() throws IOException { + outputStream.flush(); + fileStream.flush(); + } + + /** + * Closes underlying streams and resources. + * The external output stream won't be closed. + * This method is the member of AutoCloseable interface and + * it will be invoked automatically after the try-with-resources block. + * + * @throws IOException If an I/O error occurs. + */ + @Override + public void close() throws IOException { + try (OutputStream file = fileStream) { + flush(); + } + } + } +} diff --git a/darwin-x86/sample/try-with-resources/src/Unzip.java b/darwin-x86/sample/try-with-resources/src/Unzip.java new file mode 100644 index 0000000..d75eba5 --- /dev/null +++ b/darwin-x86/sample/try-with-resources/src/Unzip.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.*; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +/** + * Extract (unzip) a file to the current directory. + */ +public class Unzip { + + /** + * The main method for the Unzip program. Run the program with an empty + * argument list to see possible arguments. + * + * @param args the argument list for {@code Unzip}. + */ + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("Usage: Unzip zipfile"); + } + final Path destDir = Paths.get("."); + /* + * Create AutoCloseable FileSystem. It will be closed automatically + * after the try block. + */ + try (FileSystem zipFileSystem = FileSystems.newFileSystem(Paths.get(args[0]), null)) { + + Path top = zipFileSystem.getPath("/"); + Files.walk(top).skip(1).forEach(file -> { + Path target = destDir.resolve(top.relativize(file).toString()); + System.out.println("Extracting " + target); + try { + Files.copy(file, target, REPLACE_EXISTING); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } catch (UncheckedIOException | IOException e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/darwin-x86/sample/try-with-resources/src/ZipCat.java b/darwin-x86/sample/try-with-resources/src/ZipCat.java new file mode 100644 index 0000000..4bbf513 --- /dev/null +++ b/darwin-x86/sample/try-with-resources/src/ZipCat.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation, and proper error handling, might not be present in + * this sample code. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * Prints data of the specified file to standard output from a zip archive. + */ +public class ZipCat { + + /** + * The main method for the ZipCat program. Run the program with an empty + * argument list to see possible arguments. + * + * @param args the argument list for ZipCat + */ + public static void main(String[] args) { + if (args.length != 2) { + System.out.println("Usage: ZipCat zipfile fileToPrint"); + } + /* + * Creates AutoCloseable FileSystem and BufferedReader. + * They will be closed automatically after the try block. + * If reader initialization fails, then zipFileSystem will be closed + * automatically. + */ + try (FileSystem zipFileSystem + = FileSystems.newFileSystem(Paths.get(args[0]),null); + InputStream input + = Files.newInputStream(zipFileSystem.getPath(args[1]))) { + byte[] buffer = new byte[1024]; + int len; + while ((len = input.read(buffer)) != -1) { + System.out.write(buffer, 0, len); + } + + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/darwin-x86/src.zip b/darwin-x86/src.zip Binary files differindex 27b4758..7a42e91 100644 --- a/darwin-x86/src.zip +++ b/darwin-x86/src.zip |