# HG changeset patch # User duke # Date 1499265690 -7200 # Node ID 3e5496df0d2bbb13732b5f743ec695c6d8405d58 # Parent 5a725d2f0daa6e29a23f4d25d890536f02b2f088# Parent e87f9c04269944511d0ff7b80ab9bf9667fe32a1 Merge diff -r 5a725d2f0daa -r 3e5496df0d2b .hgtags-top-repo --- a/.hgtags-top-repo Thu Sep 11 11:25:48 2008 -0700 +++ b/.hgtags-top-repo Wed Jul 05 16:41:30 2017 +0200 @@ -9,3 +9,4 @@ 64da805be725721bf2004e7409a0d7a16fc8ddbc jdk7-b32 bb1ef4ee3d2c8cbf43a37d372325a7952be590b9 jdk7-b33 46a989ab932992b2084b946eeb322fa99b9fee6c jdk7-b34 +143c1abedb7d3095eff0f9ee5fec9bf48e3490fc jdk7-b35 diff -r 5a725d2f0daa -r 3e5496df0d2b README-builds.html --- a/README-builds.html Thu Sep 11 11:25:48 2008 -0700 +++ b/README-builds.html Wed Jul 05 16:41:30 2017 +0200 @@ -5,7 +5,7 @@
- +
Introduction
Fedora+Fedora 9- TBD + After installing + Fedora 9 + you need to make sure you have + the "Software Development" bundle installed, plus the + following packages: +-++ Debian+CentOS 5.2- TBD + After installing + CentOS 5.2 + you need to make sure you have + the following Development bundles installed: +++ Ubuntu@@ -664,8 +719,8 @@+ WARNING: Make sure you check out the + CYGWIN link.exe WARNING. + The path /usr/bin must be after the path to the + Visual Studio product. Windows X64: Microsoft Platform SDK April 2005 @@ -1079,6 +1139,7 @@ |
+ WARNING: + Be very careful with link.exe, it will conflict + with the Visual Studio version. You need the Visual Studio + version of link.exe, not the CYGWIN one. + So it's important that the Visual Studio paths in PATH preceed + the CYGWIN path /usr/bin. Microsoft DirectX 9.0 SDK header files and libraries
@@ -1429,7 +1506,7 @@ build output is to go. The default output directory will be build/platform. -ALT_SLASHJAVA +ALT_SLASH_JAVA The default root location for many of the ALT path locations of the following ALT variables. diff -r 5a725d2f0daa -r 3e5496df0d2b corba/.hgtags --- a/corba/.hgtags Thu Sep 11 11:25:48 2008 -0700 +++ b/corba/.hgtags Wed Jul 05 16:41:30 2017 +0200 @@ -9,3 +9,4 @@ 80a0f46a6203e727012bd579fe38a609b83decce jdk7-b32 6a5b9d2f8b20de54e3bfe33cd12bd0793caedc4e jdk7-b33 0a812b9824e5d17b073765d1505594b49ff88a10 jdk7-b34 +3867c4d14a5bfdbb37c97b4874ccb0ee5343111c jdk7-b35 diff -r 5a725d2f0daa -r 3e5496df0d2b corba/make/common/shared/Defs-utils.gmk --- a/corba/make/common/shared/Defs-utils.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/corba/make/common/shared/Defs-utils.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -67,16 +67,6 @@ UTILS_DEVTOOL_PATH=$(DEVTOOLS_PATH) endif -# Utilities ant and findbugs -ifndef ANT_HOME - ANT_HOME = $(JDK_DEVTOOLS_DIR)/share/ant/latest -endif -ANT = $(ANT_HOME)/bin/ant -ifndef FINDBUGS_HOME - FINDBUGS_HOME = $(JDK_DEVTOOLS_DIR)/share/findbugs/latest -endif -FINDBUGS = $(FINDBUGS_HOME)/bin/findbugs - # Utilities ADB = $(UTILS_COMMAND_PATH)adb AR = $(UTILS_CCS_BIN_PATH)ar diff -r 5a725d2f0daa -r 3e5496df0d2b corba/make/jprt.config --- a/corba/make/jprt.config Thu Sep 11 11:25:48 2008 -0700 +++ b/corba/make/jprt.config Wed Jul 05 16:41:30 2017 +0200 @@ -93,23 +93,13 @@ jdk_devtools="${slashjava}/devtools" share="${jdk_devtools}/share" -# Needed for langtools, maybe other parts of the build -ANT_HOME="${share}/ant/latest" -export ANT_HOME -FINDBUGS_HOME="${share}/findbugs/latest" -export FINDBUGS_HOME - # The 3 bin directories in common to all platforms sharebin="${share}/bin" -antbin="${ANT_HOME}/bin" -findbugsbin="${FINDBUGS_HOME}/bin" # Check input dirMustExist "${bootdir}" ALT_BOOTDIR dirMustExist "${slashjava}" ALT_SLASH_JAVA dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH -dirMustExist "${ANT_HOME}" ANT_HOME -dirMustExist "${FINDBUGS_HOME}" FINDBUGS_HOME # Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. osname=`uname -s` @@ -133,7 +123,7 @@ ALT_COMPILER_PATH="${compiler_path}" export ALT_COMPILER_PATH dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin}:${findbugsbin} + path4sdk=${compiler_path}:${sharebin} # Add basic solaris system paths path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin @@ -170,7 +160,7 @@ ALT_COMPILER_PATH="${compiler_path}" export ALT_COMPILER_PATH dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin}:${findbugsbin} + path4sdk=${compiler_path}:${sharebin} # Add basic paths path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin @@ -211,7 +201,7 @@ dosname="${mkshome}/mksnt/dosname -s" # Most unix utilities are in the mksnt directory of ROOTDIR unixcommand_path="${mkshome}/mksnt" - path4sdk="${sharebin};${antbin};${findbugsbin};${unixcommand_path}" + path4sdk="${sharebin};${unixcommand_path}" dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH devtools_path="${jdk_devtools}/win32/bin" path4sdk="${devtools_path};${path4sdk}" @@ -229,7 +219,7 @@ dosname="/usr/bin/cygpath -a -m -s" # Most unix utilities are in the /usr/bin unixcommand_path="/usr/bin" - path4sdk="${sharebin};${antbin};${findbugsbin};${unixcommand_path}" + path4sdk="${sharebin};${unixcommand_path}" dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH # Find GNU make make="${unixcommand_path}/make.exe" diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/.hgtags --- a/hotspot/.hgtags Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/.hgtags Wed Jul 05 16:41:30 2017 +0200 @@ -9,3 +9,4 @@ b727c32788a906c04839516ae7443a085185a300 jdk7-b32 585535ec8a14adafa6bfea65d6975e29094c8cec jdk7-b33 5251a9cd8eb8743eee647365bee1c8afdc131556 jdk7-b34 +5fa96a5a7e76da7c8dad12486293a0456c2c116c jdk7-b35 diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Location.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Location.java Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Location.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,9 +39,9 @@ Encoding:
bits: - Where: [15] - Type: [14..12] - Offset: [11..0] + Type: [3..0] + Where: [4] + Offset: [31..5]*/ @@ -69,6 +69,7 @@ // Location::Type constants TYPE_NORMAL = db.lookupIntConstant("Location::normal").intValue(); TYPE_OOP = db.lookupIntConstant("Location::oop").intValue(); + TYPE_NARROWOOP = db.lookupIntConstant("Location::narrowoop").intValue(); TYPE_INT_IN_LONG = db.lookupIntConstant("Location::int_in_long").intValue(); TYPE_LNG = db.lookupIntConstant("Location::lng").intValue(); TYPE_FLOAT_IN_DBL = db.lookupIntConstant("Location::float_in_dbl").intValue(); @@ -115,6 +116,8 @@ public static final Type NORMAL = new Type("normal"); /** Oop (please GC me!) */ public static final Type OOP = new Type("oop"); + /** NarrowOop (please GC me!) */ + public static final Type NARROWOOP = new Type("narrowoop"); /** Long held in one register */ public static final Type INT_IN_LONG = new Type("int_in_long"); /** Long held in one register */ @@ -142,6 +145,8 @@ return TYPE_NORMAL; } else if (this == OOP) { return TYPE_OOP; + } else if (this == NARROWOOP) { + return TYPE_NARROWOOP; } else if (this == INT_IN_LONG) { return TYPE_INT_IN_LONG; } else if (this == LNG) { @@ -170,6 +175,7 @@ // constants in Type enum private static int TYPE_NORMAL; private static int TYPE_OOP; + private static int TYPE_NARROWOOP; private static int TYPE_INT_IN_LONG; private static int TYPE_LNG; private static int TYPE_FLOAT_IN_DBL; @@ -185,7 +191,7 @@ Location(Where where, Type type, int offset) { setWhere(where); setType(type); - setOffset(offset & 0x0000FFFF); + setOffset(offset); } public Where getWhere() { @@ -205,6 +211,8 @@ return Type.NORMAL; } else if (type == TYPE_OOP) { return Type.OOP; + } else if (type == TYPE_NARROWOOP) { + return Type.NARROWOOP; } else if (type == TYPE_INT_IN_LONG) { return Type.INT_IN_LONG; } else if (type == TYPE_LNG) { @@ -238,6 +246,10 @@ return getType() == Type.OOP; } + public boolean holdsNarrowOop() { + return getType() == Type.NARROWOOP; + } + public boolean holdsInt() { return getType() == Type.INT_IN_LONG; } @@ -266,7 +278,7 @@ if (Assert.ASSERTS_ENABLED) { Assert.that(getWhere() == Where.ON_STACK, "wrong Where"); } - return getOffset() << VM.getVM().getLogAddressSize(); + return getOffset() * (int)VM.getVM().getIntSize(); } public int getRegisterNumber() { @@ -296,6 +308,8 @@ if (type == Type.NORMAL) { } else if (type == Type.OOP) { tty.print(",oop"); + } else if (type == Type.NARROWOOP) { + tty.print(",narrowoop"); } else if (type == Type.INT_IN_LONG) { tty.print(",int"); } else if (type == Type.LNG) { @@ -314,26 +328,26 @@ /** Serialization of debugging information */ public Location(DebugInfoReadStream stream) { - value = (0x0000FFFF & stream.readInt()); + value = stream.readInt(); } // FIXME: not yet implementable // void write_on(DebugInfoWriteStream* stream); - //-------------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // Internals only below this point // private void setWhere(Where where) { - value |= (where.getValue() << WHERE_SHIFT); + value |= ((where.getValue() << WHERE_SHIFT) & WHERE_MASK); } private void setType(Type type) { - value |= (type.getValue() << TYPE_SHIFT); + value |= ((type.getValue() << TYPE_SHIFT) & TYPE_MASK); } private void setOffset(int offset) { - value |= (offset << OFFSET_SHIFT); + value |= ((offset << OFFSET_SHIFT) & OFFSET_MASK); } } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Wed Jul 05 16:41:30 2017 +0200 @@ -206,6 +206,16 @@ Assert.that( loc.isRegister(), "ints always saved to stack in 1 word" ); } return new StackValue(valueAddr.getJLongAt(0) & 0xFFFFFFFF); + } else if (loc.holdsNarrowOop()) { // Holds an narrow oop? + if (loc.isRegister() && VM.getVM().isBigEndian()) { + // The callee has no clue whether the register holds an narrow oop, + // long or is unused. He always saves a long. Here we know + // a long was saved, but we only want an narrow oop back. Narrow the + // saved long to the narrow oop that the JVM wants. + return new StackValue(valueAddr.getCompOopHandleAt(VM.getVM().getIntSize())); + } else { + return new StackValue(valueAddr.getCompOopHandleAt(0)); + } } else if( loc.holdsOop() ) { // Holds an oop? return new StackValue(valueAddr.getOopHandleAt(0)); } else if( loc.holdsDouble() ) { diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Wed Jul 05 16:41:30 2017 +0200 @@ -621,6 +621,11 @@ return bytes; } + /** Returns true if this is a isBigEndian, false otherwise */ + public boolean isBigEndian() { + return isBigEndian; + } + /** Returns true if this is a "core" build, false if either C1 or C2 is present */ public boolean isCore() { diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Jul 05 16:41:30 2017 +0200 @@ -1135,6 +1135,8 @@ buf.append("normal"); } else if (type == Location.Type.OOP) { buf.append("oop"); + } else if (type == Location.Type.NARROWOOP) { + buf.append("narrowoop"); } else if (type == Location.Type.INT_IN_LONG) { buf.append("int"); } else if (type == Location.Type.LNG) { diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/make/hotspot_version --- a/hotspot/make/hotspot_version Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/make/hotspot_version Wed Jul 05 16:41:30 2017 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=14 HS_MINOR_VER=0 -HS_BUILD_NUMBER=04 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/make/jprt.properties --- a/hotspot/make/jprt.properties Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/make/jprt.properties Wed Jul 05 16:41:30 2017 +0200 @@ -295,3 +295,9 @@ ${jprt.my.windows.i586.test.targets}, \ ${jprt.my.windows.x64.test.targets} +# The default test/Makefile targets that should be run + +# Example: +# jprt.make.rule.test.targets=*-*-*-packtest +#jprt.make.rule.test.targets=*-product-*-packtest + diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1129,8 +1129,8 @@ #else __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 0)); // push and pop the part at src + wordSize, adding wordSize for the previous push - __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), wordSize)); - __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), wordSize)); + __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 2 * wordSize)); + __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 2 * wordSize)); __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 0)); #endif // _LP64 diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/code/location.cpp --- a/hotspot/src/share/vm/code/location.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/code/location.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #include "incls/_location.cpp.incl" void Location::print_on(outputStream* st) const { - if(type() == invalid && !legal_offset_in_bytes(offset() * BytesPerInt)) { + if(type() == invalid) { // product of Location::invalid_loc() or Location::Location(). switch (where()) { case on_stack: st->print("empty"); break; @@ -42,6 +42,7 @@ switch (type()) { case normal: break; case oop: st->print(",oop"); break; + case narrowoop: st->print(",narrowoop"); break; case int_in_long: st->print(",int"); break; case lng: st->print(",long"); break; case float_in_dbl: st->print(",float"); break; @@ -53,17 +54,17 @@ Location::Location(DebugInfoReadStream* stream) { - _value = (uint16_t) stream->read_int(); + _value = (juint) stream->read_int(); } void Location::write_on(DebugInfoWriteStream* stream) { - stream->write_int(_value & 0x0000FFFF); + stream->write_int(_value); } // Valid argument to Location::new_stk_loc()? bool Location::legal_offset_in_bytes(int offset_in_bytes) { if ((offset_in_bytes % BytesPerInt) != 0) return false; - return (offset_in_bytes / BytesPerInt) < (OFFSET_MASK >> OFFSET_SHIFT); + return (juint)(offset_in_bytes / BytesPerInt) < (OFFSET_MASK >> OFFSET_SHIFT); } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/code/location.hpp --- a/hotspot/src/share/vm/code/location.hpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/code/location.hpp Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,10 @@ // // Encoding: // -// bits: -// Where: [15] -// Type: [14..12] -// Offset: [11..0] +// bits (use low bits for best compression): +// Type: [3..0] +// Where: [4] +// Offset: [31..5] class Location VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -42,6 +42,7 @@ }; enum Type { + invalid, // Invalid location normal, // Ints, floats, double halves oop, // Oop (please GC me!) int_in_long, // Integer held in long register @@ -49,21 +50,21 @@ float_in_dbl, // Float held in double register dbl, // Double held in one register addr, // JSR return address - invalid // Invalid location + narrowoop // Narrow Oop (please GC me!) }; private: enum { - OFFSET_MASK = (jchar) 0x0FFF, - OFFSET_SHIFT = 0, - TYPE_MASK = (jchar) 0x7000, - TYPE_SHIFT = 12, - WHERE_MASK = (jchar) 0x8000, - WHERE_SHIFT = 15 + TYPE_MASK = (juint) 0x0F, + TYPE_SHIFT = 0, + WHERE_MASK = (juint) 0x10, + WHERE_SHIFT = 4, + OFFSET_MASK = (juint) 0xFFFFFFE0, + OFFSET_SHIFT = 5 }; - uint16_t _value; + juint _value; // Create a bit-packed Location Location(Where where_, Type type_, unsigned offset_) { @@ -74,9 +75,9 @@ } inline void set(Where where_, Type type_, unsigned offset_) { - _value = (uint16_t) ((where_ << WHERE_SHIFT) | - (type_ << TYPE_SHIFT) | - ((offset_ << OFFSET_SHIFT) & OFFSET_MASK)); + _value = (juint) ((where_ << WHERE_SHIFT) | + (type_ << TYPE_SHIFT) | + ((offset_ << OFFSET_SHIFT) & OFFSET_MASK)); } public: @@ -86,7 +87,7 @@ // Register location Factory static Location new_reg_loc( Type t, VMReg reg ) { return Location(in_register, t, reg->value()); } // Default constructor - Location() { set(on_stack,invalid,(unsigned) -1); } + Location() { set(on_stack,invalid,0); } // Bit field accessors Where where() const { return (Where) ((_value & WHERE_MASK) >> WHERE_SHIFT);} diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/addnode.cpp --- a/hotspot/src/share/vm/opto/addnode.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/addnode.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -157,6 +157,7 @@ Node *a12 = add1->in(2); const Type *t12 = phase->type( a12 ); if( t12->singleton() && t12 != Type::TOP && (add1 != add1->in(1)) ) { + assert(add1->in(1) != this, "dead loop in AddNode::Ideal"); add2 = add1->clone(); add2->set_req(2, in(2)); add2 = phase->transform(add2); @@ -173,6 +174,7 @@ Node *a22 = add2->in(2); const Type *t22 = phase->type( a22 ); if( t22->singleton() && t22 != Type::TOP && (add2 != add2->in(1)) ) { + assert(add2->in(1) != this, "dead loop in AddNode::Ideal"); Node *addx = add2->clone(); addx->set_req(1, in(1)); addx->set_req(2, add2->in(1)); diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -334,6 +334,9 @@ case Type::InstPtr: st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->isa_oopptr()->const_oop()); break; + case Type::NarrowOop: + st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->make_ptr()->isa_oopptr()->const_oop()); + break; case Type::RawPtr: st->print(" %s%d]=#Raw" INTPTR_FORMAT,msg,i,t->is_rawptr()); break; diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1967,6 +1967,7 @@ !n->is_Proj() && nop != Op_CreateEx && nop != Op_CheckCastPP && + nop != Op_DecodeN && !n->is_Mem() ) { Node *x = n->clone(); call->set_req( TypeFunc::Parms, x ); @@ -2075,20 +2076,27 @@ case Op_CmpP: // Do this transformation here to preserve CmpPNode::sub() and // other TypePtr related Ideal optimizations (for example, ptr nullness). - if( n->in(1)->is_DecodeN() ) { + if (n->in(1)->is_DecodeN() || n->in(2)->is_DecodeN()) { + Node* in1 = n->in(1); + Node* in2 = n->in(2); + if (!in1->is_DecodeN()) { + in2 = in1; + in1 = n->in(2); + } + assert(in1->is_DecodeN(), "sanity"); + Compile* C = Compile::current(); - Node* in2 = NULL; - if( n->in(2)->is_DecodeN() ) { - in2 = n->in(2)->in(1); - } else if ( n->in(2)->Opcode() == Op_ConP ) { - const Type* t = n->in(2)->bottom_type(); - if (t == TypePtr::NULL_PTR) { - Node *in1 = n->in(1); + Node* new_in2 = NULL; + if (in2->is_DecodeN()) { + new_in2 = in2->in(1); + } else if (in2->Opcode() == Op_ConP) { + const Type* t = in2->bottom_type(); + if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) { if (Matcher::clone_shift_expressions) { // x86, ARM and friends can handle 2 adds in addressing mode. // Decode a narrow oop and do implicit NULL check in address // [R12 + narrow_oop_reg<<3 + offset] - in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); + new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); } else { // Don't replace CmpP(o ,null) if 'o' is used in AddP // to generate implicit NULL check on Sparc where @@ -2099,16 +2107,22 @@ break; } if (i >= in1->outcnt()) { - in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); + new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); } } } else if (t->isa_oopptr()) { - in2 = ConNode::make(C, t->make_narrowoop()); + new_in2 = ConNode::make(C, t->make_narrowoop()); } } - if( in2 != NULL ) { - Node* cmpN = new (C, 3) CmpNNode(n->in(1)->in(1), in2); + if (new_in2 != NULL) { + Node* cmpN = new (C, 3) CmpNNode(in1->in(1), new_in2); n->subsume_by( cmpN ); + if (in1->outcnt() == 0) { + in1->disconnect_inputs(NULL); + } + if (in2->outcnt() == 0) { + in2->disconnect_inputs(NULL); + } } } break; @@ -2214,6 +2228,9 @@ // Replacing Opaque nodes with their input in final_graph_reshaping_impl(), // requires that the walk visits a node's inputs before visiting the node. static void final_graph_reshaping_walk( Node_Stack &nstack, Node *root, Final_Reshape_Counts &fpu ) { + ResourceArea *area = Thread::current()->resource_area(); + Unique_Node_List sfpt(area); + fpu._visited.set(root->_idx); // first, mark node as visited uint cnt = root->req(); Node *n = root; @@ -2224,6 +2241,8 @@ Node* m = n->in(i); ++i; if (m != NULL && !fpu._visited.test_set(m->_idx)) { + if (m->is_SafePoint() && m->as_SafePoint()->jvms() != NULL) + sfpt.push(m); cnt = m->req(); nstack.push(n, i); // put on stack parent and next input's index n = m; @@ -2240,6 +2259,41 @@ nstack.pop(); // Shift to the next node on stack } } + + // Go over safepoints nodes to skip DecodeN nodes for debug edges. + // It could be done for an uncommon traps or any safepoints/calls + // if the DecodeN node is referenced only in a debug info. + while (sfpt.size() > 0) { + n = sfpt.pop(); + JVMState *jvms = n->as_SafePoint()->jvms(); + assert(jvms != NULL, "sanity"); + int start = jvms->debug_start(); + int end = n->req(); + bool is_uncommon = (n->is_CallStaticJava() && + n->as_CallStaticJava()->uncommon_trap_request() != 0); + for (int j = start; j < end; j++) { + Node* in = n->in(j); + if (in->is_DecodeN()) { + bool safe_to_skip = true; + if (!is_uncommon ) { + // Is it safe to skip? + for (uint i = 0; i < in->outcnt(); i++) { + Node* u = in->raw_out(i); + if (!u->is_SafePoint() || + u->is_Call() && u->as_Call()->has_non_debug_use(n)) { + safe_to_skip = false; + } + } + } + if (safe_to_skip) { + n->set_req(j, in->in(1)); + } + if (in->outcnt() == 0) { + in->disconnect_inputs(NULL); + } + } + } + } } //------------------------------final_graph_reshaping-------------------------- diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1212,6 +1212,7 @@ Deoptimization::Action_make_not_entrant, NULL, "assert_null"); } else { + replace_in_map(value, zerocon(type)); builtin_throw(reason); } } @@ -1960,6 +1961,7 @@ // method will be compiled to handle NULLs. PreserveJVMState pjvms(this); set_control(*null_control); + replace_in_map(value, null()); uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_make_not_entrant); (*null_control) = top(); // NULL path is dead diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/lcm.cpp --- a/hotspot/src/share/vm/opto/lcm.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/lcm.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -58,6 +58,9 @@ not_null_block = _succs[0]; null_block = _succs[1]; } + while (null_block->is_Empty() == Block::empty_with_goto) { + null_block = null_block->_succs[0]; + } // Search the exception block for an uncommon trap. // (See Parse::do_if and Parse::do_ifnull for the reason @@ -149,6 +152,10 @@ const TypePtr *adr_type = NULL; // Do not need this return value here const Node* base = mach->get_base_and_disp(offset, adr_type); if (base == NULL || base == NodeSentinel) { + // Narrow oop address doesn't have base, only index + if( val->bottom_type()->isa_narrowoop() && + MacroAssembler::needs_explicit_null_check(offset) ) + continue; // Give up if offset is beyond page size // cannot reason about it; is probably not implicit null exception } else { const TypePtr* tptr = base->bottom_type()->is_ptr(); diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -932,7 +932,7 @@ // to fold a StoreP and an AddP together (as part of an // address expression) and the AddP and StoreP have // different controls. - if( !x->is_Load() ) _igvn._worklist.yank(x); + if( !x->is_Load() && !x->is_DecodeN() ) _igvn._worklist.yank(x); } _igvn.remove_dead_node(n); } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/output.cpp --- a/hotspot/src/share/vm/opto/output.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/output.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -685,6 +685,8 @@ } else if( t->base() == Type::Int && OptoReg::is_reg(regnum) ) { array->append(new_loc_value( _regalloc, regnum, Matcher::int_in_long ? Location::int_in_long : Location::normal )); + } else if( t->base() == Type::NarrowOop ) { + array->append(new_loc_value( _regalloc, regnum, Location::narrowoop )); } else { array->append(new_loc_value( _regalloc, regnum, _regalloc->is_oop(local) ? Location::oop : Location::normal )); } @@ -704,6 +706,13 @@ case Type::KlassPtr: // fall through array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->encoding())); break; + case Type::NarrowOop: + if (t == TypeNarrowOop::NULL_PTR) { + array->append(new ConstantOopWriteValue(NULL)); + } else { + array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->encoding())); + } + break; case Type::Int: array->append(new ConstantIntValue(t->is_int()->get_con())); break; @@ -878,9 +887,14 @@ } } else if( !obj_node->is_Con() ) { OptoReg::Name obj_reg = _regalloc->get_reg_first(obj_node); - scval = new_loc_value( _regalloc, obj_reg, Location::oop ); + if( obj_node->bottom_type()->base() == Type::NarrowOop ) { + scval = new_loc_value( _regalloc, obj_reg, Location::narrowoop ); + } else { + scval = new_loc_value( _regalloc, obj_reg, Location::oop ); + } } else { - scval = new ConstantOopWriteValue(obj_node->bottom_type()->is_instptr()->const_oop()->encoding()); + const TypePtr *tp = obj_node->bottom_type()->make_ptr(); + scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->encoding()); } OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node); diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/opto/reg_split.cpp --- a/hotspot/src/share/vm/opto/reg_split.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/opto/reg_split.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -527,6 +527,7 @@ // Initialize needs_phi and needs_split bool needs_phi = false; bool needs_split = false; + bool has_phi = false; // Walk the predecessor blocks to check inputs for that live range // Grab predecessor block header n1 = b->pred(1); @@ -570,28 +571,30 @@ } } // End for all potential Phi inputs - // If a phi is needed, check for it - if( needs_phi ) { - // check block for appropriate phinode & update edges - for( insidx = 1; insidx <= b->end_idx(); insidx++ ) { - n1 = b->_nodes[insidx]; - // bail if this is not a phi - phi = n1->is_Phi() ? n1->as_Phi() : NULL; - if( phi == NULL ) { - // Keep track of index of first non-PhiNode instruction in block - non_phi = insidx; - // break out of the for loop as we have handled all phi nodes - break; - } - // must be looking at a phi - if( Find_id(n1) == lidxs.at(slidx) ) { - // found the necessary phi - needs_phi = false; - // initialize the Reaches entry for this LRG - Reachblock[slidx] = phi; - break; - } // end if found correct phi - } // end for all phi's + // check block for appropriate phinode & update edges + for( insidx = 1; insidx <= b->end_idx(); insidx++ ) { + n1 = b->_nodes[insidx]; + // bail if this is not a phi + phi = n1->is_Phi() ? n1->as_Phi() : NULL; + if( phi == NULL ) { + // Keep track of index of first non-PhiNode instruction in block + non_phi = insidx; + // break out of the for loop as we have handled all phi nodes + break; + } + // must be looking at a phi + if( Find_id(n1) == lidxs.at(slidx) ) { + // found the necessary phi + needs_phi = false; + has_phi = true; + // initialize the Reaches entry for this LRG + Reachblock[slidx] = phi; + break; + } // end if found correct phi + } // end for all phi's + + // If a phi is needed or exist, check for it + if( needs_phi || has_phi ) { // add new phinode if one not already found if( needs_phi ) { // create a new phi node and insert it into the block @@ -695,7 +698,8 @@ } } assert( u, "at least 1 valid input expected" ); - if( i >= cnt ) { // Didn't find 2+ unique inputs? + if( i >= cnt ) { // Found one unique input + assert(Find_id(n) == Find_id(u), "should be the same lrg"); n->replace_by(u); // Then replace with unique input n->disconnect_inputs(NULL); b->_nodes.remove(insidx); diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1204,15 +1204,17 @@ // Turn off until bug is fixed. // FLAG_SET_ERGO(bool, UseCompressedOops, true); } +#ifdef _WIN64 + if (UseLargePages && UseCompressedOops) { + // Cannot allocate guard pages for implicit checks in indexed addressing + // mode, when large pages are specified on windows. + FLAG_SET_DEFAULT(UseImplicitNullCheckForNarrowOop, false); + } +#endif // _WIN64 } else { if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { // If specified, give a warning - if (UseConcMarkSweepGC){ - warning("Compressed Oops does not work with CMS"); - } else { - warning( - "Max heap size too large for Compressed Oops"); - } + warning( "Max heap size too large for Compressed Oops"); FLAG_SET_DEFAULT(UseCompressedOops, false); } } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 16:41:30 2017 +0200 @@ -294,6 +294,9 @@ lp64_product(bool, CheckCompressedOops, trueInDebug, \ "generate checks in encoding/decoding code") \ \ + product(bool, UseImplicitNullCheckForNarrowOop, true, \ + "generate implicit null check in indexed addressing mode.") \ + \ /* UseMembar is theoretically a temp flag used for memory barrier \ * removal testing. It was supposed to be removed before FCS but has \ * been re-added (see 6401008) */ \ diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/stackValue.cpp --- a/hotspot/src/share/vm/runtime/stackValue.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/stackValue.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,6 +86,22 @@ case Location::lng: // Long value in an aligned adjacent pair return new StackValue(*(intptr_t*)value_addr); + case Location::narrowoop: { + union { intptr_t p; narrowOop noop;} value; + value.p = (intptr_t) CONST64(0xDEADDEAFDEADDEAF); + if (loc.is_register()) { + // The callee has no clue whether the register holds an int, + // long or is unused. He always saves a long. Here we know + // a long was saved, but we only want an int back. Narrow the + // saved long to the int that the JVM wants. + value.noop = (narrowOop) *(julong*) value_addr; + } else { + value.noop = *(narrowOop*) value_addr; + } + // Decode narrowoop and wrap a handle around the oop + Handle h(oopDesc::decode_heap_oop(value.noop)); + return new StackValue(h); + } #endif case Location::oop: { Handle h(*(oop *)value_addr); // Wrap a handle around the oop diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -2756,13 +2756,17 @@ // For now, just manually iterate through them. tc->do_thread(VMThread::vm_thread()); Universe::heap()->gc_threads_do(tc); - { - // Grab the Terminator_lock to prevent watcher_thread from being terminated. - MutexLockerEx mu(Terminator_lock, Mutex::_no_safepoint_check_flag); - WatcherThread *wt = WatcherThread::watcher_thread(); - if (wt != NULL) - tc->do_thread(wt); - } + WatcherThread *wt = WatcherThread::watcher_thread(); + // Strictly speaking, the following NULL check isn't sufficient to make sure + // the data for WatcherThread is still valid upon being examined. However, + // considering that WatchThread terminates when the VM is on the way to + // exit at safepoint, the chance of the above is extremely small. The right + // way to prevent termination of WatcherThread would be to acquire + // Terminator_lock, but we can't do that without violating the lock rank + // checking in some cases. + if (wt != NULL) + tc->do_thread(wt); + // If CompilerThreads ever become non-JavaThreads, add them here } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -380,7 +380,8 @@ bool large, char* requested_address) : ReservedSpace(size, alignment, large, requested_address, - UseCompressedOops ? lcm(os::vm_page_size(), alignment) : 0) { + UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + lcm(os::vm_page_size(), alignment) : 0) { // Only reserved space for the java heap should have a noaccess_prefix // if using compressed oops. protect_noaccess_prefix(size); @@ -391,7 +392,8 @@ const size_t suffix_size, const size_t suffix_align) : ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align, - UseCompressedOops ? lcm(os::vm_page_size(), prefix_align) : 0) { + UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + lcm(os::vm_page_size(), prefix_align) : 0) { protect_noaccess_prefix(prefix_size+suffix_size); } diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1577,6 +1577,7 @@ \ declare_constant(Location::normal) \ declare_constant(Location::oop) \ + declare_constant(Location::narrowoop) \ declare_constant(Location::int_in_long) \ declare_constant(Location::lng) \ declare_constant(Location::float_in_dbl) \ diff -r 5a725d2f0daa -r 3e5496df0d2b hotspot/test/Makefile --- a/hotspot/test/Makefile Thu Sep 11 11:25:48 2008 -0700 +++ b/hotspot/test/Makefile Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -19,17 +19,18 @@ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. -# +# # # -# Makefile to run jtreg +# Makefile to run various jdk tests # +# Get OS/ARCH specifics OSNAME = $(shell uname -s) +SLASH_JAVA = /java ifeq ($(OSNAME), SunOS) PLATFORM = solaris - JCT_PLATFORM = solaris ARCH = $(shell uname -p) ifeq ($(ARCH), i386) ARCH=i586 @@ -37,203 +38,165 @@ endif ifeq ($(OSNAME), Linux) PLATFORM = linux - JCT_PLATFORM = linux ARCH = $(shell uname -m) ifeq ($(ARCH), i386) - ARCH=i586 + ARCH = i586 endif endif ifeq ($(OSNAME), Windows_NT) PLATFORM = windows - JCT_PLATFORM = win32 + SLASH_JAVA = J: ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) - ARCH=ia64 + ARCH = ia64 else ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) - ARCH=x64 + ARCH = x64 else ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),EM64T) - ARCH=x64 + ARCH = x64 else - ARCH=i586 + ARCH = i586 endif endif endif -endif - -# Default bundle of all test results (passed or not) -JPRT_ARCHIVE_BUNDLE=$(TEST_ROOT)/JPRT_ARCHIVE_BUNDLE.zip - -# Default home for JTREG -ifeq ($(PLATFORM), windows) - JT_HOME = J:/svc/jct-tools3.2.2_01 -else - JT_HOME = /java/svc/jct-tools3.2.2_01 + EXESUFFIX = .exe endif -# Default JTREG to run -JTREG = $(JT_HOME)/$(JCT_PLATFORM)/bin/jtreg - -# Root of this test area -TEST_ROOT := $(shell pwd) - -# Default JDK to test -JAVA_HOME = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +# Utilities used +CD = cd +CP = cp +ECHO = echo +MKDIR = mkdir +ZIP = zip -# The test directories to run -DEFAULT_TESTDIRS = serviceability -TESTDIRS = $(DEFAULT_TESTDIRS) - -# Files that hold total passed and failed counts (passed==0 is bad) -JTREG_TOTALS_DIR = $(TEST_ROOT)/JTREG_TOTALS_$(PLATFORM)_$(ARCH) -JTREG_FAILED = $(JTREG_TOTALS_DIR)/failed_count -JTREG_PASSED = $(JTREG_TOTALS_DIR)/passed_count +# Root of this test area (important to use full paths in some places) +TEST_ROOT := $(shell pwd) # Root of all test results -JTREG_ALL_OUTPUT_DIRNAME = JTREG_OUTPUT_$(PLATFORM)_$(ARCH) -JTREG_ALL_OUTPUT_DIR = $(TEST_ROOT)/$(JTREG_ALL_OUTPUT_DIRNAME) - -# Test results for one test directory -JTREG_TEST_OUTPUT_DIR = $(JTREG_ALL_OUTPUT_DIR)/$@ -JTREG_TEST_REPORT_DIR = $(JTREG_TEST_OUTPUT_DIR)/JTreport -JTREG_TEST_WORK_DIR = $(JTREG_TEST_OUTPUT_DIR)/JTwork -JTREG_TEST_SUMMARY = $(JTREG_TEST_REPORT_DIR)/summary.txt - -# Temp files used by this Makefile -JTREG_TEST_TEMP_DIR = $(JTREG_ALL_OUTPUT_DIR)/$@/temp -JTREG_TEMP_PASSED = $(JTREG_TEST_TEMP_DIR)/passed -JTREG_TEMP_FAILED = $(JTREG_TEST_TEMP_DIR)/failed -JTREG_TEMP_OUTPUT = $(JTREG_TEST_TEMP_DIR)/output -JTREG_TEMP_RESULTS = $(JTREG_TEST_TEMP_DIR)/results - -# JTREG options (different for 2.1.6 and 3.2.2_01) -JTREG_COMMON_OPTIONS = -r:$(JTREG_TEST_REPORT_DIR) \ - -w:$(JTREG_TEST_WORK_DIR) \ - -testjdk:$(JAVA_HOME) \ - -automatic \ - -verbose:all -JTREG_216_OPTIONS = $(JTREG_COMMON_OPTIONS) $@ $(JAVA_ARGS) -JTREG_322_OPTIONS = $(JTREG_COMMON_OPTIONS) $(JAVA_ARGS:%=-vmoption:%) $@ - -# Default make rule -all: clean check tests - -# Chaeck to make sure these directories exist -check: $(JT_HOME) $(JAVA_HOME) $(JTREG) +ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput -# Prime the test run -primecounts: FRC - @rm -f -r $(JTREG_TOTALS_DIR) - @mkdir -p $(JTREG_TOTALS_DIR) - @echo "0" > $(JTREG_FAILED) - @echo "0" > $(JTREG_PASSED) +# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) +ifndef PRODUCT_HOME + # Try to use j2sdk-image if it exists + ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image + PRODUCT_HOME := \ + $(shell \ + if [ -d $(ABS_JDK_IMAGE) ] ; then \ + $(ECHO) "$(ABS_JDK_IMAGE)"; \ + else \ + $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + fi) +endif -# Run the tests and determine the 'make' command exit status -# Ultimately we determine the make exit code based on the passed/failed count -tests: primecounts $(TESTDIRS) - @echo "JTREG TOTAL: passed=`cat $(JTREG_PASSED)` failed=`cat $(JTREG_FAILED)`" - zip -q -r $(JPRT_ARCHIVE_BUNDLE) $(JTREG_ALL_OUTPUT_DIRNAME) - @if [ `cat $(JTREG_FAILED)` -ne 0 -o \ - `cat $(JTREG_PASSED)` -le 0 ] ; then \ - echo "JTREG FAILED"; \ - exit 1; \ - else \ - echo "JTREG PASSED"; \ - exit 0; \ - fi - -# Just make sure these directires exist -$(JT_HOME) $(JAVA_HOME): FRC - @if [ ! -d $@ ] ; then \ - echo "ERROR: Directory $@ does not exist"; \ - exit 1; \ - fi - -# Make sure this file exists -$(JTREG): FRC - @if [ ! -f $@ ] ; then \ - echo "ERROR: File $@ does not exist"; \ - exit 1; \ - fi +# Expect JPRT to set JAVA_ARGS (e.g. -server etc.) +JAVA_OPTIONS = +ifdef JAVA_ARGS + JAVA_OPTIONS = $(JAVA_ARGS) +endif -# Process each test directory one by one, this rule always completes. -# Note that the use of 'tee' tosses the jtreg process exit status, this -# is as expected because even if jtreg fails, we need to save the -# output. So we update the JTREG_PASSED and JTREG_FAILED count files. -# Note that missing the 'results:' line in the last few lines of output -# will indicate a failure (or a bump by one of the JTREG_FAILED file. -# Note that passed: 0 or no passed: indication means a failure. -# Note that any indication of the word 'failed' indicates failure. -# Ultimately if the contents of JTREG_FAILED is not 0, we have failed -# tests, and if the contents of JTREG_PASSED is 0, we consider that a -# failure. -$(TESTDIRS): FRC - @if [ ! -d $@ ] ; then \ - echo "ERROR: Directory $@ does not exist"; \ - exit 1; \ - fi - @echo "---------------------------------------------------" - @rm -f -r $(JTREG_TEST_OUTPUT_DIR) - @mkdir -p $(JTREG_TEST_OUTPUT_DIR) - @mkdir -p $(JTREG_TEST_WORK_DIR) - @mkdir -p $(JTREG_TEST_WORK_DIR)/scratch - @mkdir -p $(JTREG_TEST_REPORT_DIR) - @mkdir -p $(JTREG_TEST_TEMP_DIR) - @echo "Testing $@" - @echo "Using JAVA_HOME=$(JAVA_HOME)" - @echo "Using JAVA_ARGS=$(JAVA_ARGS)" - @if [ "`$(JTREG) -help 2>&1 | fgrep -- -vmoption`" != "" ] ; then \ - echo "Assume we are using jtreg 3.2.2_01 or newer"; \ - echo "$(JTREG) $(JTREG_322_OPTIONS)"; \ - $(JTREG) $(JTREG_322_OPTIONS) 2>&1 | tee $(JTREG_TEMP_OUTPUT) ; \ - else \ - echo "Assume we are using jtreg 2.1.6"; \ - echo "$(JTREG) $(JTREG_216_OPTIONS)"; \ - $(JTREG) $(JTREG_216_OPTIONS) 2>&1 | tee $(JTREG_TEMP_OUTPUT) ; \ - fi - @echo "---------------------------------------------------" - @echo "Extracting passed and failed counts from jtreg output" - @tail -10 $(JTREG_TEMP_OUTPUT) | fgrep -i 'results:' | \ - tail -1 | tee $(JTREG_TEMP_RESULTS) - @sed -e 's@.*\ passed:\ \([1-9][0-9]*\).*@\1@' $(JTREG_TEMP_RESULTS) \ - > $(JTREG_TEMP_PASSED) - @if [ "`cat $(JTREG_TEMP_PASSED)`" = "" ] ; then \ - echo "ERROR: No passed indication in results"; \ - expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \ - elif [ `cat $(JTREG_TEMP_PASSED)` -le 0 ] ; then \ - echo "ERROR: Passed count appears to be 0"; \ - expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \ - elif [ "`fgrep -i failed $(JTREG_TEMP_RESULTS)`" = "" ] ; then \ - echo "No indication anything failed"; \ - expr `cat $(JTREG_PASSED)` '+' `cat $(JTREG_TEMP_PASSED)` \ - > $(JTREG_PASSED); \ - else \ - sed -e 's@.*\ failed:\ \([1-9][0-9]*\).*@\1@' $(JTREG_TEMP_FAILED) \ - > $(JTREG_TEMP_FAILED); \ - if [ "`cat $(JTREG_TEMP_FAILED)`" = "" ] ; then \ - echo "ERROR: Failed pattern but no failed count in results"; \ - expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \ - elif [ `cat $(JTREG_TEMP_FAILED)` -le 0 ] ; then \ - echo "ERROR: Failed count is 0, did something failed or not?"; \ - expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \ - else \ - expr `cat $(JTREG_FAILED)` '+' `cat $(JTREG_TEMP_FAILED)` \ - > $(JTREG_FAILED); \ - fi; \ - fi - @echo "---------------------------------------------------" - @echo "Summary: " - @if [ -f $(JTREG_TEST_SUMMARY) ] ; then \ - cat $(JTREG_TEST_SUMMARY) ; \ - else \ - echo "ERROR: Missing $(JTREG_TEST_SUMMARY)"; \ - fi - @echo "---------------------------------------------------" +# Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) +ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip +ifdef JPRT_ARCHIVE_BUNDLE + ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) +endif + +# How to create the test bundle (pass or fail, we want to create this) +BUNDLE_UP = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` \ + && $(CD) $(ABS_TEST_OUTPUT_DIR) \ + && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) +BUNDLE_UP_FAILED = ( exitCode=$$? && $(BUNDLE_UP) && exit $${exitCode} ) + +################################################################ + +# Default make rule (runs jtreg_tests) +all: jtreg_tests + @$(ECHO) "Testing completed successfully" + +# Prep for output +prep: clean + @$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR) + @$(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` # Cleanup clean: - rm -f -r $(JTREG_ALL_OUTPUT_DIR) - rm -f $(JPRT_ARCHIVE_BUNDLE) + $(RM) -r $(ABS_TEST_OUTPUT_DIR) + $(RM) $(ARCHIVE_BUNDLE) + +################################################################ + +# jtreg tests + +# Expect JT_HOME to be set for jtreg tests. (home for jtreg) +JT_HOME = $(SLASH_JAVA)/re/jtreg/4.0/promoted/latest/binaries/jtreg +ifdef JPRT_JTREG_HOME + JT_HOME = $(JPRT_JTREG_HOME) +endif + +# Expect JPRT to set TESTDIRS to the jtreg test dirs +JTREG_TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof +ifdef TESTDIRS + JTREG_TESTDIRS = $(TESTDIRS) +endif + +# Default JTREG to run (win32 script works for everybody) +JTREG = $(JT_HOME)/win32/bin/jtreg + +# Option to tell jtreg to not run tests marked with "ignore" +ifeq ($(PLATFORM), windows) + JTREG_KEY_OPTION = -k:!ignore +else + JTREG_KEY_OPTION = -k:\!ignore +endif + +#EXTRA_JTREG_OPTIONS = -FRC: +jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) + $(JTREG) -a -v:fail,error \ + $(JTREG_KEY_OPTION) \ + $(EXTRA_JTREG_OPTIONS) \ + -r:$(ABS_TEST_OUTPUT_DIR)/JTreport \ + -w:$(ABS_TEST_OUTPUT_DIR)/JTwork \ + -jdk:$(PRODUCT_HOME) \ + $(JAVA_OPTIONS:%=-vmoption:%) \ + $(JTREG_TESTDIRS) \ + || $(BUNDLE_UP_FAILED) + $(BUNDLE_UP) + +PHONY_LIST += jtreg_tests + +################################################################ + +# packtest + +# Expect JPRT to set JPRT_PACKTEST_HOME. +PACKTEST_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/packtest +ifdef JPRT_PACKTEST_HOME + PACKTEST_HOME = $(JPRT_PACKTEST_HOME) +endif +#EXTRA_PACKTEST_OPTIONS = + +packtest: prep $(PACKTEST_HOME)/ptest $(PRODUCT_HOME) + ( $(CD) $(PACKTEST_HOME) && \ + $(PACKTEST_HOME)/ptest \ + -t "$(PRODUCT_HOME)" \ + $(PACKTEST_STRESS_OPTION) \ + $(EXTRA_PACKTEST_OPTIONS) \ + -W $(ABS_TEST_OUTPUT_DIR) \ + $(JAVA_OPTIONS:%=-J %) \ + ) || $(BUNDLE_UP_FAILED) + $(BUNDLE_UP) + +packtest_stress: PACKTEST_STRESS_OPTION=-s +packtest_stress: packtest + +PHONY_LIST += packtest packtest_stress + +################################################################ + +# Phony targets (e.g. these are not filenames) +.PHONY: all clean prep $(PHONY_LIST) + +################################################################ + diff -r 5a725d2f0daa -r 3e5496df0d2b jaxp/.hgtags --- a/jaxp/.hgtags Thu Sep 11 11:25:48 2008 -0700 +++ b/jaxp/.hgtags Wed Jul 05 16:41:30 2017 +0200 @@ -9,3 +9,4 @@ 400a5ee432cc2db9031e06852ddde9264a192b48 jdk7-b32 95375835527f0bf06124ce984266e2ad5de8a6dc jdk7-b33 01facdf8cabdeaaf68cca037aef56cc5f074897f jdk7-b34 +eac46d1eb7f0935ba04f1c7929ec15423fd0309e jdk7-b35 diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/.hgtags --- a/jdk/.hgtags Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/.hgtags Wed Jul 05 16:41:30 2017 +0200 @@ -9,3 +9,4 @@ c51121419e30eac5f0fbbce45ff1711c4ce0de28 jdk7-b32 fa4c0a6cdd25d97d4e6f5d7aa180bcbb0e0d56af jdk7-b33 434055a0716ee44bca712ebca02fc04b20e6e288 jdk7-b34 +cf4894b78ceb966326e93bf221db0c2d14d59218 jdk7-b35 diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/common/Defs.gmk --- a/jdk/make/common/Defs.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/common/Defs.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -704,7 +704,20 @@ # Install of imported file (JDK_IMPORT_PATH, or some other external location) define install-import-file @$(ECHO) "ASSEMBLY_IMPORT: $@" -$(install-file) +$(prep-target) +$(CP) $< $@ +@if [ "$(PLATFORM)" = "linux" -a "$(@F)" = "libjvm.so" ] ; then \ + if [ -x /usr/sbin/selinuxenabled ] ; then \ + /usr/sbin/selinuxenabled; \ + if [ $$? = 0 ] ; then \ + $(ECHO) "/usr/bin/chcon -t textrel_shlib_t $@"; \ + /usr/bin/chcon -t textrel_shlib_t $@; \ + if [ $$? != 0 ]; then \ + echo "ERROR: Cannot chcon $@"; \ + fi; \ + fi; \ + fi; \ +fi endef .PHONY: all build clean clobber diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/common/Sanity.gmk --- a/jdk/make/common/Sanity.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/common/Sanity.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -70,7 +70,6 @@ sane-compiler \ sane-cacerts \ sane-ant_version \ - sane-findbugs_version \ sane-zip_version \ sane-msvcrt_path diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/common/shared/Defs.gmk --- a/jdk/make/common/shared/Defs.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/common/shared/Defs.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -352,30 +352,6 @@ HOTSPOT_DOCS_IMPORT_PATH :=$(call DirExists,$(HOTSPOT_IMPORT_PATH)/docs,$(PROMOTED_BUILD_BASEDIR)/docs,/NO_DOCS_DIR) endif -# PREVIOUS_JDK_FILE: filename of install bundle for previous JDK -ifdef ALT_PREVIOUS_JDK_FILE - PREVIOUS_JDK_FILE =$(ALT_PREVIOUS_JDK_FILE) -else - PREVIOUS_JDK_FILE = jdk-$(PREVIOUS_JDK_UNDERSCORE_VERSION)-$(PLATFORM)-$(ARCH)$(BUNDLE_FILE_SUFFIX) -endif -export PREVIOUS_JDK_FILE -PREVIOUS_JDK_FILE:=$(call AltCheckSpaces,PREVIOUS_JDK_FILE) -PREVIOUS_JDK_FILE:=$(call AltCheckValue,PREVIOUS_JDK_FILE) - -# PREVIOUS_JRE_FILE: filename of install bundle for previous JRE -ifdef ALT_PREVIOUS_JRE_FILE - PREVIOUS_JRE_FILE =$(ALT_PREVIOUS_JRE_FILE) -else - PREVIOUS_JRE_FILE = jre-$(PREVIOUS_JDK_UNDERSCORE_VERSION)-$(PLATFORM)-$(ARCH)$(BUNDLE_FILE_SUFFIX) -endif -export PREVIOUS_JRE_FILE -PREVIOUS_JRE_FILE:=$(call AltCheckSpaces,PREVIOUS_JRE_FILE) -PREVIOUS_JRE_FILE:=$(call AltCheckValue,PREVIOUS_JRE_FILE) - -# Set here as shared variables -PREVIOUS_JRE_BUNDLE = $(PREVIOUS_RELEASE_PATH)/$(PREVIOUS_JRE_FILE) -PREVIOUS_JDK_BUNDLE = $(PREVIOUS_RELEASE_PATH)/$(PREVIOUS_JDK_FILE) - # These are the same on all platforms but require the above platform include 1st # BOOTDIR: Bootstrap JDK, previous released JDK. @@ -389,19 +365,70 @@ BOOTDIR:=$(call AltCheckSpaces,BOOTDIR) BOOTDIR:=$(call AltCheckValue,BOOTDIR) -# PREVIOUS_RELEASE_PATH: path to where previous release bundles are -ifdef ALT_PREVIOUS_RELEASE_PATH - PREVIOUS_RELEASE_PATH :=$(call OptFullPath,$(ALT_PREVIOUS_RELEASE_PATH)) -else - PREVIOUS_RELEASE_PATH =$(SLASH_JAVA)/re/jdk/$(PREVIOUS_JDK_VERSION)/archive/fcs/bundles/$(PLATFORM)-$(ARCH) -endif -export PREVIOUS_RELEASE_PATH -PREVIOUS_RELEASE_PATH:=$(call AltCheckSpaces,PREVIOUS_RELEASE_PATH) -PREVIOUS_RELEASE_PATH:=$(call AltCheckValue,PREVIOUS_RELEASE_PATH) +# PREVIOUS_FCS_RE_AREA: re path to where previous release binaries/bundles are +PREVIOUS_FCS_RE_AREA = $(SLASH_JAVA)/re/jdk/$(PREVIOUS_JDK_VERSION)/archive/fcs # PREVIOUS_RELEASE_IMAGE: Previous install image to compare against ifdef ALT_PREVIOUS_RELEASE_IMAGE + + # Explicit image provided, no bundle access needed PREVIOUS_RELEASE_IMAGE :=$(call FullPath,$(ALT_PREVIOUS_RELEASE_IMAGE)) + +else + + # PREVIOUS_RELEASE_PATH: path to where previous release bundles are + ifdef ALT_PREVIOUS_RELEASE_PATH + PREVIOUS_RELEASE_PATH :=$(call OptFullPath,$(ALT_PREVIOUS_RELEASE_PATH)) + else + PREVIOUS_RELEASE_PATH := \ + $(call DirExists,$(PREVIOUS_FCS_RE_AREA)/bundles/$(PLATFORM)-$(ARCH),,) + endif + + # Depending on if we have access to these bundles + ifeq ($(PREVIOUS_RELEASE_PATH),) + # Use images in re area or BOOTDIR (which is normally the previous release) + PREVIOUS_RELEASE_IMAGE := \ + $(call DirExists,$(PREVIOUS_FCS_RE_AREA)/binaries/$(PLATFORM)-$(ARCH),$(BOOTDIR),) + else + # Get names of and paths to bundles + PREVIOUS_RELEASE_PATH:=$(call AltCheckSpaces,PREVIOUS_RELEASE_PATH) + PREVIOUS_RELEASE_PATH:=$(call AltCheckValue,PREVIOUS_RELEASE_PATH) + export PREVIOUS_RELEASE_PATH + + # PREVIOUS_JDK_FILE: filename of install bundle for previous JDK + ifdef ALT_PREVIOUS_JDK_FILE + PREVIOUS_JDK_FILE =$(ALT_PREVIOUS_JDK_FILE) + else + PREVIOUS_JDK_FILE = \ + jdk-$(PREVIOUS_JDK_UNDERSCORE_VERSION)-$(PLATFORM)-$(ARCH)$(BUNDLE_FILE_SUFFIX) + endif + export PREVIOUS_JDK_FILE + PREVIOUS_JDK_FILE:=$(call AltCheckSpaces,PREVIOUS_JDK_FILE) + PREVIOUS_JDK_FILE:=$(call AltCheckValue,PREVIOUS_JDK_FILE) + + # PREVIOUS_JRE_FILE: filename of install bundle for previous JRE + ifdef ALT_PREVIOUS_JRE_FILE + PREVIOUS_JRE_FILE =$(ALT_PREVIOUS_JRE_FILE) + else + PREVIOUS_JRE_FILE = \ + jre-$(PREVIOUS_JDK_UNDERSCORE_VERSION)-$(PLATFORM)-$(ARCH)$(BUNDLE_FILE_SUFFIX) + endif + export PREVIOUS_JRE_FILE + PREVIOUS_JRE_FILE:=$(call AltCheckSpaces,PREVIOUS_JRE_FILE) + PREVIOUS_JRE_FILE:=$(call AltCheckValue,PREVIOUS_JRE_FILE) + + # Paths to these bundles + PREVIOUS_JRE_BUNDLE = $(PREVIOUS_RELEASE_PATH)/$(PREVIOUS_JRE_FILE) + PREVIOUS_JDK_BUNDLE = $(PREVIOUS_RELEASE_PATH)/$(PREVIOUS_JDK_FILE) + endif + +endif + +# Indicate we are using an image comparison +ifneq ($(PREVIOUS_RELEASE_IMAGE),) + PREVIOUS_RELEASE_PATH = USING-PREVIOUS_RELEASE_IMAGE + PREVIOUS_JRE_BUNDLE = USING-PREVIOUS_RELEASE_IMAGE + PREVIOUS_JDK_BUNDLE = USING-PREVIOUS_RELEASE_IMAGE endif # CACERTS_FILE: if OPENJDK is false and the internal version of the file @@ -513,23 +540,17 @@ endif endif -# Utilities ant and findbugs -ifeq ($(ANT_HOME),) - ANT_HOME := $(call DirExists,/usr/share/ant,$(JDK_DEVTOOLS_DIR)/share/ant/latest,) +# Utilities ant +ifeq ($(PLATFORM), windows) + ifeq ($(ANT_HOME),) + ANT_HOME := $(call DirExists,$(JDK_DEVTOOLS_DIR)/share/ant/latest,,) + endif endif ifeq ($(ANT_HOME),) ANT = ant else ANT = $(ANT_HOME)/bin/ant endif -ifeq ($(FINDBUGS_HOME),) - FINDBUGS_HOME := $(call DirExists,/usr/share/findbugs,$(JDK_DEVTOOLS_DIR)/share/findbugs/latest,) -endif -ifeq ($(FINDBUGS_HOME),) - FINDBUGS = findbugs -else - FINDBUGS = $(FINDBUGS_HOME)/bin/findbugs -endif ifdef ALT_COPYRIGHT_YEAR COPYRIGHT_YEAR = $(ALT_COPYRIGHT_YEAR) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/common/shared/Sanity-Settings.gmk --- a/jdk/make/common/shared/Sanity-Settings.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/common/shared/Sanity-Settings.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,6 @@ ALL_SETTINGS+=$(call addRequiredSetting,VARIANT) ALL_SETTINGS+=$(call addAltSetting,JDK_DEVTOOLS_DIR) ALL_SETTINGS+=$(call addOptionalSetting,ANT_HOME) -ALL_SETTINGS+=$(call addOptionalSetting,FINDBUGS_HOME) ALL_SETTINGS+=$(call addAltSetting,UNIXCOMMAND_PATH) ALL_SETTINGS+=$(call addAltSetting,COMPILER_PATH) ALL_SETTINGS+=$(call addAltSetting,DEVTOOLS_PATH) @@ -119,7 +118,6 @@ ALL_SETTINGS+=$(call addRequiredVersionSetting,LINK_VER) endif ALL_SETTINGS+=$(call addRequiredVersionSetting,ANT_VER) -ALL_SETTINGS+=$(call addRequiredVersionSetting,FINDBUGS_VER) ALL_SETTINGS+=$(call addRequiredSetting,TEMPDIR) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/common/shared/Sanity.gmk --- a/jdk/make/common/shared/Sanity.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/common/shared/Sanity.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -107,21 +107,9 @@ BOOT_VER :=$(call GetVersion,"$(_BOOT_VER)") REQUIRED_ANT_VER := 1.6.3 -ifeq ($(ANT_HOME),) - _ANT_VER:=$(shell JAVACMD="$(BOOTDIR)/bin/java" $(ANT) -version 2>&1 ) -else - _ANT_VER:=$(shell JAVACMD="$(BOOTDIR)/bin/java" ANT_HOME="$(ANT_HOME)" $(ANT) -version 2>&1 ) -endif +_ANT_VER:=$(shell $(ANT) -version 2>&1 ) ANT_VER:=$(call GetVersion,"$(_ANT_VER)") -REQUIRED_FINDBUGS_VER := 1.2 -ifeq ($(FINDBUGS_HOME),) - _FINDBUGS_VER:=$(shell $(FINDBUGS) -javahome "$(BOOTDIR)" -textui -version 2>&1 ) -else - _FINDBUGS_VER:=$(shell FINDBUGS_HOME="$(FINDBUGS_HOME)" $(FINDBUGS) -javahome "$(BOOTDIR)" -textui -version 2>&1 ) -endif -FINDBUGS_VER:=$(call GetVersion,"$(_FINDBUGS_VER)") - ifdef ALT_BINDIR ALT_BINDIR_VERSION := $(shell $(ALT_BINDIR)/java$(EXE_SUFFIX) -version 2>&1 | $(NAWK) -F'"' '{ print $$2 }') ALT_BINDIR_OK := $(shell $(ECHO) $(ALT_BINDIR_VERSION) | $(EGREP) -c '^$(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION)') @@ -182,7 +170,6 @@ sane-alsa-versioncheck \ sane-alsa-headers \ sane-ant_version \ - sane-findbugs_version \ sane-zip_version \ sane-unzip_version \ sane-msvcrt_path \ @@ -1217,19 +1204,6 @@ fi ###################################################### -# Check the findbugs version -###################################################### -FINDBUGS_CHECK :=$(call CheckVersions,$(FINDBUGS_VER),$(REQUIRED_FINDBUGS_VER)) -sane-findbugs_version: - @if [ "$(FINDBUGS_CHECK)" != "same" \ - -a "$(FINDBUGS_CHECK)" != "newer" ]; then \ - $(ECHO) "WARNING: The version of findbugs being used is older than \n" \ - " the required version of '$(REQUIRED_FINDBUGS_VER)'. \n" \ - " The version of findbugs found was '$(FINDBUGS_VER)'. \n" \ - "" >> $(WARNING_FILE) ; \ - fi - -###################################################### # Check the zip file version ###################################################### ZIP_CHECK :=$(call CheckVersions,$(ZIP_VER),$(REQUIRED_ZIP_VER)) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/docs/CORE_PKGS.gmk --- a/jdk/make/docs/CORE_PKGS.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/docs/CORE_PKGS.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -158,6 +158,7 @@ javax.management.event \ javax.management.loading \ javax.management.monitor \ + javax.management.namespace \ javax.management.relation \ javax.management.openmbean \ javax.management.timer \ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/java/FILES_java.gmk --- a/jdk/make/java/java/FILES_java.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/java/FILES_java.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -449,6 +449,7 @@ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ sun/misc/JavaIODeleteOnExitAccess.java \ - sun/misc/JavaIOFileDescriptorAccess.java + sun/misc/JavaIOFileDescriptorAccess.java \ + sun/misc/JavaNioAccess.java FILES_java = $(JAVA_JAVA_java) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/java/mapfile-vers --- a/jdk/make/java/java/mapfile-vers Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/java/mapfile-vers Wed Jul 05 16:41:30 2017 +0200 @@ -222,8 +222,6 @@ Java_java_lang_UNIXProcess_waitForProcessExit; Java_java_lang_UNIXProcess_forkAndExec; Java_java_lang_UNIXProcess_destroyProcess; - Java_java_nio_Bits_copyFromByteArray; - Java_java_nio_Bits_copyToByteArray; Java_java_nio_Bits_copyFromShortArray; Java_java_nio_Bits_copyToShortArray; Java_java_nio_Bits_copyFromIntArray; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/jli/Makefile --- a/jdk/make/java/jli/Makefile Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/jli/Makefile Wed Jul 05 16:41:30 2017 +0200 @@ -113,7 +113,11 @@ JAVALIB = OTHER_LCF = -export:JLI_Launch \ -export:JLI_ManifestIterate \ - -export:JLI_SetTraceLauncher + -export:JLI_SetTraceLauncher \ + -export:JLI_ReportErrorMessage \ + -export:JLI_ReportErrorMessageSys \ + -export:JLI_ReportMessage \ + -export:JLI_ReportExceptionDescription endif diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/jli/mapfile-vers --- a/jdk/make/java/jli/mapfile-vers Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/jli/mapfile-vers Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,10 @@ JLI_Launch; JLI_ManifestIterate; JLI_SetTraceLauncher; + JLI_ReportErrorMessage; + JLI_ReportErrorMessageSys; + JLI_ReportMessage; + JLI_ReportExceptionDescription; local: *; }; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/nio/FILES_java.gmk --- a/jdk/make/java/nio/FILES_java.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/nio/FILES_java.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -26,6 +26,7 @@ FILES_src = \ java/nio/Bits.java \ java/nio/Buffer.java \ + java/nio/BufferPoolMXBean.java \ java/nio/ByteOrder.java \ java/nio/MappedByteBuffer.java \ java/nio/StringCharBuffer.java \ @@ -38,6 +39,9 @@ java/nio/channels/FileLock.java \ java/nio/channels/GatheringByteChannel.java \ java/nio/channels/InterruptibleChannel.java \ + java/nio/channels/MembershipKey.java \ + java/nio/channels/MulticastChannel.java \ + java/nio/channels/NetworkChannel.java \ java/nio/channels/ReadableByteChannel.java \ java/nio/channels/ScatteringByteChannel.java \ java/nio/channels/SelectableChannel.java \ @@ -72,6 +76,7 @@ sun/nio/ch/DatagramSocketAdaptor.java \ sun/nio/ch/DefaultSelectorProvider.java \ sun/nio/ch/DirectBuffer.java \ + sun/nio/ch/ExtendedSocketOption.java \ sun/nio/ch/FileChannelImpl.java \ sun/nio/ch/FileDispatcher.java \ sun/nio/ch/FileKey.java \ @@ -79,12 +84,14 @@ sun/nio/ch/IOUtil.java \ sun/nio/ch/IOStatus.java \ sun/nio/ch/IOVecWrapper.java \ + sun/nio/ch/MembershipKeyImpl.java \ + sun/nio/ch/MembershipRegistry.java \ sun/nio/ch/NativeDispatcher.java \ sun/nio/ch/NativeObject.java \ sun/nio/ch/NativeThread.java \ sun/nio/ch/NativeThreadSet.java \ sun/nio/ch/Net.java \ - sun/nio/ch/OptionAdaptor.java \ + sun/nio/ch/OptionKey.java \ sun/nio/ch/PipeImpl.java \ sun/nio/ch/PollArrayWrapper.java \ sun/nio/ch/Reflect.java \ @@ -98,8 +105,7 @@ sun/nio/ch/SocketAdaptor.java \ sun/nio/ch/SocketChannelImpl.java \ sun/nio/ch/SocketDispatcher.java \ - sun/nio/ch/SocketOpts.java \ - sun/nio/ch/SocketOptsImpl.java \ + sun/nio/ch/SocketOptionRegistry.java \ sun/nio/ch/SourceChannelImpl.java \ sun/nio/ch/Util.java \ \ @@ -239,6 +245,7 @@ java/nio/InvalidMarkException.java \ java/nio/ReadOnlyBufferException.java \ \ + java/nio/channels/AlreadyBoundException.java \ java/nio/channels/AlreadyConnectedException.java \ java/nio/channels/AsynchronousCloseException.java \ java/nio/channels/ClosedByInterruptException.java \ @@ -257,14 +264,15 @@ java/nio/channels/UnresolvedAddressException.java \ java/nio/channels/UnsupportedAddressTypeException.java \ \ - sun/nio/ch/AlreadyBoundException.java \ - \ java/nio/charset/CharacterCodingException.java \ java/nio/charset/IllegalCharsetNameException.java \ java/nio/charset/UnsupportedCharsetException.java FILES_gen_csp = sun/nio/cs/StandardCharsets.java -FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) $(FILES_gen_csp) +FILES_gen_sor = sun/nio/ch/SocketOptionRegistry.java + +FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) \ + $(FILES_gen_csp) $(FILES_gen_sor) FILES_java = $(FILES_src) $(FILES_gen) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/nio/Makefile --- a/jdk/make/java/nio/Makefile Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/nio/Makefile Wed Jul 05 16:41:30 2017 +0200 @@ -56,18 +56,18 @@ sun/nio/ch/DevPollSelectorProvider.java \ sun/nio/ch/InheritedChannel.java \ sun/nio/ch/PollSelectorProvider.java \ - sun/nio/ch/PollSelectorImpl.java + sun/nio/ch/PollSelectorImpl.java FILES_c += \ DevPollArrayWrapper.c \ InheritedChannel.c \ - PollArrayWrapper.c \ - NativeThread.c + NativeThread.c \ + PollArrayWrapper.c FILES_export += \ sun/nio/ch/DevPollArrayWrapper.java \ sun/nio/ch/InheritedChannel.java \ - sun/nio/ch/NativeThread.java + sun/nio/ch/NativeThread.java endif # PLATFORM = solaris ifeq ($(PLATFORM), windows) @@ -94,14 +94,14 @@ FILES_c += \ EPollArrayWrapper.c \ - PollArrayWrapper.c \ InheritedChannel.c \ - NativeThread.c + NativeThread.c \ + PollArrayWrapper.c FILES_export += \ sun/nio/ch/EPollArrayWrapper.java \ sun/nio/ch/InheritedChannel.java \ - sun/nio/ch/NativeThread.java + sun/nio/ch/NativeThread.java endif # PLATFORM = linux # Find platform-specific C source files @@ -618,12 +618,6 @@ @$(RM) $@.temp $(GEN_EX_CMD) $(BUF_SRC)/exceptions $(BUF_GEN) -$(SCH_GEN)/%Exception.java: genExceptions.sh $(SCH_SRC)/exceptions - $(prep-target) - @$(RM) $@.temp - $(GEN_EX_CMD) $(SCH_SRC)/exceptions $(SCH_GEN) - - # # Generated charset-provider classes # @@ -638,4 +632,29 @@ HASHER="$(BOOT_JAVA_CMD) -jar $(HASHER_JARFILE)" \ $(SH) -e genCharsetProvider.sh $(SCS_SRC)/standard-charsets $(SCS_GEN) +# +# Generated channel implementation classes. +# C source is compiled in TEMPDIR to avoid turds left by Windows compilers. +# + +GENSOR_SRC = $(SHARE_SRC)/native/sun/nio/ch/genSocketOptionRegistry.c + +GENSOR_EXE = $(TEMPDIR)/genSocketOptionRegistry$(EXE_SUFFIX) + +SOR_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSOR_SRC) | \ + $(NAWK) '/^.*Copyright.*Sun/ { print $$3 }') + +$(TEMPDIR)/$(GENSOR_SRC) : $(GENSOR_SRC) + $(install-file) + +$(GENSOR_EXE) : $(TEMPDIR)/$(GENSOR_SRC) + $(prep-target) + ($(CD) $(TEMPDIR); $(CC) $(CPPFLAGS) $(LDDFLAGS) \ + -o genSocketOptionRegistry$(EXE_SUFFIX) $(GENSOR_SRC)) + +$(SCH_GEN)/SocketOptionRegistry.java: $(GENSOR_EXE) + $(prep-target) + NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(SOR_COPYRIGHT_YEARS) > $@ + $(GENSOR_EXE) >> $@ + .PHONY: sources diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/nio/mapfile-linux --- a/jdk/make/java/nio/mapfile-linux Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/nio/mapfile-linux Wed Jul 05 16:41:30 2017 +0200 @@ -1,3 +1,27 @@ +# +# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# SUNWprivate_1.1 { global: @@ -18,6 +42,8 @@ Java_sun_nio_ch_EPollArrayWrapper_fdLimit; Java_sun_nio_ch_EPollArrayWrapper_init; Java_sun_nio_ch_EPollArrayWrapper_interrupt; + Java_sun_nio_ch_EPollArrayWrapper_offsetofData; + Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent; Java_sun_nio_ch_FileChannelImpl_close0; Java_sun_nio_ch_FileChannelImpl_force0; Java_sun_nio_ch_FileChannelImpl_initIDs; @@ -59,20 +85,29 @@ Java_sun_nio_ch_NativeThread_init; Java_sun_nio_ch_NativeThread_signal; Java_sun_nio_ch_Net_socket0; - Java_sun_nio_ch_Net_bind; - Java_sun_nio_ch_Net_connect; + Java_sun_nio_ch_Net_bind0; + Java_sun_nio_ch_Net_connect0; + Java_sun_nio_ch_Net_listen; Java_sun_nio_ch_Net_localPort; Java_sun_nio_ch_Net_localInetAddress; Java_sun_nio_ch_Net_getIntOption0; Java_sun_nio_ch_Net_setIntOption0; Java_sun_nio_ch_Net_initIDs; + Java_sun_nio_ch_Net_isIPv6Available0; + Java_sun_nio_ch_Net_joinOrDrop4; + Java_sun_nio_ch_Net_blockOrUnblock4; + Java_sun_nio_ch_Net_joinOrDrop6; + Java_sun_nio_ch_Net_blockOrUnblock6; + Java_sun_nio_ch_Net_setInterface4; + Java_sun_nio_ch_Net_getInterface4; + Java_sun_nio_ch_Net_setInterface6; + Java_sun_nio_ch_Net_getInterface6; + Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_initIDs; - Java_sun_nio_ch_ServerSocketChannelImpl_listen; Java_sun_nio_ch_SocketChannelImpl_checkConnect; - Java_sun_nio_ch_SocketChannelImpl_shutdown; local: *; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/java/nio/mapfile-solaris --- a/jdk/make/java/nio/mapfile-solaris Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/java/nio/mapfile-solaris Wed Jul 05 16:41:30 2017 +0200 @@ -1,3 +1,27 @@ +# +# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# SUNWprivate_1.1 { global: @@ -59,20 +83,29 @@ Java_sun_nio_ch_NativeThread_init; Java_sun_nio_ch_NativeThread_signal; Java_sun_nio_ch_Net_socket0; - Java_sun_nio_ch_Net_bind; - Java_sun_nio_ch_Net_connect; + Java_sun_nio_ch_Net_bind0; + Java_sun_nio_ch_Net_connect0; + Java_sun_nio_ch_Net_listen; Java_sun_nio_ch_Net_localPort; Java_sun_nio_ch_Net_localInetAddress; Java_sun_nio_ch_Net_getIntOption0; Java_sun_nio_ch_Net_setIntOption0; Java_sun_nio_ch_Net_initIDs; + Java_sun_nio_ch_Net_isIPv6Available0; + Java_sun_nio_ch_Net_joinOrDrop4; + Java_sun_nio_ch_Net_blockOrUnblock4; + Java_sun_nio_ch_Net_joinOrDrop6; + Java_sun_nio_ch_Net_blockOrUnblock6; + Java_sun_nio_ch_Net_setInterface4; + Java_sun_nio_ch_Net_getInterface4; + Java_sun_nio_ch_Net_setInterface6; + Java_sun_nio_ch_Net_getInterface6; + Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_initIDs; - Java_sun_nio_ch_ServerSocketChannelImpl_listen; Java_sun_nio_ch_SocketChannelImpl_checkConnect; - Java_sun_nio_ch_SocketChannelImpl_shutdown; local: *; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/jprt.config --- a/jdk/make/jprt.config Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/jprt.config Wed Jul 05 16:41:30 2017 +0200 @@ -100,20 +100,16 @@ # Needed for langtools, maybe other parts of the build ANT_HOME="${share}/ant/latest" export ANT_HOME -FINDBUGS_HOME="${share}/findbugs/latest" -export FINDBUGS_HOME # The 3 bin directories in common to all platforms sharebin="${share}/bin" antbin="${ANT_HOME}/bin" -findbugsbin="${FINDBUGS_HOME}/bin" # Check input dirMustExist "${bootdir}" ALT_BOOTDIR dirMustExist "${slashjava}" ALT_SLASH_JAVA dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH dirMustExist "${ANT_HOME}" ANT_HOME -dirMustExist "${FINDBUGS_HOME}" FINDBUGS_HOME # Use the JDK import for now (FIXME: use the binary plugs?) if [ "${OPENJDK}" = true ] ; then @@ -143,7 +139,7 @@ ALT_COMPILER_PATH="${compiler_path}" export ALT_COMPILER_PATH dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin}:${findbugsbin} + path4sdk=${compiler_path}:${sharebin}:${antbin} # Add basic solaris system paths path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin @@ -180,7 +176,7 @@ ALT_COMPILER_PATH="${compiler_path}" export ALT_COMPILER_PATH dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin}:${findbugsbin} + path4sdk=${compiler_path}:${sharebin}:${antbin} # Add basic paths path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin @@ -228,7 +224,7 @@ dosname="${mkshome}/mksnt/dosname -s" # Most unix utilities are in the mksnt directory of ROOTDIR unixcommand_path="${mkshome}/mksnt" - path4sdk="${sharebin};${antbin};${findbugsbin};${unixcommand_path}" + path4sdk="${sharebin};${antbin};${unixcommand_path}" dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH devtools_path="${jdk_devtools}/win32/bin" path4sdk="${devtools_path};${path4sdk}" @@ -246,7 +242,7 @@ dosname="/usr/bin/cygpath -a -m -s" # Most unix utilities are in the /usr/bin unixcommand_path="/usr/bin" - path4sdk="${sharebin};${antbin};${findbugsbin};${unixcommand_path}" + path4sdk="${sharebin};${antbin};${unixcommand_path}" dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH # Find GNU make make="${unixcommand_path}/make.exe" diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/mksample/nio/Makefile --- a/jdk/make/mksample/nio/Makefile Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/mksample/nio/Makefile Wed Jul 05 16:41:30 2017 +0200 @@ -31,7 +31,7 @@ PRODUCT = java include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = server +SUBDIRS = multicast server all build clean clobber:: $(SUBDIRS-loop) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/mksample/nio/multicast/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/mksample/nio/multicast/Makefile Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,52 @@ +# +# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Makefile for the nio/multicast sample code +# + +BUILDDIR = ../../.. + +PRODUCT = java + +include $(BUILDDIR)/common/Defs.gmk + +SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/multicast +SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/multicast + +SAMPLE_FILES = \ + $(SAMPLE_DST_DIR)/Reader.java \ + $(SAMPLE_DST_DIR)/Sender.java \ + $(SAMPLE_DST_DIR)/MulticastAddress.java + +all build: $(SAMPLE_FILES) + +$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/% + $(install-file) + +clean clobber: + $(RM) -r $(SAMPLE_DST_DIR) + +.PHONY: all build clean clobber diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/sun/awt/FILES_c_unix.gmk --- a/jdk/make/sun/awt/FILES_c_unix.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/sun/awt/FILES_c_unix.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -142,59 +142,59 @@ # These files rely on motif to be built, and should not be included # in a headless build. -FILES_MOTIF_c = \ - awt_AWTEvent.c \ - awt_Button.c \ - awt_Canvas.c \ - awt_Checkbox.c \ - awt_Component.c \ - awt_Cursor.c \ - awt_DataTransferer.c \ - awt_DrawingSurface.c \ - awt_Event.c \ - awt_FileDialog.c \ - awt_GlobalCursorManager.c \ - awt_GraphicsEnv.c \ - awt_InputMethod.c \ - awt_Insets.c \ - awt_KeyboardFocusManager.c \ - awt_Label.c \ - awt_List.c \ - awt_Menu.c \ - awt_MenuBar.c \ - awt_MenuComponent.c \ - awt_MenuItem.c \ - awt_motif.c \ - awt_Plugin.c \ - awt_PopupMenu.c \ - awt_Robot.c \ - awt_Scrollbar.c \ - awt_ScrollPane.c \ - awt_Selection.c \ - awt_UNIXToolkit.c \ - awt_TextArea.c \ - awt_TextField.c \ - awt_TopLevel.c \ - awt_mgrsel.c \ - awt_util.c \ - awt_wm.c \ - awt_XmDnD.c \ - awt_dnd.c \ - awt_dnd_ds.c \ - awt_dnd_dt.c \ - canvas.c \ - cursor.c \ - multi_font.c \ - robot_common.c \ - list.c \ - multiVis.c \ - XDrawingArea.c \ - MouseInfo.c \ - awt_xembed.c \ - awt_xembed_server.c \ - gtk2_interface.c \ - swing_GTKEngine.c \ - swing_GTKStyle.c +#FILES_MOTIF_c = \ +#keep awt_AWTEvent.c \ +# awt_Button.c \ +# awt_Canvas.c \ +# awt_Checkbox.c \ +#keep .h awt_Component.c \ +#keep .h awt_Cursor.c \ +# awt_DataTransferer.c \ +# awt_DrawingSurface.c \ +# awt_Event.c \ +# awt_FileDialog.c \ +# awt_GlobalCursorManager.c \ +# awt_GraphicsEnv.c \ +# awt_InputMethod.c \ +#keep awt_Insets.c \ +# awt_KeyboardFocusManager.c \ +# awt_Label.c \ +# awt_List.c \ +# awt_Menu.c \ +# awt_MenuBar.c \ +# awt_MenuComponent.c \ +# awt_MenuItem.c \ +# awt_motif.c \ +# awt_Plugin.c \ +# awt_PopupMenu.c \ +# awt_Robot.c \ +# awt_Scrollbar.c \ +# awt_ScrollPane.c \ +# awt_Selection.c \ +# awt_UNIXToolkit.c \ +# awt_TextArea.c \ +# awt_TextField.c \ +# awt_TopLevel.c \ +# awt_mgrsel.c \ +# awt_util.c \ +# awt_wm.c \ +# awt_XmDnD.c \ +# awt_dnd.c \ +# awt_dnd_ds.c \ +# awt_dnd_dt.c \ +# canvas.c \ +# cursor.c \ +# multi_font.c \ +# robot_common.c \ +# list.c \ +# multiVis.c \ +# XDrawingArea.c \ +# MouseInfo.c \ +# awt_xembed.c \ +# awt_xembed_server.c \ +# gtk2_interface.c \ +# swing_GTKEngine.c \ +# swing_GTKStyle.c # These files are required to be built, with or without motif. Some of diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/sun/awt/FILES_export_unix.gmk --- a/jdk/make/sun/awt/FILES_export_unix.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/sun/awt/FILES_export_unix.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -60,48 +60,15 @@ sun/awt/image/DataBufferNative.java \ \ sun/awt/motif/X11FontMetrics.java \ - sun/awt/motif/X11Clipboard.java \ - sun/awt/motif/X11Selection.java \ - sun/awt/motif/X11SelectionHolder.java \ sun/awt/X11InputMethod.java \ - sun/awt/motif/MInputMethod.java \ - sun/awt/motif/MInputMethodControl.java \ - sun/awt/motif/MCustomCursor.java \ sun/awt/motif/MFontConfiguration.java \ sun/awt/motif/MFontPeer.java \ sun/awt/motif/MToolkit.java \ - sun/awt/motif/MComponentPeer.java \ - sun/awt/motif/MButtonPeer.java \ - sun/awt/motif/MCanvasPeer.java \ - sun/awt/motif/MCheckboxPeer.java \ - sun/awt/motif/MFileDialogPeer.java \ - sun/awt/motif/MGlobalCursorManager.java \ - sun/awt/motif/MTextFieldPeer.java \ - sun/awt/motif/MLabelPeer.java \ - sun/awt/motif/MListPeer.java \ - sun/awt/motif/MWindowPeer.java \ - sun/awt/motif/MMenuBarPeer.java \ - sun/awt/motif/MMenuPeer.java \ - sun/awt/motif/MPopupMenuPeer.java \ - sun/awt/motif/MDialogPeer.java \ - sun/awt/motif/MMenuItemPeer.java \ - sun/awt/motif/MCheckboxMenuItemPeer.java \ - sun/awt/motif/MChoicePeer.java \ - sun/awt/motif/MTextAreaPeer.java \ - sun/awt/motif/MScrollbarPeer.java \ - sun/awt/motif/MScrollPanePeer.java \ - sun/awt/motif/MFramePeer.java \ sun/awt/DebugSettings.java \ sun/awt/EmbeddedFrame.java \ - sun/awt/motif/MEmbeddedFramePeer.java \ sun/awt/PlatformFont.java \ sun/awt/FontDescriptor.java \ sun/awt/NativeLibLoader.java \ - sun/awt/motif/MDropTargetContextPeer.java \ - sun/awt/motif/MDragSourceContextPeer.java \ - sun/awt/motif/MRobotPeer.java \ - sun/awt/motif/X11DragSourceContextPeer.java \ - sun/awt/motif/X11DropTargetContextPeer.java \ sun/awt/X11GraphicsEnvironment.java \ sun/awt/X11GraphicsDevice.java \ sun/awt/X11GraphicsConfig.java \ @@ -124,7 +91,6 @@ sun/java2d/cmm/ColorTransform.java \ sun/awt/datatransfer/DataTransferer.java \ sun/awt/dnd/SunDragSourceContextPeer.java \ - sun/awt/motif/MDataTransferer.java \ sun/awt/motif/MToolkitThreadBlockedHandler.java \ sun/java2d/opengl/OGLBlitLoops.java \ sun/java2d/opengl/OGLContext.java \ @@ -220,6 +186,5 @@ java/awt/event/NativeLibLoader.java \ java/awt/peer/ComponentPeer.java \ java/awt/dnd/DnDConstants.java \ - sun/awt/CausedFocusEvent.java \ - sun/awt/motif/MEmbedCanvasPeer.java + sun/awt/CausedFocusEvent.java diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/sun/awt/mapfile-mawt-vers --- a/jdk/make/sun/awt/mapfile-mawt-vers Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/sun/awt/mapfile-mawt-vers Wed Jul 05 16:41:30 2017 +0200 @@ -31,7 +31,7 @@ global: JNI_OnLoad; - Java_sun_awt_motif_MComponentPeer_restoreFocus; + #Java_sun_awt_motif_MComponentPeer_restoreFocus; Java_sun_awt_DefaultMouseInfoPeer_fillPointWithCoords; Java_sun_awt_DefaultMouseInfoPeer_isWindowUnderMouse; Java_java_awt_AWTEvent_nativeSetSource; @@ -56,163 +56,163 @@ Java_sun_awt_UNIXToolkit_load_1stock_1icon; Java_sun_awt_UNIXToolkit_load_1gtk_1icon; Java_sun_awt_UNIXToolkit_nativeSync; - Java_sun_awt_motif_MButtonPeer_create; - Java_sun_awt_motif_MButtonPeer_setLabel; - Java_sun_awt_motif_MPanelPeer_pEnsureIndex; - Java_sun_awt_motif_MPanelPeer_pRestack; - Java_sun_awt_motif_MCanvasPeer_create; - Java_sun_awt_motif_MCanvasPeer_initIDs; - Java_sun_awt_motif_MCanvasPeer_resetTargetGC; - Java_sun_awt_motif_MCheckboxMenuItemPeer_pSetState; - Java_sun_awt_motif_MCheckboxPeer_create; - Java_sun_awt_motif_MCheckboxPeer_setCheckboxGroup; - Java_sun_awt_motif_MCheckboxPeer_setLabel; - Java_sun_awt_motif_MCheckboxPeer_pSetState; - Java_sun_awt_motif_MCheckboxPeer_pGetState; - Java_sun_awt_motif_MChoicePeer_addItem; - Java_sun_awt_motif_MChoicePeer_appendItems; - Java_sun_awt_motif_MChoicePeer_create; - Java_sun_awt_motif_MChoicePeer_pReshape; - Java_sun_awt_motif_MChoicePeer_remove; - Java_sun_awt_motif_MChoicePeer_removeAll; - Java_sun_awt_motif_MChoicePeer_setBackground; - Java_sun_awt_motif_MChoicePeer_pSelect; - Java_sun_awt_motif_MChoicePeer_setFont; - Java_sun_awt_motif_MChoicePeer_setForeground; - Java_sun_awt_motif_MComponentPeer_addNativeDropTarget; - Java_sun_awt_motif_MComponentPeer_getNativeColor; - Java_sun_awt_motif_MComponentPeer_getWindow; - Java_sun_awt_motif_MComponentPeer_pDisable; - Java_sun_awt_motif_MComponentPeer_pDispose; - Java_sun_awt_motif_MComponentPeer_pEnable; - Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen; - Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen2; - Java_sun_awt_motif_MComponentPeer_pHide; - Java_sun_awt_motif_MComponentPeer_pInitialize; - Java_sun_awt_motif_MComponentPeer_pMakeCursorVisible; - Java_sun_awt_motif_MComponentPeer_pReshape; - Java_sun_awt_motif_MComponentPeer_pShow; - Java_sun_awt_motif_MComponentPeer_removeNativeDropTarget; - Java_sun_awt_motif_MComponentPeer_pSetBackground; - Java_sun_awt_motif_MComponentPeer_pSetFont; - Java_sun_awt_motif_MComponentPeer_processSynchronousLightweightTransfer; - Java_sun_awt_motif_MComponentPeer__1requestFocus; - Java_sun_awt_motif_MComponentPeer_getNativeFocusedWindow; - Java_sun_awt_motif_MCheckboxMenuItemPeer_getState; - Java_sun_awt_motif_MComponentPeer_pSetForeground; - Java_sun_awt_motif_MDragSourceContextPeer_startDrag; - Java_sun_awt_motif_MDragSourceContextPeer_setNativeCursor; - Java_sun_awt_motif_MDropTargetContextPeer_addTransfer; - Java_sun_awt_motif_MDropTargetContextPeer_dropDone; - Java_sun_awt_motif_MDropTargetContextPeer_startTransfer; - Java_sun_awt_motif_X11DragSourceContextPeer_startDrag; - Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor; - Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse; - Java_sun_awt_motif_X11DropTargetContextPeer_dropDone; - Java_sun_awt_motif_X11DropTargetContextPeer_getData; - Java_sun_awt_motif_MEmbeddedFramePeer_NEFcreate; - Java_sun_awt_motif_MEmbeddedFramePeer_pShowImpl; - Java_sun_awt_motif_MEmbeddedFramePeer_requestXEmbedFocus; - Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedApplicationActive; - Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedActive; - Java_sun_awt_motif_MEmbeddedFramePeer_synthesizeFocusInOut; - Java_sun_awt_motif_MEmbeddedFramePeer_pReshapePrivate; - Java_sun_awt_motif_MEmbeddedFramePeer_getBoundsPrivate; - Java_sun_awt_motif_MEmbeddedFrame_getWidget; - Java_sun_awt_motif_MEmbeddedFrame_mapWidget; - Java_sun_awt_motif_MEmbedCanvasPeer_forwardEventToEmbedded; - Java_sun_awt_motif_MFramePeer_pSetIconImage___3B_3I_3SII; - Java_sun_awt_motif_MFileDialogPeer_create; - Java_sun_awt_motif_MFileDialogPeer_pDispose; - Java_sun_awt_motif_MFileDialogPeer_pHide; - Java_sun_awt_motif_MFileDialogPeer_pReshape; - Java_sun_awt_motif_MFileDialogPeer_pShow; - Java_sun_awt_motif_MFileDialogPeer_setFileEntry; - Java_sun_awt_motif_MFileDialogPeer_setFont; - Java_sun_awt_motif_MFramePeer_pGetIconSize; - Java_sun_awt_motif_MGlobalCursorManager_cacheInit; - Java_sun_awt_motif_MGlobalCursorManager_findComponentAt; - Java_sun_awt_motif_MGlobalCursorManager_findHeavyweightUnderCursor; - Java_sun_awt_motif_MGlobalCursorManager_getCursorPos; - Java_sun_awt_motif_MGlobalCursorManager_getLocationOnScreen; - Java_sun_awt_motif_MLabelPeer_create; - Java_sun_awt_motif_MLabelPeer_setAlignment; - Java_sun_awt_motif_MLabelPeer_setText; - Java_sun_awt_motif_MListPeer_addItem; - Java_sun_awt_motif_MListPeer_create; - Java_sun_awt_motif_MListPeer_delItems; - Java_sun_awt_motif_MListPeer_deselect; - Java_sun_awt_motif_MListPeer_isSelected; - Java_sun_awt_motif_MListPeer_makeVisible; - Java_sun_awt_motif_MListPeer_nativeHandleMouseWheel; - Java_sun_awt_motif_MListPeer_select; - Java_sun_awt_motif_MListPeer_setMultipleSelections; - Java_sun_awt_motif_MMenuBarPeer_create; - Java_sun_awt_motif_MMenuItemPeer_createMenuItem; - Java_sun_awt_motif_MMenuItemPeer_pDisable; - Java_sun_awt_motif_MMenuItemPeer_pDispose; - Java_sun_awt_motif_MMenuItemPeer_pEnable; - Java_sun_awt_motif_MMenuItemPeer_pSetLabel; - Java_sun_awt_motif_MMenuPeer_createMenu; - Java_sun_awt_motif_MMenuPeer_createSubMenu; - Java_sun_awt_motif_MMenuPeer_pDispose; - Java_sun_awt_motif_MPopupMenuPeer_createMenu; - Java_sun_awt_motif_MPopupMenuPeer_pDispose; - Java_sun_awt_motif_MPopupMenuPeer_pShow; - Java_sun_awt_motif_MRobotPeer_getRGBPixelsImpl; - Java_sun_awt_motif_MRobotPeer_keyPressImpl; - Java_sun_awt_motif_MRobotPeer_keyReleaseImpl; - Java_sun_awt_motif_MRobotPeer_mouseMoveImpl; - Java_sun_awt_motif_MRobotPeer_mousePressImpl; - Java_sun_awt_motif_MRobotPeer_mouseReleaseImpl; - Java_sun_awt_motif_MRobotPeer_mouseWheelImpl; - Java_sun_awt_motif_MRobotPeer_setup; - Java_sun_awt_motif_MScrollbarPeer_create; - Java_sun_awt_motif_MScrollbarPeer_setLineIncrement; - Java_sun_awt_motif_MScrollbarPeer_setPageIncrement; - Java_sun_awt_motif_MScrollbarPeer_pSetValues; - Java_sun_awt_motif_MScrollPanePeer_create; - Java_sun_awt_motif_MScrollPanePeer_pGetBlockIncrement; - Java_sun_awt_motif_MScrollPanePeer_pGetScrollbarSpace; - Java_sun_awt_motif_MScrollPanePeer_pGetShadow; - Java_sun_awt_motif_MScrollPanePeer_pInsets; - Java_sun_awt_motif_MScrollPanePeer_pSetIncrement; - Java_sun_awt_motif_MScrollPanePeer_pSetScrollChild; - Java_sun_awt_motif_MScrollPanePeer_setScrollPosition; - Java_sun_awt_motif_MScrollPanePeer_setTypedValue; - Java_sun_awt_motif_MTextAreaPeer_initIDs; - Java_sun_awt_motif_MTextAreaPeer_pCreate; - Java_sun_awt_motif_MTextAreaPeer_getCaretPosition; - Java_sun_awt_motif_MTextAreaPeer_getExtraHeight; - Java_sun_awt_motif_MTextAreaPeer_getExtraWidth; - Java_sun_awt_motif_MTextAreaPeer_getSelectionEnd; - Java_sun_awt_motif_MTextAreaPeer_getSelectionStart; - Java_sun_awt_motif_MTextAreaPeer_getText; - Java_sun_awt_motif_MTextAreaPeer_insert; - Java_sun_awt_motif_MTextAreaPeer_nativeHandleMouseWheel; - Java_sun_awt_motif_MTextAreaPeer_pMakeCursorVisible; - Java_sun_awt_motif_MTextAreaPeer_pSetEditable; - Java_sun_awt_motif_MTextAreaPeer_pShow2; - Java_sun_awt_motif_MTextAreaPeer_replaceRange; - Java_sun_awt_motif_MTextAreaPeer_select; - Java_sun_awt_motif_MTextAreaPeer_setCaretPosition; - Java_sun_awt_motif_MTextAreaPeer_setFont; - Java_sun_awt_motif_MTextAreaPeer_setText; - Java_sun_awt_motif_MTextAreaPeer_setTextBackground; - Java_sun_awt_motif_MTextFieldPeer_initIDs; - Java_sun_awt_motif_MTextFieldPeer_pCreate; - Java_sun_awt_motif_MTextFieldPeer_getCaretPosition; - Java_sun_awt_motif_MTextFieldPeer_getSelectionEnd; - Java_sun_awt_motif_MTextFieldPeer_getSelectionStart; - Java_sun_awt_motif_MTextFieldPeer_getText; - Java_sun_awt_motif_MTextFieldPeer_insertReplaceText; - Java_sun_awt_motif_MTextFieldPeer_preDispose; - Java_sun_awt_motif_MTextFieldPeer_pSetEditable; - Java_sun_awt_motif_MTextFieldPeer_select; - Java_sun_awt_motif_MTextFieldPeer_setCaretPosition; - Java_sun_awt_motif_MTextFieldPeer_setEchoChar; - Java_sun_awt_motif_MTextFieldPeer_setFont; - Java_sun_awt_motif_MTextFieldPeer_setText; + #Java_sun_awt_motif_MButtonPeer_create; + #Java_sun_awt_motif_MButtonPeer_setLabel; + #Java_sun_awt_motif_MPanelPeer_pEnsureIndex; + #Java_sun_awt_motif_MPanelPeer_pRestack; + #Java_sun_awt_motif_MCanvasPeer_create; + #Java_sun_awt_motif_MCanvasPeer_initIDs; + #Java_sun_awt_motif_MCanvasPeer_resetTargetGC; + #Java_sun_awt_motif_MCheckboxMenuItemPeer_pSetState; + #Java_sun_awt_motif_MCheckboxPeer_create; + #Java_sun_awt_motif_MCheckboxPeer_setCheckboxGroup; + #Java_sun_awt_motif_MCheckboxPeer_setLabel; + #Java_sun_awt_motif_MCheckboxPeer_pSetState; + #Java_sun_awt_motif_MCheckboxPeer_pGetState; + #Java_sun_awt_motif_MChoicePeer_addItem; + #Java_sun_awt_motif_MChoicePeer_appendItems; + #Java_sun_awt_motif_MChoicePeer_create; + #Java_sun_awt_motif_MChoicePeer_pReshape; + #Java_sun_awt_motif_MChoicePeer_remove; + #Java_sun_awt_motif_MChoicePeer_removeAll; + #Java_sun_awt_motif_MChoicePeer_setBackground; + #Java_sun_awt_motif_MChoicePeer_pSelect; + #Java_sun_awt_motif_MChoicePeer_setFont; + #Java_sun_awt_motif_MChoicePeer_setForeground; + #Java_sun_awt_motif_MComponentPeer_addNativeDropTarget; + #Java_sun_awt_motif_MComponentPeer_getNativeColor; + #Java_sun_awt_motif_MComponentPeer_getWindow; + #Java_sun_awt_motif_MComponentPeer_pDisable; + #Java_sun_awt_motif_MComponentPeer_pDispose; + #Java_sun_awt_motif_MComponentPeer_pEnable; + #Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen; + #Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen2; + #Java_sun_awt_motif_MComponentPeer_pHide; + #Java_sun_awt_motif_MComponentPeer_pInitialize; + #Java_sun_awt_motif_MComponentPeer_pMakeCursorVisible; + #Java_sun_awt_motif_MComponentPeer_pReshape; + #Java_sun_awt_motif_MComponentPeer_pShow; + #Java_sun_awt_motif_MComponentPeer_removeNativeDropTarget; + #Java_sun_awt_motif_MComponentPeer_pSetBackground; + #Java_sun_awt_motif_MComponentPeer_pSetFont; + #Java_sun_awt_motif_MComponentPeer_processSynchronousLightweightTransfer; + #Java_sun_awt_motif_MComponentPeer__1requestFocus; + #Java_sun_awt_motif_MComponentPeer_getNativeFocusedWindow; + #Java_sun_awt_motif_MCheckboxMenuItemPeer_getState; + #Java_sun_awt_motif_MComponentPeer_pSetForeground; + #Java_sun_awt_motif_MDragSourceContextPeer_startDrag; + #Java_sun_awt_motif_MDragSourceContextPeer_setNativeCursor; + #Java_sun_awt_motif_MDropTargetContextPeer_addTransfer; + #Java_sun_awt_motif_MDropTargetContextPeer_dropDone; + #Java_sun_awt_motif_MDropTargetContextPeer_startTransfer; + #Java_sun_awt_motif_X11DragSourceContextPeer_startDrag; + #Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor; + #Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse; + #Java_sun_awt_motif_X11DropTargetContextPeer_dropDone; + #Java_sun_awt_motif_X11DropTargetContextPeer_getData; + #Java_sun_awt_motif_MEmbeddedFramePeer_NEFcreate; + #Java_sun_awt_motif_MEmbeddedFramePeer_pShowImpl; + #Java_sun_awt_motif_MEmbeddedFramePeer_requestXEmbedFocus; + #Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedApplicationActive; + #Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedActive; + #Java_sun_awt_motif_MEmbeddedFramePeer_synthesizeFocusInOut; + #Java_sun_awt_motif_MEmbeddedFramePeer_pReshapePrivate; + #Java_sun_awt_motif_MEmbeddedFramePeer_getBoundsPrivate; + #Java_sun_awt_motif_MEmbeddedFrame_getWidget; + #Java_sun_awt_motif_MEmbeddedFrame_mapWidget; + #Java_sun_awt_motif_MEmbedCanvasPeer_forwardEventToEmbedded; + #Java_sun_awt_motif_MFramePeer_pSetIconImage___3B_3I_3SII; + #Java_sun_awt_motif_MFileDialogPeer_create; + #Java_sun_awt_motif_MFileDialogPeer_pDispose; + #Java_sun_awt_motif_MFileDialogPeer_pHide; + #Java_sun_awt_motif_MFileDialogPeer_pReshape; + #Java_sun_awt_motif_MFileDialogPeer_pShow; + #Java_sun_awt_motif_MFileDialogPeer_setFileEntry; + #Java_sun_awt_motif_MFileDialogPeer_setFont; + #Java_sun_awt_motif_MFramePeer_pGetIconSize; + #Java_sun_awt_motif_MGlobalCursorManager_cacheInit; + #Java_sun_awt_motif_MGlobalCursorManager_findComponentAt; + #Java_sun_awt_motif_MGlobalCursorManager_findHeavyweightUnderCursor; + #Java_sun_awt_motif_MGlobalCursorManager_getCursorPos; + #Java_sun_awt_motif_MGlobalCursorManager_getLocationOnScreen; + #Java_sun_awt_motif_MLabelPeer_create; + #Java_sun_awt_motif_MLabelPeer_setAlignment; + #Java_sun_awt_motif_MLabelPeer_setText; + #Java_sun_awt_motif_MListPeer_addItem; + #Java_sun_awt_motif_MListPeer_create; + #Java_sun_awt_motif_MListPeer_delItems; + #Java_sun_awt_motif_MListPeer_deselect; + #Java_sun_awt_motif_MListPeer_isSelected; + #Java_sun_awt_motif_MListPeer_makeVisible; + #Java_sun_awt_motif_MListPeer_nativeHandleMouseWheel; + #Java_sun_awt_motif_MListPeer_select; + #Java_sun_awt_motif_MListPeer_setMultipleSelections; + #Java_sun_awt_motif_MMenuBarPeer_create; + #Java_sun_awt_motif_MMenuItemPeer_createMenuItem; + #Java_sun_awt_motif_MMenuItemPeer_pDisable; + #Java_sun_awt_motif_MMenuItemPeer_pDispose; + #Java_sun_awt_motif_MMenuItemPeer_pEnable; + #Java_sun_awt_motif_MMenuItemPeer_pSetLabel; + #Java_sun_awt_motif_MMenuPeer_createMenu; + #Java_sun_awt_motif_MMenuPeer_createSubMenu; + #Java_sun_awt_motif_MMenuPeer_pDispose; + #Java_sun_awt_motif_MPopupMenuPeer_createMenu; + #Java_sun_awt_motif_MPopupMenuPeer_pDispose; + #Java_sun_awt_motif_MPopupMenuPeer_pShow; + #Java_sun_awt_motif_MRobotPeer_getRGBPixelsImpl; + #Java_sun_awt_motif_MRobotPeer_keyPressImpl; + #Java_sun_awt_motif_MRobotPeer_keyReleaseImpl; + #Java_sun_awt_motif_MRobotPeer_mouseMoveImpl; + #Java_sun_awt_motif_MRobotPeer_mousePressImpl; + #Java_sun_awt_motif_MRobotPeer_mouseReleaseImpl; + #Java_sun_awt_motif_MRobotPeer_mouseWheelImpl; + #Java_sun_awt_motif_MRobotPeer_setup; + #Java_sun_awt_motif_MScrollbarPeer_create; + #Java_sun_awt_motif_MScrollbarPeer_setLineIncrement; + #Java_sun_awt_motif_MScrollbarPeer_setPageIncrement; + #Java_sun_awt_motif_MScrollbarPeer_pSetValues; + #Java_sun_awt_motif_MScrollPanePeer_create; + #Java_sun_awt_motif_MScrollPanePeer_pGetBlockIncrement; + #Java_sun_awt_motif_MScrollPanePeer_pGetScrollbarSpace; + #Java_sun_awt_motif_MScrollPanePeer_pGetShadow; + #Java_sun_awt_motif_MScrollPanePeer_pInsets; + #Java_sun_awt_motif_MScrollPanePeer_pSetIncrement; + #Java_sun_awt_motif_MScrollPanePeer_pSetScrollChild; + #Java_sun_awt_motif_MScrollPanePeer_setScrollPosition; + #Java_sun_awt_motif_MScrollPanePeer_setTypedValue; + #Java_sun_awt_motif_MTextAreaPeer_initIDs; + #Java_sun_awt_motif_MTextAreaPeer_pCreate; + #Java_sun_awt_motif_MTextAreaPeer_getCaretPosition; + #Java_sun_awt_motif_MTextAreaPeer_getExtraHeight; + #Java_sun_awt_motif_MTextAreaPeer_getExtraWidth; + #Java_sun_awt_motif_MTextAreaPeer_getSelectionEnd; + #Java_sun_awt_motif_MTextAreaPeer_getSelectionStart; + #Java_sun_awt_motif_MTextAreaPeer_getText; + #Java_sun_awt_motif_MTextAreaPeer_insert; + #Java_sun_awt_motif_MTextAreaPeer_nativeHandleMouseWheel; + #Java_sun_awt_motif_MTextAreaPeer_pMakeCursorVisible; + #Java_sun_awt_motif_MTextAreaPeer_pSetEditable; + #Java_sun_awt_motif_MTextAreaPeer_pShow2; + #Java_sun_awt_motif_MTextAreaPeer_replaceRange; + #Java_sun_awt_motif_MTextAreaPeer_select; + #Java_sun_awt_motif_MTextAreaPeer_setCaretPosition; + #Java_sun_awt_motif_MTextAreaPeer_setFont; + #Java_sun_awt_motif_MTextAreaPeer_setText; + #Java_sun_awt_motif_MTextAreaPeer_setTextBackground; + #Java_sun_awt_motif_MTextFieldPeer_initIDs; + #Java_sun_awt_motif_MTextFieldPeer_pCreate; + #Java_sun_awt_motif_MTextFieldPeer_getCaretPosition; + #Java_sun_awt_motif_MTextFieldPeer_getSelectionEnd; + #Java_sun_awt_motif_MTextFieldPeer_getSelectionStart; + #Java_sun_awt_motif_MTextFieldPeer_getText; + #Java_sun_awt_motif_MTextFieldPeer_insertReplaceText; + #Java_sun_awt_motif_MTextFieldPeer_preDispose; + #Java_sun_awt_motif_MTextFieldPeer_pSetEditable; + #Java_sun_awt_motif_MTextFieldPeer_select; + #Java_sun_awt_motif_MTextFieldPeer_setCaretPosition; + #Java_sun_awt_motif_MTextFieldPeer_setEchoChar; + #Java_sun_awt_motif_MTextFieldPeer_setFont; + #Java_sun_awt_motif_MTextFieldPeer_setText; Java_sun_awt_motif_MToolkit_beep; Java_sun_awt_motif_MToolkit_getLockingKeyStateNative; Java_sun_awt_motif_MToolkit_getMulticlickTime; @@ -236,30 +236,30 @@ Java_sun_awt_motif_MToolkit_nativeGrab; Java_sun_awt_motif_MToolkit_getWMName; Java_sun_awt_motif_MWindowAttributes_initIDs; - Java_sun_awt_motif_MWindowPeer_pDispose; - Java_sun_awt_motif_MWindowPeer_pHide; - Java_sun_awt_motif_MWindowPeer_pReshape; - Java_sun_awt_motif_MWindowPeer_pSetTitle; - Java_sun_awt_motif_MWindowPeer_pShow; - Java_sun_awt_motif_MWindowPeer_setResizable; - Java_sun_awt_motif_MWindowPeer_toBack; - Java_sun_awt_motif_MWindowPeer_addTextComponentNative; - Java_sun_awt_motif_MWindowPeer_getState; - Java_sun_awt_motif_MWindowPeer_pSetIMMOption; - Java_sun_awt_motif_MWindowPeer_pSetMenuBar; - Java_sun_awt_motif_MWindowPeer_pShowModal; - Java_sun_awt_motif_MWindowPeer_removeTextComponentNative; - Java_sun_awt_motif_MWindowPeer_setSaveUnder; - Java_sun_awt_motif_MWindowPeer_setState; - Java_sun_awt_motif_MWindowPeer_resetTargetGC; - Java_sun_awt_motif_MWindowPeer_registerX11DropTarget; - Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget; - Java_sun_awt_motif_MWindowPeer_updateAlwaysOnTop; - Java_sun_awt_motif_MWindowPeer_setFocusableWindow; - Java_sun_awt_motif_MWindowPeer_pToFront; - Java_sun_awt_motif_MCustomCursor_cacheInit; - Java_sun_awt_motif_MCustomCursor_createCursor; - Java_sun_awt_motif_MCustomCursor_queryBestCursor; + #Java_sun_awt_motif_MWindowPeer_pDispose; + #Java_sun_awt_motif_MWindowPeer_pHide; + #Java_sun_awt_motif_MWindowPeer_pReshape; + #Java_sun_awt_motif_MWindowPeer_pSetTitle; + #Java_sun_awt_motif_MWindowPeer_pShow; + #Java_sun_awt_motif_MWindowPeer_setResizable; + #Java_sun_awt_motif_MWindowPeer_toBack; + #Java_sun_awt_motif_MWindowPeer_addTextComponentNative; + #Java_sun_awt_motif_MWindowPeer_getState; + #Java_sun_awt_motif_MWindowPeer_pSetIMMOption; + #Java_sun_awt_motif_MWindowPeer_pSetMenuBar; + #Java_sun_awt_motif_MWindowPeer_pShowModal; + #Java_sun_awt_motif_MWindowPeer_removeTextComponentNative; + #Java_sun_awt_motif_MWindowPeer_setSaveUnder; + #Java_sun_awt_motif_MWindowPeer_setState; + #Java_sun_awt_motif_MWindowPeer_resetTargetGC; + #Java_sun_awt_motif_MWindowPeer_registerX11DropTarget; + #Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget; + #Java_sun_awt_motif_MWindowPeer_updateAlwaysOnTop; + #Java_sun_awt_motif_MWindowPeer_setFocusableWindow; + #Java_sun_awt_motif_MWindowPeer_pToFront; + #Java_sun_awt_motif_MCustomCursor_cacheInit; + #Java_sun_awt_motif_MCustomCursor_createCursor; + #Java_sun_awt_motif_MCustomCursor_queryBestCursor; Java_sun_awt_motif_X11FontMetrics_bytesWidth; Java_sun_awt_motif_X11FontMetrics_getMFCharsWidth; Java_sun_awt_motif_X11FontMetrics_init; @@ -268,18 +268,18 @@ Java_sun_awt_X11InputMethod_resetXIC; Java_sun_awt_X11InputMethod_setCompositionEnabledNative; Java_sun_awt_X11InputMethod_turnoffStatusWindow; - Java_sun_awt_motif_MInputMethod_openXIMNative; - Java_sun_awt_motif_MInputMethod_configureStatusAreaNative; - Java_sun_awt_motif_MInputMethod_createXICNative; - Java_sun_awt_motif_MInputMethod_reconfigureXICNative; - Java_sun_awt_motif_MInputMethod_setXICFocusNative; - Java_sun_awt_motif_X11Clipboard_getClipboardData; - Java_sun_awt_motif_X11Clipboard_getClipboardFormats; - Java_sun_awt_motif_X11Clipboard_registerClipboardViewer; - Java_sun_awt_motif_X11Clipboard_unregisterClipboardViewer; - Java_sun_awt_motif_X11Selection_init; - Java_sun_awt_motif_X11Selection_pGetSelectionOwnership; - Java_sun_awt_motif_X11Selection_clearNativeContext; + #Java_sun_awt_motif_MInputMethod_openXIMNative; + #Java_sun_awt_motif_MInputMethod_configureStatusAreaNative; + #Java_sun_awt_motif_MInputMethod_createXICNative; + #Java_sun_awt_motif_MInputMethod_reconfigureXICNative; + #Java_sun_awt_motif_MInputMethod_setXICFocusNative; + #Java_sun_awt_motif_X11Clipboard_getClipboardData; + #Java_sun_awt_motif_X11Clipboard_getClipboardFormats; + #Java_sun_awt_motif_X11Clipboard_registerClipboardViewer; + #Java_sun_awt_motif_X11Clipboard_unregisterClipboardViewer; + #Java_sun_awt_motif_X11Selection_init; + #Java_sun_awt_motif_X11Selection_pGetSelectionOwnership; + #Java_sun_awt_motif_X11Selection_clearNativeContext; Java_sun_awt_SunToolkit_closeSplashScreen; Java_sun_awt_PlatformFont_initIDs; Java_sun_awt_X11GraphicsConfig_init; @@ -311,25 +311,25 @@ Java_sun_awt_X11GraphicsEnvironment_initGLX; Java_sun_awt_X11GraphicsEnvironment_pRunningXinerama; Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint; - Java_sun_awt_motif_MEmbedCanvasPeer_initXEmbedServer; - Java_sun_awt_motif_MEmbedCanvasPeer_destroyXEmbedServer; - Java_sun_awt_motif_MEmbedCanvasPeer_isXEmbedActive; - Java_sun_awt_motif_MEmbedCanvasPeer_initDispatching; - Java_sun_awt_motif_MEmbedCanvasPeer_endDispatching; - Java_sun_awt_motif_MEmbedCanvasPeer_embedChild; - Java_sun_awt_motif_MEmbedCanvasPeer_childDestroyed; - Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedPreferredSize; - Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedMinimumSize; - Java_sun_awt_motif_MEmbedCanvasPeer_getClientBounds; - Java_sun_awt_motif_MEmbedCanvasPeer_notifyChildEmbedded; - Java_sun_awt_motif_MEmbedCanvasPeer_detachChild; - Java_sun_awt_motif_MEmbedCanvasPeer_forwardKeyEvent; - Java_sun_awt_motif_MEmbedCanvasPeer_getAWTKeyCodeForKeySym; - Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__I; - Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__IJJJ; - Java_sun_awt_motif_MEmbedCanvasPeer_getWindow; - Java_sun_awt_motif_GrabbedKey_initKeySymAndModifiers; - Java_sun_awt_motif_MEmbeddedFramePeer_traverseOut; + #Java_sun_awt_motif_MEmbedCanvasPeer_initXEmbedServer; + #Java_sun_awt_motif_MEmbedCanvasPeer_destroyXEmbedServer; + #Java_sun_awt_motif_MEmbedCanvasPeer_isXEmbedActive; + #Java_sun_awt_motif_MEmbedCanvasPeer_initDispatching; + #Java_sun_awt_motif_MEmbedCanvasPeer_endDispatching; + #Java_sun_awt_motif_MEmbedCanvasPeer_embedChild; + #Java_sun_awt_motif_MEmbedCanvasPeer_childDestroyed; + #Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedPreferredSize; + #Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedMinimumSize; + #Java_sun_awt_motif_MEmbedCanvasPeer_getClientBounds; + #Java_sun_awt_motif_MEmbedCanvasPeer_notifyChildEmbedded; + #Java_sun_awt_motif_MEmbedCanvasPeer_detachChild; + #Java_sun_awt_motif_MEmbedCanvasPeer_forwardKeyEvent; + #Java_sun_awt_motif_MEmbedCanvasPeer_getAWTKeyCodeForKeySym; + #Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__I; + #Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__IJJJ; + #Java_sun_awt_motif_MEmbedCanvasPeer_getWindow; + #Java_sun_awt_motif_GrabbedKey_initKeySymAndModifiers; + #Java_sun_awt_motif_MEmbeddedFramePeer_traverseOut; Java_java_awt_AWTEvent_initIDs; Java_java_awt_Button_initIDs; Java_java_awt_Container_initIDs; @@ -343,39 +343,39 @@ Java_java_awt_Insets_initIDs; Java_java_awt_TextField_initIDs; Java_java_awt_Window_initIDs; - Java_sun_awt_motif_MCheckboxPeer_getIndicatorSize; - Java_sun_awt_motif_MCheckboxPeer_getSpacing; - Java_sun_awt_motif_MChoicePeer_freeNativeData; - Java_sun_awt_motif_MComponentPeer_getComponents_1NoClientCode; - Java_sun_awt_motif_MComponentPeer_getParent_1NoClientCode; - Java_sun_awt_motif_MComponentPeer_initIDs; - Java_sun_awt_motif_MComponentPeer_nativeHandleEvent; - Java_sun_awt_motif_MComponentPeer_pSetCursor; - Java_sun_awt_motif_MComponentPeer_pSetInnerForeground; - Java_sun_awt_motif_MComponentPeer_pSetScrollbarBackground; - Java_sun_awt_motif_MComponentPeer_setTargetBackground; - Java_sun_awt_motif_MDataTransferer_dragQueryFile; - Java_sun_awt_motif_MDataTransferer_getAtomForTarget; - Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom; - Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText; + #Java_sun_awt_motif_MCheckboxPeer_getIndicatorSize; + #Java_sun_awt_motif_MCheckboxPeer_getSpacing; + #Java_sun_awt_motif_MChoicePeer_freeNativeData; + #Java_sun_awt_motif_MComponentPeer_getComponents_1NoClientCode; + #Java_sun_awt_motif_MComponentPeer_getParent_1NoClientCode; + #Java_sun_awt_motif_MComponentPeer_initIDs; + #Java_sun_awt_motif_MComponentPeer_nativeHandleEvent; + #Java_sun_awt_motif_MComponentPeer_pSetCursor; + #Java_sun_awt_motif_MComponentPeer_pSetInnerForeground; + #Java_sun_awt_motif_MComponentPeer_pSetScrollbarBackground; + #Java_sun_awt_motif_MComponentPeer_setTargetBackground; + #Java_sun_awt_motif_MDataTransferer_dragQueryFile; + #Java_sun_awt_motif_MDataTransferer_getAtomForTarget; + #Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom; + #Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText; Java_sun_awt_motif_MFontPeer_initIDs; - Java_sun_awt_motif_MListPeer_setBackground; - Java_sun_awt_motif_MMenuBarPeer_initIDs; - Java_sun_awt_motif_MMenuBarPeer_pDispose; - Java_sun_awt_motif_MMenuItemPeer_getParent_1NoClientCode; - Java_sun_awt_motif_MMenuItemPeer_initIDs; - Java_sun_awt_motif_MMenuItemPeer_pSetShortcut; - Java_sun_awt_motif_MPopupMenuPeer_initIDs; - Java_sun_awt_motif_MScrollbarPeer_initIDs; - Java_sun_awt_motif_MScrollPanePeer_initIDs; - Java_sun_awt_motif_MTextAreaPeer_pSetCursor; + #Java_sun_awt_motif_MListPeer_setBackground; + #Java_sun_awt_motif_MMenuBarPeer_initIDs; + #Java_sun_awt_motif_MMenuBarPeer_pDispose; + #Java_sun_awt_motif_MMenuItemPeer_getParent_1NoClientCode; + #Java_sun_awt_motif_MMenuItemPeer_initIDs; + #Java_sun_awt_motif_MMenuItemPeer_pSetShortcut; + #Java_sun_awt_motif_MPopupMenuPeer_initIDs; + #Java_sun_awt_motif_MScrollbarPeer_initIDs; + #Java_sun_awt_motif_MScrollPanePeer_initIDs; + #Java_sun_awt_motif_MTextAreaPeer_pSetCursor; Java_sun_awt_motif_MToolkit_shutdown; - Java_sun_awt_motif_MWindowPeer_initIDs; - Java_sun_awt_motif_MWindowPeer_pCreate; - Java_sun_awt_motif_MWindowPeer_wrapInSequenced; + #Java_sun_awt_motif_MWindowPeer_initIDs; + #Java_sun_awt_motif_MWindowPeer_pCreate; + #Java_sun_awt_motif_MWindowPeer_wrapInSequenced; Java_sun_awt_motif_X11FontMetrics_initIDs; - Java_sun_awt_X11InputMethod_initIDs; - Java_sun_awt_motif_X11Selection_initIDs; + #Java_sun_awt_X11InputMethod_initIDs; + #Java_sun_awt_motif_X11Selection_initIDs; Java_sun_awt_motif_MToolkitThreadBlockedHandler_enter; Java_sun_awt_motif_MToolkitThreadBlockedHandler_exit; Java_sun_awt_X11GraphicsConfig_init; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/sun/awt/mapfile-vers-linux --- a/jdk/make/sun/awt/mapfile-vers-linux Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/sun/awt/mapfile-vers-linux Wed Jul 05 16:41:30 2017 +0200 @@ -170,7 +170,7 @@ GrPrim_Sg2dGetPixel; GrPrim_Sg2dGetLCDTextContrast; - Java_sun_awt_motif_MComponentPeer_restoreFocus; + #Java_sun_awt_motif_MComponentPeer_restoreFocus; Java_sun_awt_DefaultMouseInfoPeer_fillPointWithCoords; Java_sun_awt_DefaultMouseInfoPeer_isWindowUnderMouse; Java_java_awt_AWTEvent_nativeSetSource; @@ -189,158 +189,158 @@ Java_java_awt_ScrollPane_initIDs; Java_java_awt_TextArea_initIDs; Java_sun_awt_FontDescriptor_initIDs; - Java_sun_awt_motif_MButtonPeer_create; - Java_sun_awt_motif_MButtonPeer_setLabel; - Java_sun_awt_motif_MCanvasPeer_create; - Java_sun_awt_motif_MCanvasPeer_initIDs; - Java_sun_awt_motif_MCanvasPeer_resetTargetGC; - Java_sun_awt_motif_MCheckboxMenuItemPeer_pSetState; - Java_sun_awt_motif_MCheckboxPeer_create; - Java_sun_awt_motif_MCheckboxPeer_setCheckboxGroup; - Java_sun_awt_motif_MCheckboxPeer_setLabel; - Java_sun_awt_motif_MCheckboxPeer_pSetState; - Java_sun_awt_motif_MCheckboxPeer_pGetState; - Java_sun_awt_motif_MChoicePeer_addItem; - Java_sun_awt_motif_MChoicePeer_appendItems; - Java_sun_awt_motif_MChoicePeer_create; - Java_sun_awt_motif_MChoicePeer_pReshape; - Java_sun_awt_motif_MChoicePeer_remove; - Java_sun_awt_motif_MChoicePeer_removeAll; - Java_sun_awt_motif_MChoicePeer_setBackground; - Java_sun_awt_motif_MChoicePeer_pSelect; - Java_sun_awt_motif_MChoicePeer_setFont; - Java_sun_awt_motif_MChoicePeer_setForeground; - Java_sun_awt_motif_MComponentPeer_addNativeDropTarget; - Java_sun_awt_motif_MComponentPeer_createBackBuffer; - Java_sun_awt_motif_MComponentPeer_destroyBackBuffer; - Java_sun_awt_motif_MComponentPeer_getNativeColor; - Java_sun_awt_motif_MComponentPeer_getWindow; - Java_sun_awt_motif_MComponentPeer_pDisable; - Java_sun_awt_motif_MComponentPeer_pDispose; - Java_sun_awt_motif_MComponentPeer_pEnable; - Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen; - Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen2; - Java_sun_awt_motif_MComponentPeer_pHide; - Java_sun_awt_motif_MComponentPeer_pInitialize; - Java_sun_awt_motif_MComponentPeer_pMakeCursorVisible; - Java_sun_awt_motif_MComponentPeer_pReshape; - Java_sun_awt_motif_MComponentPeer_pShow; - Java_sun_awt_motif_MComponentPeer_removeNativeDropTarget; - Java_sun_awt_motif_MComponentPeer_swapBuffers; - Java_sun_awt_motif_MComponentPeer_pSetBackground; - Java_sun_awt_motif_MComponentPeer_pSetFont; - Java_sun_awt_motif_MComponentPeer_processSynchronousLightweightTransfer; - Java_sun_awt_motif_MComponentPeer__1requestFocus; - Java_sun_awt_motif_MCheckboxMenuItemPeer_getState; - Java_sun_awt_motif_MComponentPeer_pSetForeground; - Java_sun_awt_motif_MDragSourceContextPeer_startDrag; - Java_sun_awt_motif_MDragSourceContextPeer_setNativeCursor; - Java_sun_awt_motif_MDropTargetContextPeer_addTransfer; - Java_sun_awt_motif_MDropTargetContextPeer_dropDone; - Java_sun_awt_motif_MDropTargetContextPeer_startTransfer; - Java_sun_awt_motif_X11DragSourceContextPeer_startDrag; - Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor; - Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse; - Java_sun_awt_motif_X11DropTargetContextPeer_dropDone; - Java_sun_awt_motif_X11DropTargetContextPeer_getData; - Java_sun_awt_motif_MEmbeddedFramePeer_NEFcreate; - Java_sun_awt_motif_MEmbeddedFramePeer_pShowImpl; - Java_sun_awt_motif_MEmbeddedFramePeer_pReshapePrivate; - Java_sun_awt_motif_MEmbeddedFramePeer_getBoundsPrivate; - Java_sun_awt_motif_MFramePeer_pSetIconImage___3B_3I_3SII; - Java_sun_awt_motif_MEmbeddedFramePeer_requestXEmbedFocus; - Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedApplicationActive; - Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedActive; - Java_sun_awt_motif_MEmbeddedFrame_getWidget; - Java_sun_awt_motif_MEmbeddedFrame_mapWidget; - Java_sun_awt_motif_MFileDialogPeer_create; - Java_sun_awt_motif_MFileDialogPeer_pDispose; - Java_sun_awt_motif_MFileDialogPeer_pHide; - Java_sun_awt_motif_MFileDialogPeer_pReshape; - Java_sun_awt_motif_MFileDialogPeer_pShow; - Java_sun_awt_motif_MFileDialogPeer_setFileEntry; - Java_sun_awt_motif_MFileDialogPeer_setFont; - Java_sun_awt_motif_MFramePeer_pGetIconSize; - Java_sun_awt_motif_MGlobalCursorManager_cacheInit; - Java_sun_awt_motif_MGlobalCursorManager_findComponentAt; - Java_sun_awt_motif_MGlobalCursorManager_findHeavyweightUnderCursor; - Java_sun_awt_motif_MGlobalCursorManager_getCursorPos; - Java_sun_awt_motif_MGlobalCursorManager_getLocationOnScreen; - Java_sun_awt_motif_MLabelPeer_create; - Java_sun_awt_motif_MLabelPeer_setAlignment; - Java_sun_awt_motif_MLabelPeer_setText; - Java_sun_awt_motif_MListPeer_addItem; - Java_sun_awt_motif_MListPeer_create; - Java_sun_awt_motif_MListPeer_delItems; - Java_sun_awt_motif_MListPeer_deselect; - Java_sun_awt_motif_MListPeer_isSelected; - Java_sun_awt_motif_MListPeer_makeVisible; - Java_sun_awt_motif_MListPeer_select; - Java_sun_awt_motif_MListPeer_setMultipleSelections; - Java_sun_awt_motif_MMenuBarPeer_create; - Java_sun_awt_motif_MMenuItemPeer_createMenuItem; - Java_sun_awt_motif_MMenuItemPeer_pDisable; - Java_sun_awt_motif_MMenuItemPeer_pDispose; - Java_sun_awt_motif_MMenuItemPeer_pEnable; - Java_sun_awt_motif_MMenuItemPeer_pSetLabel; - Java_sun_awt_motif_MMenuPeer_createMenu; - Java_sun_awt_motif_MMenuPeer_createSubMenu; - Java_sun_awt_motif_MMenuPeer_pDispose; - Java_sun_awt_motif_MPopupMenuPeer_createMenu; - Java_sun_awt_motif_MPopupMenuPeer_pDispose; - Java_sun_awt_motif_MPopupMenuPeer_pShow; - Java_sun_awt_motif_MRobotPeer_getRGBPixelsImpl; - Java_sun_awt_motif_MRobotPeer_keyPressImpl; - Java_sun_awt_motif_MRobotPeer_keyReleaseImpl; - Java_sun_awt_motif_MRobotPeer_mouseMoveImpl; - Java_sun_awt_motif_MRobotPeer_mousePressImpl; - Java_sun_awt_motif_MRobotPeer_mouseReleaseImpl; - Java_sun_awt_motif_MRobotPeer_mouseWheelImpl; - Java_sun_awt_motif_MRobotPeer_setup; - Java_sun_awt_motif_MScrollbarPeer_create; - Java_sun_awt_motif_MScrollbarPeer_setLineIncrement; - Java_sun_awt_motif_MScrollbarPeer_setPageIncrement; - Java_sun_awt_motif_MScrollbarPeer_pSetValues; - Java_sun_awt_motif_MScrollPanePeer_create; - Java_sun_awt_motif_MScrollPanePeer_pGetBlockIncrement; - Java_sun_awt_motif_MScrollPanePeer_pGetScrollbarSpace; - Java_sun_awt_motif_MScrollPanePeer_pGetShadow; - Java_sun_awt_motif_MScrollPanePeer_pInsets; - Java_sun_awt_motif_MScrollPanePeer_pSetIncrement; - Java_sun_awt_motif_MScrollPanePeer_pSetScrollChild; - Java_sun_awt_motif_MScrollPanePeer_setScrollPosition; - Java_sun_awt_motif_MTextAreaPeer_initIDs; - Java_sun_awt_motif_MTextAreaPeer_pCreate; - Java_sun_awt_motif_MTextAreaPeer_getCaretPosition; - Java_sun_awt_motif_MTextAreaPeer_getExtraHeight; - Java_sun_awt_motif_MTextAreaPeer_getExtraWidth; - Java_sun_awt_motif_MTextAreaPeer_getSelectionEnd; - Java_sun_awt_motif_MTextAreaPeer_getSelectionStart; - Java_sun_awt_motif_MTextAreaPeer_getText; - Java_sun_awt_motif_MTextAreaPeer_insert; - Java_sun_awt_motif_MTextAreaPeer_pMakeCursorVisible; - Java_sun_awt_motif_MTextAreaPeer_pSetEditable; - Java_sun_awt_motif_MTextAreaPeer_pShow2; - Java_sun_awt_motif_MTextAreaPeer_replaceRange; - Java_sun_awt_motif_MTextAreaPeer_select; - Java_sun_awt_motif_MTextAreaPeer_setCaretPosition; - Java_sun_awt_motif_MTextAreaPeer_setFont; - Java_sun_awt_motif_MTextAreaPeer_setText; - Java_sun_awt_motif_MTextAreaPeer_setTextBackground; - Java_sun_awt_motif_MTextFieldPeer_initIDs; - Java_sun_awt_motif_MTextFieldPeer_pCreate; - Java_sun_awt_motif_MTextFieldPeer_getCaretPosition; - Java_sun_awt_motif_MTextFieldPeer_getSelectionEnd; - Java_sun_awt_motif_MTextFieldPeer_getSelectionStart; - Java_sun_awt_motif_MTextFieldPeer_getText; - Java_sun_awt_motif_MTextFieldPeer_insertReplaceText; - Java_sun_awt_motif_MTextFieldPeer_preDispose; - Java_sun_awt_motif_MTextFieldPeer_pSetEditable; - Java_sun_awt_motif_MTextFieldPeer_select; - Java_sun_awt_motif_MTextFieldPeer_setCaretPosition; - Java_sun_awt_motif_MTextFieldPeer_setEchoChar; - Java_sun_awt_motif_MTextFieldPeer_setFont; - Java_sun_awt_motif_MTextFieldPeer_setText; + #Java_sun_awt_motif_MButtonPeer_create; + #Java_sun_awt_motif_MButtonPeer_setLabel; + #Java_sun_awt_motif_MCanvasPeer_create; + #Java_sun_awt_motif_MCanvasPeer_initIDs; + #Java_sun_awt_motif_MCanvasPeer_resetTargetGC; + #Java_sun_awt_motif_MCheckboxMenuItemPeer_pSetState; + #Java_sun_awt_motif_MCheckboxPeer_create; + #Java_sun_awt_motif_MCheckboxPeer_setCheckboxGroup; + #Java_sun_awt_motif_MCheckboxPeer_setLabel; + #Java_sun_awt_motif_MCheckboxPeer_pSetState; + #Java_sun_awt_motif_MCheckboxPeer_pGetState; + #Java_sun_awt_motif_MChoicePeer_addItem; + #Java_sun_awt_motif_MChoicePeer_appendItems; + #Java_sun_awt_motif_MChoicePeer_create; + #Java_sun_awt_motif_MChoicePeer_pReshape; + #Java_sun_awt_motif_MChoicePeer_remove; + #Java_sun_awt_motif_MChoicePeer_removeAll; + #Java_sun_awt_motif_MChoicePeer_setBackground; + #Java_sun_awt_motif_MChoicePeer_pSelect; + #Java_sun_awt_motif_MChoicePeer_setFont; + #Java_sun_awt_motif_MChoicePeer_setForeground; + #Java_sun_awt_motif_MComponentPeer_addNativeDropTarget; + #Java_sun_awt_motif_MComponentPeer_createBackBuffer; + #Java_sun_awt_motif_MComponentPeer_destroyBackBuffer; + #Java_sun_awt_motif_MComponentPeer_getNativeColor; + #Java_sun_awt_motif_MComponentPeer_getWindow; + #Java_sun_awt_motif_MComponentPeer_pDisable; + #Java_sun_awt_motif_MComponentPeer_pDispose; + #Java_sun_awt_motif_MComponentPeer_pEnable; + #Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen; + #Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen2; + #Java_sun_awt_motif_MComponentPeer_pHide; + #Java_sun_awt_motif_MComponentPeer_pInitialize; + #Java_sun_awt_motif_MComponentPeer_pMakeCursorVisible; + #Java_sun_awt_motif_MComponentPeer_pReshape; + #Java_sun_awt_motif_MComponentPeer_pShow; + #Java_sun_awt_motif_MComponentPeer_removeNativeDropTarget; + #Java_sun_awt_motif_MComponentPeer_swapBuffers; + #Java_sun_awt_motif_MComponentPeer_pSetBackground; + #Java_sun_awt_motif_MComponentPeer_pSetFont; + #Java_sun_awt_motif_MComponentPeer_processSynchronousLightweightTransfer; + #Java_sun_awt_motif_MComponentPeer__1requestFocus; + #Java_sun_awt_motif_MCheckboxMenuItemPeer_getState; + #Java_sun_awt_motif_MComponentPeer_pSetForeground; + #Java_sun_awt_motif_MDragSourceContextPeer_startDrag; + #Java_sun_awt_motif_MDragSourceContextPeer_setNativeCursor; + #Java_sun_awt_motif_MDropTargetContextPeer_addTransfer; + #Java_sun_awt_motif_MDropTargetContextPeer_dropDone; + #Java_sun_awt_motif_MDropTargetContextPeer_startTransfer; + #Java_sun_awt_motif_X11DragSourceContextPeer_startDrag; + #Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor; + #Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse; + #Java_sun_awt_motif_X11DropTargetContextPeer_dropDone; + #Java_sun_awt_motif_X11DropTargetContextPeer_getData; + #Java_sun_awt_motif_MEmbeddedFramePeer_NEFcreate; + #Java_sun_awt_motif_MEmbeddedFramePeer_pShowImpl; + #Java_sun_awt_motif_MEmbeddedFramePeer_pReshapePrivate; + #Java_sun_awt_motif_MEmbeddedFramePeer_getBoundsPrivate; + #Java_sun_awt_motif_MFramePeer_pSetIconImage___3B_3I_3SII; + #Java_sun_awt_motif_MEmbeddedFramePeer_requestXEmbedFocus; + #Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedApplicationActive; + #Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedActive; + #Java_sun_awt_motif_MEmbeddedFrame_getWidget; + #Java_sun_awt_motif_MEmbeddedFrame_mapWidget; + #Java_sun_awt_motif_MFileDialogPeer_create; + #Java_sun_awt_motif_MFileDialogPeer_pDispose; + #Java_sun_awt_motif_MFileDialogPeer_pHide; + #Java_sun_awt_motif_MFileDialogPeer_pReshape; + #Java_sun_awt_motif_MFileDialogPeer_pShow; + #Java_sun_awt_motif_MFileDialogPeer_setFileEntry; + #Java_sun_awt_motif_MFileDialogPeer_setFont; + #Java_sun_awt_motif_MFramePeer_pGetIconSize; + #Java_sun_awt_motif_MGlobalCursorManager_cacheInit; + #Java_sun_awt_motif_MGlobalCursorManager_findComponentAt; + #Java_sun_awt_motif_MGlobalCursorManager_findHeavyweightUnderCursor; + #Java_sun_awt_motif_MGlobalCursorManager_getCursorPos; + #Java_sun_awt_motif_MGlobalCursorManager_getLocationOnScreen; + #Java_sun_awt_motif_MLabelPeer_create; + #Java_sun_awt_motif_MLabelPeer_setAlignment; + #Java_sun_awt_motif_MLabelPeer_setText; + #Java_sun_awt_motif_MListPeer_addItem; + #Java_sun_awt_motif_MListPeer_create; + #Java_sun_awt_motif_MListPeer_delItems; + #Java_sun_awt_motif_MListPeer_deselect; + #Java_sun_awt_motif_MListPeer_isSelected; + #Java_sun_awt_motif_MListPeer_makeVisible; + #Java_sun_awt_motif_MListPeer_select; + #Java_sun_awt_motif_MListPeer_setMultipleSelections; + #Java_sun_awt_motif_MMenuBarPeer_create; + #Java_sun_awt_motif_MMenuItemPeer_createMenuItem; + #Java_sun_awt_motif_MMenuItemPeer_pDisable; + #Java_sun_awt_motif_MMenuItemPeer_pDispose; + #Java_sun_awt_motif_MMenuItemPeer_pEnable; + #Java_sun_awt_motif_MMenuItemPeer_pSetLabel; + #Java_sun_awt_motif_MMenuPeer_createMenu; + #Java_sun_awt_motif_MMenuPeer_createSubMenu; + #Java_sun_awt_motif_MMenuPeer_pDispose; + #Java_sun_awt_motif_MPopupMenuPeer_createMenu; + #Java_sun_awt_motif_MPopupMenuPeer_pDispose; + #Java_sun_awt_motif_MPopupMenuPeer_pShow; + #Java_sun_awt_motif_MRobotPeer_getRGBPixelsImpl; + #Java_sun_awt_motif_MRobotPeer_keyPressImpl; + #Java_sun_awt_motif_MRobotPeer_keyReleaseImpl; + #Java_sun_awt_motif_MRobotPeer_mouseMoveImpl; + #Java_sun_awt_motif_MRobotPeer_mousePressImpl; + #Java_sun_awt_motif_MRobotPeer_mouseReleaseImpl; + #Java_sun_awt_motif_MRobotPeer_mouseWheelImpl; + #Java_sun_awt_motif_MRobotPeer_setup; + #Java_sun_awt_motif_MScrollbarPeer_create; + #Java_sun_awt_motif_MScrollbarPeer_setLineIncrement; + #Java_sun_awt_motif_MScrollbarPeer_setPageIncrement; + #Java_sun_awt_motif_MScrollbarPeer_pSetValues; + #Java_sun_awt_motif_MScrollPanePeer_create; + #Java_sun_awt_motif_MScrollPanePeer_pGetBlockIncrement; + #Java_sun_awt_motif_MScrollPanePeer_pGetScrollbarSpace; + #Java_sun_awt_motif_MScrollPanePeer_pGetShadow; + #Java_sun_awt_motif_MScrollPanePeer_pInsets; + #Java_sun_awt_motif_MScrollPanePeer_pSetIncrement; + #Java_sun_awt_motif_MScrollPanePeer_pSetScrollChild; + #Java_sun_awt_motif_MScrollPanePeer_setScrollPosition; + #Java_sun_awt_motif_MTextAreaPeer_initIDs; + #Java_sun_awt_motif_MTextAreaPeer_pCreate; + #Java_sun_awt_motif_MTextAreaPeer_getCaretPosition; + #Java_sun_awt_motif_MTextAreaPeer_getExtraHeight; + #Java_sun_awt_motif_MTextAreaPeer_getExtraWidth; + #Java_sun_awt_motif_MTextAreaPeer_getSelectionEnd; + #Java_sun_awt_motif_MTextAreaPeer_getSelectionStart; + #Java_sun_awt_motif_MTextAreaPeer_getText; + #Java_sun_awt_motif_MTextAreaPeer_insert; + #Java_sun_awt_motif_MTextAreaPeer_pMakeCursorVisible; + #Java_sun_awt_motif_MTextAreaPeer_pSetEditable; + #Java_sun_awt_motif_MTextAreaPeer_pShow2; + #Java_sun_awt_motif_MTextAreaPeer_replaceRange; + #Java_sun_awt_motif_MTextAreaPeer_select; + #Java_sun_awt_motif_MTextAreaPeer_setCaretPosition; + #Java_sun_awt_motif_MTextAreaPeer_setFont; + #Java_sun_awt_motif_MTextAreaPeer_setText; + #Java_sun_awt_motif_MTextAreaPeer_setTextBackground; + #Java_sun_awt_motif_MTextFieldPeer_initIDs; + #Java_sun_awt_motif_MTextFieldPeer_pCreate; + #Java_sun_awt_motif_MTextFieldPeer_getCaretPosition; + #Java_sun_awt_motif_MTextFieldPeer_getSelectionEnd; + #Java_sun_awt_motif_MTextFieldPeer_getSelectionStart; + #Java_sun_awt_motif_MTextFieldPeer_getText; + #Java_sun_awt_motif_MTextFieldPeer_insertReplaceText; + #Java_sun_awt_motif_MTextFieldPeer_preDispose; + #Java_sun_awt_motif_MTextFieldPeer_pSetEditable; + #Java_sun_awt_motif_MTextFieldPeer_select; + #Java_sun_awt_motif_MTextFieldPeer_setCaretPosition; + #Java_sun_awt_motif_MTextFieldPeer_setEchoChar; + #Java_sun_awt_motif_MTextFieldPeer_setFont; + #Java_sun_awt_motif_MTextFieldPeer_setText; Java_sun_awt_motif_MToolkit_beep; Java_sun_awt_motif_MToolkit_getLockingKeyStateNative; Java_sun_awt_motif_MToolkit_getMulticlickTime; @@ -357,28 +357,28 @@ Java_sun_awt_motif_MToolkit_sync; Java_sun_awt_motif_MToolkit_isAlwaysOnTopSupported; Java_sun_awt_motif_MWindowAttributes_initIDs; - Java_sun_awt_motif_MWindowPeer_pDispose; - Java_sun_awt_motif_MWindowPeer_pHide; - Java_sun_awt_motif_MWindowPeer_pReshape; - Java_sun_awt_motif_MWindowPeer_pSetTitle; - Java_sun_awt_motif_MWindowPeer_pShow; - Java_sun_awt_motif_MWindowPeer_setResizable; - Java_sun_awt_motif_MWindowPeer_toBack; - Java_sun_awt_motif_MWindowPeer_addTextComponentNative; - Java_sun_awt_motif_MWindowPeer_getState; - Java_sun_awt_motif_MWindowPeer_pSetIMMOption; - Java_sun_awt_motif_MWindowPeer_pSetMenuBar; - Java_sun_awt_motif_MWindowPeer_pShowModal; - Java_sun_awt_motif_MWindowPeer_removeTextComponentNative; - Java_sun_awt_motif_MWindowPeer_setSaveUnder; - Java_sun_awt_motif_MWindowPeer_setState; - Java_sun_awt_motif_MWindowPeer_resetTargetGC; - Java_sun_awt_motif_MWindowPeer_registerX11DropTarget; - Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget; - Java_sun_awt_motif_MWindowPeer_updateAlwaysOnTop; - Java_sun_awt_motif_X11CustomCursor_cacheInit; - Java_sun_awt_motif_X11CustomCursor_createCursor; - Java_sun_awt_motif_X11CustomCursor_queryBestCursor; + #Java_sun_awt_motif_MWindowPeer_pDispose; + #Java_sun_awt_motif_MWindowPeer_pHide; + #Java_sun_awt_motif_MWindowPeer_pReshape; + #Java_sun_awt_motif_MWindowPeer_pSetTitle; + #Java_sun_awt_motif_MWindowPeer_pShow; + #Java_sun_awt_motif_MWindowPeer_setResizable; + #Java_sun_awt_motif_MWindowPeer_toBack; + #Java_sun_awt_motif_MWindowPeer_addTextComponentNative; + #Java_sun_awt_motif_MWindowPeer_getState; + #Java_sun_awt_motif_MWindowPeer_pSetIMMOption; + #Java_sun_awt_motif_MWindowPeer_pSetMenuBar; + #Java_sun_awt_motif_MWindowPeer_pShowModal; + #Java_sun_awt_motif_MWindowPeer_removeTextComponentNative; + #Java_sun_awt_motif_MWindowPeer_setSaveUnder; + #Java_sun_awt_motif_MWindowPeer_setState; + #Java_sun_awt_motif_MWindowPeer_resetTargetGC; + #Java_sun_awt_motif_MWindowPeer_registerX11DropTarget; + #Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget; + #Java_sun_awt_motif_MWindowPeer_updateAlwaysOnTop; + #Java_sun_awt_motif_X11CustomCursor_cacheInit; + #Java_sun_awt_motif_X11CustomCursor_createCursor; + #Java_sun_awt_motif_X11CustomCursor_queryBestCursor; Java_sun_awt_motif_X11FontMetrics_bytesWidth; Java_sun_awt_motif_X11FontMetrics_getMFCharsWidth; Java_sun_awt_motif_X11FontMetrics_init; @@ -387,18 +387,18 @@ Java_sun_awt_X11InputMethod_resetXIC; Java_sun_awt_X11InputMethod_setCompositionEnabledNative; Java_sun_awt_X11InputMethod_turnoffStatusWindow; - Java_sun_awt_motif_MInputMethod_openXIMNative; - Java_sun_awt_motif_MInputMethod_configureStatusAreaNative; - Java_sun_awt_motif_MInputMethod_createXICNative; - Java_sun_awt_motif_MInputMethod_reconfigureXICNative; - Java_sun_awt_motif_MInputMethod_setXICFocusNative; - Java_sun_awt_motif_X11Clipboard_getClipboardData; - Java_sun_awt_motif_X11Clipboard_getClipboardFormats; - Java_sun_awt_motif_X11Clipboard_registerClipboardViewer; - Java_sun_awt_motif_X11Clipboard_unregisterClipboardViewer; - Java_sun_awt_motif_X11Selection_init; - Java_sun_awt_motif_X11Selection_pGetSelectionOwnership; - Java_sun_awt_motif_X11Selection_clearNativeContext; + #Java_sun_awt_motif_MInputMethod_openXIMNative; + #Java_sun_awt_motif_MInputMethod_configureStatusAreaNative; + #Java_sun_awt_motif_MInputMethod_createXICNative; + #Java_sun_awt_motif_MInputMethod_reconfigureXICNative; + #Java_sun_awt_motif_MInputMethod_setXICFocusNative; + #Java_sun_awt_motif_X11Clipboard_getClipboardData; + #Java_sun_awt_motif_X11Clipboard_getClipboardFormats; + #Java_sun_awt_motif_X11Clipboard_registerClipboardViewer; + #Java_sun_awt_motif_X11Clipboard_unregisterClipboardViewer; + #Java_sun_awt_motif_X11Selection_init; + #Java_sun_awt_motif_X11Selection_pGetSelectionOwnership; + #Java_sun_awt_motif_X11Selection_clearNativeContext; Java_sun_awt_SunToolkit_closeSplashScreen; Java_sun_awt_PlatformFont_initIDs; Java_sun_awt_X11GraphicsConfig_init; @@ -442,40 +442,40 @@ Java_java_awt_Insets_initIDs; Java_java_awt_TextField_initIDs; Java_java_awt_Window_initIDs; - Java_sun_awt_motif_MCheckboxPeer_getIndicatorSize; - Java_sun_awt_motif_MCheckboxPeer_getSpacing; - Java_sun_awt_motif_MChoicePeer_freeNativeData; - Java_sun_awt_motif_MComponentPeer_getComponents_1NoClientCode; - Java_sun_awt_motif_MComponentPeer_getParent_1NoClientCode; - Java_sun_awt_motif_MComponentPeer_initIDs; - Java_sun_awt_motif_MComponentPeer_nativeHandleEvent; - Java_sun_awt_motif_MComponentPeer_pSetCursor; - Java_sun_awt_motif_MComponentPeer_pSetInnerForeground; - Java_sun_awt_motif_MComponentPeer_pSetScrollbarBackground; - Java_sun_awt_motif_MComponentPeer_setTargetBackground; - Java_sun_awt_motif_MDataTransferer_dragQueryFile; - Java_sun_awt_motif_MDataTransferer_getAtomForTarget; - Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom; - Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText; + #Java_sun_awt_motif_MCheckboxPeer_getIndicatorSize; + #Java_sun_awt_motif_MCheckboxPeer_getSpacing; + #Java_sun_awt_motif_MChoicePeer_freeNativeData; + #Java_sun_awt_motif_MComponentPeer_getComponents_1NoClientCode; + #Java_sun_awt_motif_MComponentPeer_getParent_1NoClientCode; + #Java_sun_awt_motif_MComponentPeer_initIDs; + #Java_sun_awt_motif_MComponentPeer_nativeHandleEvent; + #Java_sun_awt_motif_MComponentPeer_pSetCursor; + #Java_sun_awt_motif_MComponentPeer_pSetInnerForeground; + #Java_sun_awt_motif_MComponentPeer_pSetScrollbarBackground; + #Java_sun_awt_motif_MComponentPeer_setTargetBackground; + #Java_sun_awt_motif_MDataTransferer_dragQueryFile; + #Java_sun_awt_motif_MDataTransferer_getAtomForTarget; + #Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom; + #Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText; Java_sun_awt_motif_MFontPeer_initIDs; - Java_sun_awt_motif_MListPeer_setBackground; - Java_sun_awt_motif_MMenuBarPeer_initIDs; - Java_sun_awt_motif_MMenuBarPeer_pDispose; - Java_sun_awt_motif_MMenuItemPeer_getParent_1NoClientCode; - Java_sun_awt_motif_MMenuItemPeer_initIDs; - Java_sun_awt_motif_MMenuItemPeer_pSetShortcut; - Java_sun_awt_motif_MPopupMenuPeer_initIDs; - Java_sun_awt_motif_MScrollbarPeer_initIDs; - Java_sun_awt_motif_MScrollPanePeer_initIDs; - Java_sun_awt_motif_MTextAreaPeer_pSetCursor; + #Java_sun_awt_motif_MListPeer_setBackground; + #Java_sun_awt_motif_MMenuBarPeer_initIDs; + #Java_sun_awt_motif_MMenuBarPeer_pDispose; + #Java_sun_awt_motif_MMenuItemPeer_getParent_1NoClientCode; + #Java_sun_awt_motif_MMenuItemPeer_initIDs; + #Java_sun_awt_motif_MMenuItemPeer_pSetShortcut; + #Java_sun_awt_motif_MPopupMenuPeer_initIDs; + #Java_sun_awt_motif_MScrollbarPeer_initIDs; + #Java_sun_awt_motif_MScrollPanePeer_initIDs; + #Java_sun_awt_motif_MTextAreaPeer_pSetCursor; Java_sun_awt_motif_MToolkit_shutdown; - Java_sun_awt_motif_MWindowPeer_initIDs; - Java_sun_awt_motif_MWindowPeer_pCreate; - Java_sun_awt_motif_MWindowPeer_wrapInSequenced; + #Java_sun_awt_motif_MWindowPeer_initIDs; + #Java_sun_awt_motif_MWindowPeer_pCreate; + #Java_sun_awt_motif_MWindowPeer_wrapInSequenced; Java_sun_awt_motif_X11FontMetrics_initIDs; - Java_sun_awt_X11InputMethod_initIDs; + #Java_sun_awt_X11InputMethod_initIDs; Java_sun_awt_motif_X11OffScreenImage_updateBitmask; - Java_sun_awt_motif_X11Selection_initIDs; + #Java_sun_awt_motif_X11Selection_initIDs; Java_sun_awt_motif_MToolkitThreadBlockedHandler_enter; Java_sun_awt_motif_MToolkitThreadBlockedHandler_exit; Java_sun_awt_X11GraphicsConfig_init; @@ -503,26 +503,26 @@ Java_sun_awt_X11SurfaceData_isDgaAvailable; Java_sun_awt_X11SurfaceData_setInvalid; Java_sun_awt_X11SurfaceData_flushNativeSurface; - Java_sun_awt_motif_MEmbedCanvasPeer_initXEmbedServer; - Java_sun_awt_motif_MEmbedCanvasPeer_destroyXEmbedServer; - Java_sun_awt_motif_MEmbedCanvasPeer_isXEmbedActive; - Java_sun_awt_motif_MEmbedCanvasPeer_initDispatching; - Java_sun_awt_motif_MEmbedCanvasPeer_endDispatching; - Java_sun_awt_motif_MEmbedCanvasPeer_embedChild; - Java_sun_awt_motif_MEmbedCanvasPeer_childDestroyed; - Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedPreferredSize; - Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedMinimumSize; - Java_sun_awt_motif_MEmbedCanvasPeer_getClientBounds; - Java_sun_awt_motif_MEmbedCanvasPeer_notifyChildEmbedded; - Java_sun_awt_motif_MEmbedCanvasPeer_detachChild; - Java_sun_awt_motif_MEmbedCanvasPeer_forwardKeyEvent; - Java_sun_awt_motif_MEmbedCanvasPeer_getAWTKeyCodeForKeySym; - Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__I; - Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__IJJJ; - Java_sun_awt_motif_MEmbedCanvasPeer_getWindow; - Java_sun_awt_motif_MEmbedCanvasPeer_forwardEventToEmbedded; - Java_sun_awt_motif_GrabbedKey_initKeySymAndModifiers; - Java_sun_awt_motif_MEmbeddedFramePeer_traverseOut; + #Java_sun_awt_motif_MEmbedCanvasPeer_initXEmbedServer; + #Java_sun_awt_motif_MEmbedCanvasPeer_destroyXEmbedServer; + #Java_sun_awt_motif_MEmbedCanvasPeer_isXEmbedActive; + #Java_sun_awt_motif_MEmbedCanvasPeer_initDispatching; + #Java_sun_awt_motif_MEmbedCanvasPeer_endDispatching; + #Java_sun_awt_motif_MEmbedCanvasPeer_embedChild; + #Java_sun_awt_motif_MEmbedCanvasPeer_childDestroyed; + #Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedPreferredSize; + #Java_sun_awt_motif_MEmbedCanvasPeer_getEmbedMinimumSize; + #Java_sun_awt_motif_MEmbedCanvasPeer_getClientBounds; + #Java_sun_awt_motif_MEmbedCanvasPeer_notifyChildEmbedded; + #Java_sun_awt_motif_MEmbedCanvasPeer_detachChild; + #Java_sun_awt_motif_MEmbedCanvasPeer_forwardKeyEvent; + #Java_sun_awt_motif_MEmbedCanvasPeer_getAWTKeyCodeForKeySym; + #Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__I; + #Java_sun_awt_motif_MEmbedCanvasPeer_sendMessage__IJJJ; + #Java_sun_awt_motif_MEmbedCanvasPeer_getWindow; + #Java_sun_awt_motif_MEmbedCanvasPeer_forwardEventToEmbedded; + #Java_sun_awt_motif_GrabbedKey_initKeySymAndModifiers; + #Java_sun_awt_motif_MEmbeddedFramePeer_traverseOut; awt_display; awt_lock; awt_Lock; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/make/sun/awt/mawt.gmk --- a/jdk/make/sun/awt/mawt.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/make/sun/awt/mawt.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -28,14 +28,6 @@ # INIT += $(LIB_LOCATION) -ifndef HEADLESS -ifeq ($(PLATFORM), linux) -ifeq ($(STATIC_MOTIF),false) -INIT += $(LIB_LOCATION)/libXm.so -endif -endif -endif - # # Files # @@ -52,13 +44,9 @@ ifdef HEADLESS FILES_c = $(FILES_NO_MOTIF_c) else - FILES_c = $(FILES_MOTIF_c) $(FILES_NO_MOTIF_c) - - ifeq ($(MOTIF_VERSION), 2) - FILES_c += awt_motif21.c - FILES_c += awt_Choice21.c - endif - +# FILES_c = $(FILES_MOTIF_c) $(FILES_NO_MOTIF_c) +# XXX if in FILES_MOTIF_c there are unrelated to motif stuff, create a separate list! + FILES_c = $(FILES_NO_MOTIF_c) endif ifeq ($(PLATFORM), solaris) @@ -93,15 +81,6 @@ $(LIB_LOCATION): $(MKDIR) -p $@ -ifeq ($(PLATFORM), linux) -ifeq ($(STATIC_MOTIF),false) -$(LIB_LOCATION)/libXm.so: - $(CP) $(MOTIF_LIB)/libXm.so $(LIB_LOCATION)/libXm.so -# Automounter problem makes the link fail on Redhat 6.1. -# $(LN) -s $(MOTIF_LIB)/libXm.so $(LIB_LOCATION)/libXm.so -endif -endif - clean:: # @@ -135,33 +114,49 @@ CPPFLAGS += -DHEADLESS=$(HEADLESS) OTHER_LDLIBS = else -CFLAGS += -DMOTIF_VERSION=$(MOTIF_VERSION) +#CFLAGS += -DMOTIF_VERSION=$(MOTIF_VERSION) -ifeq ($(STATIC_MOTIF),true) - LIBXM = $(MOTIF_LIB)/libXm.a -lXp -lXmu - ifeq ($(PLATFORM), linux) - ifeq ($(ARCH_DATA_MODEL), 64) - LIBXT = -lXt - else - # Allows for builds on Debian GNU Linux, X11 is in a different place - LIBXT = $(firstword $(wildcard /usr/X11R6/lib/libXt.a) \ - $(wildcard /usr/lib/libXt.a)) - LIBSM = $(firstword $(wildcard /usr/X11R6/lib/libSM.a) \ - $(wildcard /usr/lib/libSM.a)) - LIBICE = $(firstword $(wildcard /usr/X11R6/lib/libICE.a) \ - $(wildcard /usr/lib/libICE.a)) - endif - endif -else - LIBXM = -L$(MOTIF_LIB) -lXm -lXp - ifeq ($(PLATFORM), linux) - LIBXT = -lXt - LIBSM = - LIBICE = - endif -endif +#ifeq ($(STATIC_MOTIF),true) +# LIBXM = $(MOTIF_LIB)/libXm.a -lXp -lXmu +# ifeq ($(PLATFORM), linux) +# ifeq ($(ARCH_DATA_MODEL), 64) +# LIBXT = -lXt +# else +# # Allows for builds on Debian GNU Linux, X11 is in a different place +# LIBXT = $(firstword $(wildcard /usr/X11R6/lib/libXt.a) \ +# $(wildcard /usr/lib/libXt.a)) +# LIBSM = $(firstword $(wildcard /usr/X11R6/lib/libSM.a) \ +# $(wildcard /usr/lib/libSM.a)) +# LIBICE = $(firstword $(wildcard /usr/X11R6/lib/libICE.a) \ +# $(wildcard /usr/lib/libICE.a)) +# endif +# endif +#else +# LIBXM = -L$(MOTIF_LIB) -lXm -lXp +# ifeq ($(PLATFORM), linux) +# LIBXT = -lXt +# LIBSM = +# LIBICE = +# endif +#endif LIBXTST = -lXtst +ifeq ($(PLATFORM), linux) + ifeq ($(ARCH_DATA_MODEL), 64) + # XXX what about the rest of them? + LIBXT = -lXt + else + # Allows for builds on Debian GNU Linux, X11 is in a different place + LIBXT = $(firstword $(wildcard /usr/X11R6/lib/libXt.a) \ + $(wildcard /usr/lib/libXt.a)) + LIBSM = $(firstword $(wildcard /usr/X11R6/lib/libSM.a) \ + $(wildcard /usr/lib/libSM.a)) + LIBICE = $(firstword $(wildcard /usr/X11R6/lib/libICE.a) \ + $(wildcard /usr/lib/libICE.a)) + LIBXTST = $(firstword $(wildcard /usr/X11R6/lib/libXtst.a) \ + $(wildcard /usr/lib/libXtst.a)) + endif +endif # Use -lXmu for EditRes support LIBXMU_DBG = -lXmu @@ -169,14 +164,14 @@ LIBXMU = $(LIBXMU_$(VARIANT)) ifeq ($(PLATFORM), solaris) -OTHER_LDLIBS = $(LIBXM) -lXt -lXext $(LIBXTST) $(LIBXMU) -lX11 -lXi +OTHER_LDLIBS = -lXt -lXext $(LIBXTST) $(LIBXMU) -lX11 -lXi endif ifeq ($(PLATFORM), linux) OTHER_CFLAGS += -DMLIB_NO_LIBSUNMATH -OTHER_CFLAGS += -DMOTIF_VERSION=2 +# XXX what is this define below? Isn't it motif-related? OTHER_CFLAGS += -DXMSTRINGDEFINES=1 -OTHER_LDLIBS = $(LIBXM) $(LIBXMU) $(LIBXTST) -lXext $(LIBXT) $(LIBSM) $(LIBICE) -lX11 -lXi +OTHER_LDLIBS = $(LIBXMU) $(LIBXTST) -lXext $(LIBXT) $(LIBSM) $(LIBICE) -lX11 -lXi endif endif @@ -199,9 +194,8 @@ CPPFLAGS += -I$(CUPS_HEADERS_PATH) ifndef HEADLESS -CPPFLAGS += -I$(MOTIF_DIR)/include \ - -I$(OPENWIN_HOME)/include -LDFLAGS += -L$(MOTIF_LIB) -L$(OPENWIN_LIB) +CPPFLAGS += -I$(OPENWIN_HOME)/include +LDFLAGS += -L$(OPENWIN_LIB) endif # !HEADLESS diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/bin/emessages.h --- a/jdk/src/share/bin/emessages.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/bin/emessages.h Wed Jul 05 16:41:30 2017 +0200 @@ -25,8 +25,8 @@ /* * This file primarily consists of all the error and warning messages, that - * are used in ReportErrorMessage. All message must be defined here, in order - * to help in I18N/L10N the messages. + * are used in JLI_ReportErrorMessage. All message must be defined here, in + * order to help with localizing the messages. */ #ifndef _EMESSAGES_H diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/bin/java.c --- a/jdk/src/share/bin/java.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/bin/java.c Wed Jul 05 16:41:30 2017 +0200 @@ -148,7 +148,7 @@ static jboolean IsWildCardEnabled(); #define ARG_CHECK(n, f, a) if (n < 1) { \ - ReportErrorMessage(f, a); \ + JLI_ReportErrorMessage(f, a); \ printUsage = JNI_TRUE; \ *pret = 1; \ return JNI_TRUE; \ @@ -326,15 +326,15 @@ start = CounterGet(); if (!InitializeJVM(&vm, &env, &ifn)) { - ReportErrorMessage(JVM_ERROR1); + JLI_ReportErrorMessage(JVM_ERROR1); exit(1); } if (printVersion || showVersion) { PrintJavaVersion(env, showVersion); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } if (printVersion) { @@ -347,8 +347,8 @@ if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { PrintUsage(env, printXUsage); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); ret=1; } goto leave; @@ -397,43 +397,43 @@ if (jarfile != 0) { mainClassName = GetMainClassName(env, jarfile); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } if (mainClassName == NULL) { - ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); + JLI_ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(CLS_ERROR1, classname); goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); } else { mainClassName = NewPlatformString(env, classname); if (mainClassName == NULL) { - ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); + JLI_ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(CLS_ERROR1, classname); goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); @@ -444,10 +444,10 @@ "([Ljava/lang/String;)V"); if (mainID == NULL) { if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); } else { - ReportErrorMessage(CLS_ERROR3); + JLI_ReportErrorMessage(CLS_ERROR3); } goto leave; } @@ -459,8 +459,8 @@ mainID, JNI_TRUE); if( obj == NULL) { /* exception occurred */ - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } @@ -469,14 +469,14 @@ (*env)->GetObjectClass(env, obj), "getModifiers", "()I"); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mods = (*env)->CallIntMethod(env, obj, mid); if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ - ReportErrorMessage(CLS_ERROR4); + JLI_ReportErrorMessage(CLS_ERROR4); goto leave; } } @@ -484,8 +484,8 @@ /* Build argument array */ mainArgs = NewPlatformStringArray(env, argv, argc); if (mainArgs == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } @@ -506,7 +506,7 @@ * launcher's return code except by calling System.exit. */ if ((*vm)->DetachCurrentThread(vm) != 0) { - ReportErrorMessage(JVM_ERROR2); + JLI_ReportErrorMessage(JVM_ERROR2); ret = 1; goto leave; } @@ -635,7 +635,7 @@ if (loopCount > knownVMsCount) { if (!speculative) { - ReportErrorMessage(CFG_ERROR1); + JLI_ReportErrorMessage(CFG_ERROR1); exit(1); } else { return "ERROR"; @@ -645,7 +645,7 @@ if (nextIdx < 0) { if (!speculative) { - ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias); + JLI_ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias); exit(1); } else { return "ERROR"; @@ -660,7 +660,7 @@ switch (knownVMs[jvmidx].flag) { case VM_WARN: if (!speculative) { - ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1); + JLI_ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1); } /* fall through */ case VM_IGNORE: @@ -670,7 +670,7 @@ break; case VM_ERROR: if (!speculative) { - ReportErrorMessage(CFG_ERROR3, jvmtype); + JLI_ReportErrorMessage(CFG_ERROR3, jvmtype); exit(1); } else { return "ERROR"; @@ -879,9 +879,9 @@ if (jarflag && operand) { if ((res = JLI_ParseManifest(operand, &info)) != 0) { if (res == -1) - ReportErrorMessage(JAR_ERROR2, operand); + JLI_ReportErrorMessage(JAR_ERROR2, operand); else - ReportErrorMessage(JAR_ERROR3, operand); + JLI_ReportErrorMessage(JAR_ERROR3, operand); exit(1); } @@ -948,7 +948,7 @@ * Check for correct syntax of the version specification (JSR 56). */ if (!JLI_ValidVersionString(info.jre_version)) { - ReportErrorMessage(SPC_ERROR1, info.jre_version); + JLI_ReportErrorMessage(SPC_ERROR1, info.jre_version); exit(1); } @@ -970,7 +970,7 @@ JLI_MemFree(new_argv); return; } else { - ReportErrorMessage(CFG_ERROR4, info.jre_version); + JLI_ReportErrorMessage(CFG_ERROR4, info.jre_version); exit(1); } } @@ -1040,7 +1040,7 @@ * command line options. */ } else if (JLI_StrCmp(arg, "-fullversion") == 0) { - ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); + JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); return JNI_FALSE; } else if (JLI_StrCmp(arg, "-verbosegc") == 0) { AddOption("-verbose:gc", NULL); @@ -1080,7 +1080,7 @@ JLI_StrCmp(arg, "-cs") == 0 || JLI_StrCmp(arg, "-noasyncgc") == 0) { /* No longer supported */ - ReportErrorMessage(ARG_WARN, arg); + JLI_ReportErrorMessage(ARG_WARN, arg); } else if (JLI_StrCCmp(arg, "-version:") == 0 || JLI_StrCmp(arg, "-no-jre-restrict-search") == 0 || JLI_StrCmp(arg, "-jre-restrict-search") == 0 || @@ -1143,12 +1143,12 @@ #define NULL_CHECK0(e) if ((e) == 0) { \ - ReportErrorMessage(JNI_ERROR); \ + JLI_ReportErrorMessage(JNI_ERROR); \ return 0; \ } #define NULL_CHECK(e) if ((e) == 0) { \ - ReportErrorMessage(JNI_ERROR); \ + JLI_ReportErrorMessage(JNI_ERROR); \ return; \ } @@ -1351,7 +1351,7 @@ char *arg = argv[i]; if (arg[0] == '-' && arg[1] == 'J') { if (arg[2] == '\0') { - ReportErrorMessage(ARG_ERROR3); + JLI_ReportErrorMessage(ARG_ERROR3); exit(1); } *nargv++ = arg + 2; @@ -1418,7 +1418,7 @@ } if (!GetApplicationHome(home, sizeof(home))) { - ReportErrorMessage(CFG_ERROR5); + JLI_ReportErrorMessage(CFG_ERROR5); return JNI_FALSE; } @@ -1691,7 +1691,7 @@ jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { if (!speculative) { - ReportErrorMessage(CFG_ERROR6, jvmCfgName); + JLI_ReportErrorMessage(CFG_ERROR6, jvmCfgName); exit(1); } else { return -1; @@ -1703,7 +1703,7 @@ if (line[0] == '#') continue; if (line[0] != '-') { - ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName); } if (cnt >= knownVMsLimit) { GrowKnownVMs(cnt); @@ -1711,13 +1711,13 @@ line[JLI_StrLen(line)-1] = '\0'; /* remove trailing newline */ tmpPtr = line + JLI_StrCSpn(line, whiteSpace); if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { /* Null-terminate this string for JLI_StringDup below */ *tmpPtr++ = 0; tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { if (!JLI_StrCCmp(tmpPtr, "KNOWN")) { vmType = VM_KNOWN; @@ -1727,7 +1727,7 @@ tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); } if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { /* Null terminate altVMName */ altVMName = tmpPtr; @@ -1747,7 +1747,7 @@ tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); } if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName); } else { /* Null terminate server class VM name */ serverClassVMName = tmpPtr; @@ -1756,7 +1756,7 @@ vmType = VM_IF_SERVER_CLASS; } } else { - ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]); + JLI_ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]); vmType = VM_KNOWN; } } @@ -2019,7 +2019,7 @@ * A utility procedure to always print to stderr */ void -ReportMessage(const char* fmt, ...) +JLI_ReportMessage(const char* fmt, ...) { va_list vl; va_start(vl, fmt); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/bin/java.h --- a/jdk/src/share/bin/java.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/bin/java.h Wed Jul 05 16:41:30 2017 +0200 @@ -121,24 +121,20 @@ char jvmpath[], jint so_jvmpath, char **original_argv); +/* Reports an error message to stderr or a window as appropriate. */ +void JLI_ReportErrorMessage(const char * message, ...); -/* - * Report an error message to stderr or a window as appropriate. - */ -void ReportErrorMessage(const char * message, ...); -void ReportErrorMessageSys(const char * format, ...); +/* Reports a system error message to stderr or a window */ +void JLI_ReportErrorMessageSys(const char * message, ...); + +/* Reports an error message only to stderr. */ +void JLI_ReportMessage(const char * message, ...); /* - * Report an error message only to stderr. - */ -void ReportMessage(const char * message, ...); - -/* - * Report an exception which terminates the vm to stderr or a window + * Reports an exception which terminates the vm to stderr or a window * as appropriate. */ -void ReportExceptionDescription(JNIEnv * env); - +void JLI_ReportExceptionDescription(JNIEnv * env); void PrintMachineDependentOptions(); const char *jlong_format_specifier(); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java --- a/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Wed Jul 05 16:41:30 2017 +0200 @@ -177,6 +177,18 @@ "javax.management.relation"; /** + * Logger name for Namespaces. + */ + public static final String NAMESPACE_LOGGER_NAME = + "javax.management.namespace"; + + /** + * Logger name for Namespaces. + */ + public static final Logger NAMESPACE_LOGGER = + Logger.getLogger(NAMESPACE_LOGGER_NAME); + + /** * Logger for Relation Service. */ public static final Logger RELATION_LOGGER = diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,33 +25,49 @@ package com.sun.jmx.interceptor; -// java import -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.Set; -import java.util.HashSet; -import java.util.WeakHashMap; + +// JMX RI +import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; +import com.sun.jmx.mbeanserver.DynamicMBean2; +import com.sun.jmx.mbeanserver.Introspector; +import com.sun.jmx.mbeanserver.MBeanInjector; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository; +import com.sun.jmx.mbeanserver.NamedObject; +import com.sun.jmx.mbeanserver.NotifySupport; +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Repository.RegistrationContext; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.remote.util.EnvHelp; + import java.lang.ref.WeakReference; import java.security.AccessControlContext; +import java.security.AccessController; import java.security.Permission; +import java.security.PrivilegedAction; import java.security.ProtectionDomain; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.logging.Level; // JMX import import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; +import javax.management.DynamicWrapperMBean; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.InvalidAttributeValueException; import javax.management.JMRuntimeException; import javax.management.ListenerNotFoundException; -import javax.management.MalformedObjectNameException; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanPermission; @@ -64,6 +80,7 @@ import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; @@ -75,22 +92,7 @@ import javax.management.RuntimeErrorException; import javax.management.RuntimeMBeanException; import javax.management.RuntimeOperationsException; - -// JMX RI -import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; -import com.sun.jmx.mbeanserver.DynamicMBean2; -import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository; -import com.sun.jmx.mbeanserver.MBeanInstantiator; -import com.sun.jmx.mbeanserver.Repository; -import com.sun.jmx.mbeanserver.NamedObject; -import com.sun.jmx.mbeanserver.Introspector; -import com.sun.jmx.mbeanserver.MBeanInjector; -import com.sun.jmx.mbeanserver.NotifySupport; -import com.sun.jmx.mbeanserver.Repository.RegistrationContext; -import com.sun.jmx.mbeanserver.Util; -import com.sun.jmx.remote.util.EnvHelp; -import javax.management.DynamicWrapperMBean; -import javax.management.NotificationBroadcasterSupport; +import javax.management.namespace.JMXNamespace; /** * This is the default class for MBean manipulation on the agent side. It @@ -113,7 +115,8 @@ * * @since 1.5 */ -public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { +public class DefaultMBeanServerInterceptor + extends MBeanServerInterceptorSupport { /** The MBeanInstantiator object used by the * DefaultMBeanServerInterceptor */ @@ -123,7 +126,7 @@ * DefaultMBeanServerInterceptor */ private transient MBeanServer server = null; - /** The MBean server object taht associated to the + /** The MBean server delegate object that is associated to the * DefaultMBeanServerInterceptor */ private final transient MBeanServerDelegate delegate; @@ -138,13 +141,15 @@ new WeakHashMap>(); + private final NamespaceDispatchInterceptor dispatcher; + /** The default domain of the object names */ private final String domain; - /** True if the repository perform queries, false otherwise */ - private boolean queryByRepo; + /** The mbeanServerName */ + private final String mbeanServerName; - /** The sequence number identifyng the notifications sent */ + /** The sequence number identifying the notifications sent */ // Now sequence number is handled by MBeanServerDelegate. // private int sequenceNumber=0; @@ -162,11 +167,13 @@ * @param instantiator The MBeanInstantiator that will be used to * instantiate MBeans and take care of class loading issues. * @param repository The repository to use for this MBeanServer. + * @param dispatcher The dispatcher used by this MBeanServer */ public DefaultMBeanServerInterceptor(MBeanServer outer, MBeanServerDelegate delegate, MBeanInstantiator instantiator, - Repository repository) { + Repository repository, + NamespaceDispatchInterceptor dispatcher) { if (outer == null) throw new IllegalArgumentException("outer MBeanServer cannot be null"); if (delegate == null) throw new @@ -181,6 +188,8 @@ this.instantiator = instantiator; this.repository = repository; this.domain = repository.getDefaultDomain(); + this.dispatcher = dispatcher; + this.mbeanServerName = Util.getMBeanServerSecurityName(delegate); } public ObjectInstance createMBean(String className, ObjectName name) @@ -259,8 +268,8 @@ name = nonDefaultDomain(name); } - checkMBeanPermission(className, null, null, "instantiate"); - checkMBeanPermission(className, null, name, "registerMBean"); + checkMBeanPermission(mbeanServerName,className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName,className, null, name, "registerMBean"); /* Load the appropriate class. */ if (withDefaultLoaderRepository) { @@ -324,7 +333,7 @@ final String infoClassName = getNewMBeanClassName(object); - checkMBeanPermission(infoClassName, null, name, "registerMBean"); + checkMBeanPermission(mbeanServerName,infoClassName, null, name, "registerMBean"); checkMBeanTrustPermission(theClass); return registerObject(infoClassName, object, name); @@ -433,7 +442,8 @@ DynamicMBean instance = getMBean(name); // may throw InstanceNotFoundException - checkMBeanPermission(instance, null, name, "unregisterMBean"); + checkMBeanPermission(mbeanServerName, instance, null, name, + "unregisterMBean"); if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); @@ -467,7 +477,8 @@ name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "getObjectInstance"); + checkMBeanPermission(mbeanServerName, + instance, null, name, "getObjectInstance"); final String className = getClassName(instance); @@ -479,7 +490,7 @@ if (sm != null) { // Check if the caller has the right to invoke 'queryMBeans' // - checkMBeanPermission((String) null, null, null, "queryMBeans"); + checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryMBeans"); // Perform query without "query". // @@ -492,7 +503,7 @@ new HashSet (list.size()); for (ObjectInstance oi : list) { try { - checkMBeanPermission(oi.getClassName(), null, + checkMBeanPermission(mbeanServerName,oi.getClassName(), null, oi.getObjectName(), "queryMBeans"); allowedList.add(oi); } catch (SecurityException e) { @@ -516,11 +527,6 @@ // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectInstancesFromFilteredNamedObjects(list, query)); } @@ -530,7 +536,7 @@ if (sm != null) { // Check if the caller has the right to invoke 'queryNames' // - checkMBeanPermission((String) null, null, null, "queryNames"); + checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryNames"); // Perform query without "query". // @@ -543,7 +549,7 @@ new HashSet (list.size()); for (ObjectInstance oi : list) { try { - checkMBeanPermission(oi.getClassName(), null, + checkMBeanPermission(mbeanServerName, oi.getClassName(), null, oi.getObjectName(), "queryNames"); allowedList.add(oi); } catch (SecurityException e) { @@ -572,11 +578,6 @@ // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectNamesFromFilteredNamedObjects(list, query)); } @@ -589,8 +590,8 @@ name = nonDefaultDomain(name); -// /* Permission check */ -// checkMBeanPermission(null, null, name, "isRegistered"); + /* No Permission check */ + // isRegistered is always unchecked as per JMX spec. return (repository.contains(name)); } @@ -600,7 +601,7 @@ if (sm != null) { // Check if the caller has the right to invoke 'getDomains' // - checkMBeanPermission((String) null, null, null, "getDomains"); + checkMBeanPermission(mbeanServerName, (String) null, null, null, "getDomains"); // Return domains // @@ -612,8 +613,9 @@ List result = new ArrayList (domains.length); for (int i = 0; i < domains.length; i++) { try { - ObjectName domain = Util.newObjectName(domains[i] + ":x=x"); - checkMBeanPermission((String) null, null, domain, "getDomains"); + ObjectName dom = + Util.newObjectName(domains[i] + ":x=x"); + checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains"); result.add(domains[i]); } catch (SecurityException e) { // OK: Do not add this domain to the list @@ -657,7 +659,8 @@ } final DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute, name, "getAttribute"); + checkMBeanPermission(mbeanServerName, instance, attribute, + name, "getAttribute"); try { return instance.getAttribute(attribute); @@ -702,7 +705,7 @@ // Check if the caller has the right to invoke 'getAttribute' // - checkMBeanPermission(classname, null, name, "getAttribute"); + checkMBeanPermission(mbeanServerName, classname, null, name, "getAttribute"); // Check if the caller has the right to invoke 'getAttribute' // on each specific attribute @@ -711,14 +714,15 @@ new ArrayList (attributes.length); for (String attr : attributes) { try { - checkMBeanPermission(classname, attr, + checkMBeanPermission(mbeanServerName, classname, attr, name, "getAttribute"); allowedList.add(attr); } catch (SecurityException e) { // OK: Do not add this attribute to the list } } - allowedAttributes = allowedList.toArray(new String[0]); + allowedAttributes = + allowedList.toArray(new String[allowedList.size()]); } try { @@ -756,7 +760,7 @@ } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute.getName(), + checkMBeanPermission(mbeanServerName, instance, attribute.getName(), name, "setAttribute"); try { @@ -799,7 +803,7 @@ // Check if the caller has the right to invoke 'setAttribute' // - checkMBeanPermission(classname, null, name, "setAttribute"); + checkMBeanPermission(mbeanServerName, classname, null, name, "setAttribute"); // Check if the caller has the right to invoke 'setAttribute' // on each specific attribute @@ -808,7 +812,7 @@ for (Iterator i = attributes.iterator(); i.hasNext();) { try { Attribute attribute = (Attribute) i.next(); - checkMBeanPermission(classname, attribute.getName(), + checkMBeanPermission(mbeanServerName, classname, attribute.getName(), name, "setAttribute"); allowedAttributes.add(attribute); } catch (SecurityException e) { @@ -832,7 +836,8 @@ name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, operationName, name, "invoke"); + checkMBeanPermission(mbeanServerName, instance, operationName, + name, "invoke"); try { return instance.invoke(operationName, params, signature); } catch (Throwable t) { @@ -934,8 +939,7 @@ "registerMBean", "ObjectName = " + name); } - ObjectName logicalName = name; - logicalName = preRegister(mbean, server, name); + ObjectName logicalName = preRegister(mbean, server, name); // preRegister returned successfully, so from this point on we // must call postRegister(false) if there is any problem. @@ -961,16 +965,17 @@ if (logicalName != name && logicalName != null) { logicalName = - ObjectName.getInstance(nonDefaultDomain(logicalName)); + ObjectName.getInstance(nonDefaultDomain(logicalName)); } - checkMBeanPermission(classname, null, logicalName, "registerMBean"); + checkMBeanPermission(mbeanServerName, classname, null, logicalName, + "registerMBean"); if (logicalName == null) { final RuntimeException wrapped = - new IllegalArgumentException("No object name specified"); + new IllegalArgumentException("No object name specified"); throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean"); + "Exception occurred trying to register the MBean"); } final Object resource = getResource(mbean); @@ -987,13 +992,15 @@ // context = registerWithRepository(resource, mbean, logicalName); + registerFailed = false; registered = true; + } finally { try { postRegister(logicalName, mbean, registered, registerFailed); } finally { - if (registered) context.done(); + if (registered && context!=null) context.done(); } } return new ObjectInstance(logicalName, classname); @@ -1001,20 +1008,19 @@ private static void throwMBeanRegistrationException(Throwable t, String where) throws MBeanRegistrationException { - try { - throw t; - } catch (RuntimeException e) { - throw new RuntimeMBeanException( - e, "RuntimeException thrown " + where); - } catch (Error er) { - throw new RuntimeErrorException(er, "Error thrown " + where); - } catch (MBeanRegistrationException r) { - throw r; - } catch (Exception ex) { - throw new MBeanRegistrationException(ex, "Exception thrown " + where); - } catch (Throwable t1) { - throw new RuntimeException(t); // neither Error nor Exception?? - } + if (t instanceof RuntimeException) { + throw new RuntimeMBeanException((RuntimeException)t, + "RuntimeException thrown " + where); + } else if (t instanceof Error) { + throw new RuntimeErrorException((Error)t, + "Error thrown " + where); + } else if (t instanceof MBeanRegistrationException) { + throw (MBeanRegistrationException)t; + } else if (t instanceof Exception) { + throw new MBeanRegistrationException((Exception)t, + "Exception thrown " + where); + } else // neither Error nor Exception?? + throw new RuntimeException(t); } private static ObjectName preRegister( @@ -1230,7 +1236,8 @@ } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "addNotificationListener"); + checkMBeanPermission(mbeanServerName, instance, null, + name, "addNotificationListener"); NotificationBroadcaster broadcaster = getNotificationBroadcaster(name, instance, @@ -1367,7 +1374,7 @@ } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, + checkMBeanPermission(mbeanServerName, instance, null, name, "removeNotificationListener"); /* We could simplify the code by assigning broadcaster after @@ -1438,7 +1445,7 @@ throw new JMRuntimeException("MBean " + name + "has no MBeanInfo"); - checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo"); + checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo"); return mbi; } @@ -1446,8 +1453,9 @@ public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException { - DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "isInstanceOf"); + final DynamicMBean instance = getMBean(name); + checkMBeanPermission(mbeanServerName, + instance, null, name, "isInstanceOf"); try { Object resource = getResource(instance); @@ -1498,7 +1506,8 @@ throws InstanceNotFoundException { DynamicMBean instance = getMBean(mbeanName); - checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); + checkMBeanPermission(mbeanServerName, instance, null, mbeanName, + "getClassLoaderFor"); return getResourceLoader(instance); } @@ -1513,12 +1522,13 @@ throws InstanceNotFoundException { if (loaderName == null) { - checkMBeanPermission((String) null, null, null, "getClassLoader"); + checkMBeanPermission(mbeanServerName, (String) null, null, null, "getClassLoader"); return server.getClass().getClassLoader(); } DynamicMBean instance = getMBean(loaderName); - checkMBeanPermission(instance, null, loaderName, "getClassLoader"); + checkMBeanPermission(mbeanServerName, instance, null, loaderName, + "getClassLoader"); Object resource = getResource(instance); @@ -1568,7 +1578,7 @@ } } else { // Access the filter - MBeanServer oldServer = QueryEval.getMBeanServer(); + final MBeanServer oldServer = QueryEval.getMBeanServer(); query.setMBeanServer(server); try { for (NamedObject no : list) { @@ -1817,26 +1827,30 @@ return mbean.getMBeanInfo().getClassName(); } - private static void checkMBeanPermission(DynamicMBean mbean, + private static void checkMBeanPermission(String mbeanServerName, + DynamicMBean mbean, String member, ObjectName objectName, String actions) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkMBeanPermission(safeGetClassName(mbean), + checkMBeanPermission(mbeanServerName, + safeGetClassName(mbean), member, objectName, actions); } } - private static void checkMBeanPermission(String classname, + private static void checkMBeanPermission(String mbeanServerName, + String classname, String member, ObjectName objectName, String actions) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - Permission perm = new MBeanPermission(classname, + Permission perm = new MBeanPermission(mbeanServerName, + classname, member, objectName, actions); @@ -1902,6 +1916,12 @@ throws InstanceAlreadyExistsException, MBeanRegistrationException { + // this will throw an exception if the pair (resource, logicalName) + // violates namespace conventions - for instance, if logicalName + // ends with // but resource is not a JMXNamespace. + // + checkResourceObjectNameConstraints(resource, logicalName); + // Creates a registration context, if needed. // final ResourceContext context = @@ -1967,6 +1987,57 @@ return context; } + + /** + * Checks that the ObjectName is legal with regards to the + * type of the MBean resource. + * If the MBean name is domain:type=JMXDomain, the + * MBean must be a JMXDomain. + * If the MBean name is namespace//:type=JMXNamespace, the + * MBean must be a JMXNamespace. + * If the MBean is a JMXDomain, its name + * must be domain:type=JMXDomain. + * If the MBean is a JMXNamespace, its name + * must be namespace//:type=JMXNamespace. + */ + private void checkResourceObjectNameConstraints(Object resource, + ObjectName logicalName) + throws MBeanRegistrationException { + try { + dispatcher.checkLocallyRegistrable(resource, logicalName); + } catch (Throwable x) { + DefaultMBeanServerInterceptor.throwMBeanRegistrationException(x, "validating ObjectName"); + } + } + + /** + * Registers a JMXNamespace with the dispatcher. + * This method is called by the ResourceContext from within the + * repository lock. + * @param namespace The JMXNamespace + * @param logicalName The JMXNamespaceMBean ObjectName + * @param postQueue A queue that will be processed after postRegister. + */ + private void addJMXNamespace(JMXNamespace namespace, + final ObjectName logicalName, + final Queue postQueue) { + dispatcher.addNamespace(logicalName, namespace, postQueue); + } + + /** + * Unregisters a JMXNamespace from the dispatcher. + * This method is called by the ResourceContext from within the + * repository lock. + * @param namespace The JMXNamespace + * @param logicalName The JMXNamespaceMBean ObjectName + * @param postQueue A queue that will be processed after postDeregister. + */ + private void removeJMXNamespace(JMXNamespace namespace, + final ObjectName logicalName, + final Queue postQueue) { + dispatcher.removeNamespace(logicalName, namespace, postQueue); + } + /** * Registers a ClassLoader with the CLR. * This method is called by the ResourceContext from within the @@ -2020,6 +2091,52 @@ } } + + /** + * Creates a ResourceContext for a JMXNamespace MBean. + * The resource context makes it possible to add the JMXNamespace to + * (ResourceContext.registering) or resp. remove the JMXNamespace from + * (ResourceContext.unregistered) the NamespaceDispatchInterceptor + * when the associated MBean is added to or resp. removed from the + * repository. + * Note: JMXDomains are special sub classes of JMXNamespaces and + * are also handled by this object. + * + * @param namespace The JMXNamespace MBean being registered or + * unregistered. + * @param logicalName The name of the JMXNamespace MBean. + * @return a ResourceContext that takes in charge the addition or removal + * of the namespace to or from the NamespaceDispatchInterceptor. + */ + private ResourceContext createJMXNamespaceContext( + final JMXNamespace namespace, + final ObjectName logicalName) { + final Queue doneTaskQueue = new LinkedList (); + return new ResourceContext() { + + public void registering() { + addJMXNamespace(namespace, logicalName, doneTaskQueue); + } + + public void unregistered() { + removeJMXNamespace(namespace, logicalName, + doneTaskQueue); + } + + public void done() { + for (Runnable r : doneTaskQueue) { + try { + r.run(); + } catch (RuntimeException x) { + MBEANSERVER_LOGGER.log(Level.FINE, + "Failed to process post queue for "+ + logicalName, x); + } + } + } + }; + } + /** * Creates a ResourceContext for a ClassLoader MBean. * The resource context makes it possible to add the ClassLoader to @@ -2065,10 +2182,16 @@ */ private ResourceContext makeResourceContextFor(Object resource, ObjectName logicalName) { + if (resource instanceof JMXNamespace) { + return createJMXNamespaceContext((JMXNamespace) resource, + logicalName); + } if (resource instanceof ClassLoader) { return createClassLoaderContext((ClassLoader) resource, logicalName); } return ResourceContext.NONE; } + + } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,547 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.interceptor; + + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespace; + +/** + * A dispatcher that dispatches to MBeanServers. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +// +// This is the base class for implementing dispatchers. We have two concrete +// dispatcher implementations: +// +// * A NamespaceDispatchInterceptor, which dispatch calls to existing +// namespace interceptors +// * A DomainDispatchInterceptor, which dispatch calls to existing domain +// interceptors. +// +// With the JMX Namespaces feature, the JMX MBeanServer is now structured +// as follows: +// +// The JMX MBeanServer delegates to a NamespaceDispatchInterceptor, +// which either dispatches to a namespace, or delegates to the +// DomainDispatchInterceptor (if the object name contained no namespace). +// The DomainDispatchInterceptor in turn either dispatches to a domain (if +// there is a JMXDomain for that domain) or delegates to the +// DefaultMBeanServerInterceptor (if there is no JMXDomain for that +// domain). This makes the following picture: +// +// JMX MBeanServer (outer shell) +// | +// | +// NamespaceDispatchInterceptor +// / \ +// no namespace in object name? \ +// / \ +// / dispatch to namespace +// DomainDispatchInterceptor +// / \ +// no JMXDomain for domain? \ +// / \ +// / dispatch to domain +// DefaultMBeanServerInterceptor +// / +// invoke locally registered MBean +// +// The logic for maintaining a map of interceptors +// and dispatching to impacted interceptor, is implemented in this +// base class, which both NamespaceDispatchInterceptor and +// DomainDispatchInterceptor extend. +// +public abstract class DispatchInterceptor ++ extends MBeanServerInterceptorSupport { + + /** + * This is an abstraction which allows us to handle queryNames + * and queryMBeans with the same algorithm. There are some subclasses + * where we need to override both queryNames & queryMBeans to apply + * the same transformation (usually aggregation of results when + * several namespaces/domains are impacted) to both algorithms. + * Usually the only thing that varies between the algorithm of + * queryNames & the algorithm of queryMBean is the type of objects + * in the returned Set. By using a QueryInvoker we can implement the + * transformation only once and apply it to both queryNames & + * queryMBeans. + * @see QueryInterceptor below, and its subclass in + * {@link DomainDispatcher}. + **/ + static abstract class QueryInvoker { + abstract Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query); + } + + /** + * Used to perform queryNames. A QueryInvoker that invokes + * queryNames on an MBeanServer. + **/ + final static QueryInvoker queryNamesInvoker = + new QueryInvoker () { + Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query) { + return mbs.queryNames(pattern,query); + } + }; + + /** + * Used to perform queryMBeans. A QueryInvoker that invokes + * queryMBeans on an MBeanServer. + **/ + final static QueryInvoker queryMBeansInvoker = + new QueryInvoker () { + Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query) { + return mbs.queryMBeans(pattern,query); + } + }; + + /** + * We use this class to intercept queries. + * There's a special case for JMXNamespace MBeans, because + * "namespace//*:*" matches both "namespace//domain:k=v" and + * "namespace//:type=JMXNamespace". + * Therefore, queries may need to be forwarded to more than + * on interceptor and the results aggregated... + */ + static class QueryInterceptor { + final MBeanServer wrapped; + QueryInterceptor(MBeanServer mbs) { + wrapped = mbs; + } + Set query(ObjectName pattern, QueryExp query, + QueryInvoker invoker, MBeanServer server) { + return invoker.query(server, pattern, query); + } + + public Set queryNames(ObjectName pattern, QueryExp query) { + return query(pattern,query,queryNamesInvoker,wrapped); + } + + public Set queryMBeans(ObjectName pattern, + QueryExp query) { + return query(pattern,query,queryMBeansInvoker,wrapped); + } + } + + // We don't need a ConcurrentHashMap here because getkeys() returns + // an array of keys. Therefore there's no risk to have a + // ConcurrentModificationException. We must however take into + // account the fact that there can be no interceptor for + // some of the returned keys if the map is being modified by + // another thread, or by a callback within the same thread... + // See getKeys() in this class and query() in DomainDispatcher. + // + private final Map handlerMap = + Collections.synchronizedMap( + new HashMap ()); + + // The key at which an interceptor for accessing the named MBean can be + // found in the handlerMap. Note: there doesn't need to be an interceptor + // for that key in the Map. + // + public abstract String getHandlerKey(ObjectName name); + + // Returns an interceptor for that name, or null if there's no interceptor + // for that name. + abstract MBeanServer getInterceptorOrNullFor(ObjectName name); + + // Returns a QueryInterceptor for that pattern. + abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern); + + // Returns the ObjectName of the JMXNamespace (or JMXDomain) for that + // key (a namespace or a domain name). + abstract ObjectName getHandlerNameFor(String key) + throws MalformedObjectNameException; + + // Creates an interceptor for the given key, name, JMXNamespace (or + // JMXDomain). Note: this will be either a NamespaceInterceptor + // wrapping a JMXNamespace, if this object is an instance of + // NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a + // JMXDomain, if this object is an instance of DomainDispatchInterceptor. + abstract T createInterceptorFor(String key, ObjectName name, + N jmxNamespace, Queue postRegisterQueue); + // + // The next interceptor in the chain. + // + // For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor. + // For the DomainDispatchInterceptor, this is the + // DefaultMBeanServerInterceptor. + // + // The logic of when to invoke the next interceptor in the chain depends + // on the logic of the concrete dispatcher class. + // + // For instance, the NamespaceDispatchInterceptor invokes the next + // interceptor when the object name doesn't contain any namespace. + // + // On the other hand, the DomainDispatchInterceptor invokes the + // next interceptor when there's no interceptor for the accessed domain. + // + abstract MBeanServer getNextInterceptor(); + + // hook for cleanup in subclasses. + void interceptorReleased(T interceptor, + Queue postDeregisterQueue) { + // hook + } + + // Hook for subclasses. + MBeanServer getInterceptorForCreate(ObjectName name) + throws MBeanRegistrationException { + final MBeanServer ns = getInterceptorOrNullFor(name); + if (ns == null) // name cannot be null here. + throw new MBeanRegistrationException( + new IllegalArgumentException("No such MBean handler: " + + getHandlerKey(name) + " for " +name)); + return ns; + } + + // Hook for subclasses. + MBeanServer getInterceptorForInstance(ObjectName name) + throws InstanceNotFoundException { + final MBeanServer ns = getInterceptorOrNullFor(name); + if (ns == null) // name cannot be null here. + throw new InstanceNotFoundException(String.valueOf(name)); + return ns; + } + + // sanity checks + void validateHandlerNameFor(String key, ObjectName name) { + if (key == null || key.equals("")) + throw new IllegalArgumentException("invalid key for "+name+": "+key); + try { + final ObjectName handlerName = getHandlerNameFor(key); + if (!name.equals(handlerName)) + throw new IllegalArgumentException("bad handler name: "+name+ + ". Should be: "+handlerName); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(name.toString(),x); + } + } + + // Called by the DefaultMBeanServerInterceptor when an instance + // of JMXNamespace (or a subclass of it) is registered as an MBean. + // This method is usually invoked from within the repository lock, + // hence the necessity of the postRegisterQueue. + public void addNamespace(ObjectName name, N jmxNamespace, + Queue postRegisterQueue) { + final String key = getHandlerKey(name); + validateHandlerNameFor(key,name); + synchronized (handlerMap) { + final T exists = + handlerMap.get(key); + if (exists != null) + throw new IllegalArgumentException(key+ + ": handler already exists"); + + final T ns = createInterceptorFor(key,name,jmxNamespace, + postRegisterQueue); + handlerMap.put(key,ns); + } + } + + // Called by the DefaultMBeanServerInterceptor when an instance + // of JMXNamespace (or a subclass of it) is deregistered. + // This method is usually invoked from within the repository lock, + // hence the necessity of the postDeregisterQueue. + public void removeNamespace(ObjectName name, N jmxNamespace, + Queue postDeregisterQueue) { + final String key = getHandlerKey(name); + final T ns; + synchronized(handlerMap) { + ns = handlerMap.remove(key); + } + interceptorReleased(ns,postDeregisterQueue); + } + + // Get the interceptor for that key. + T getInterceptor(String key) { + synchronized (handlerMap) { + return handlerMap.get(key); + } + } + + // We return an array of keys, which makes it possible to make + // concurrent modifications of the handlerMap, provided that + // the code which loops over the keys is prepared to handle null + // interceptors. + // See declaration of handlerMap above, and see also query() in + // DomainDispatcher + // + public String[] getKeys() { + synchronized (handlerMap) { + final int size = handlerMap.size(); + return handlerMap.keySet().toArray(new String[size]); + } + } + + // From MBeanServer + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).createMBean(className,name); + } + + // From MBeanServer + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException{ + return getInterceptorForCreate(name).createMBean(className,name,loaderName); + } + + // From MBeanServer + public ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException{ + return getInterceptorForCreate(name). + createMBean(className,name,params,signature); + } + + // From MBeanServer + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object params[], + String signature[]) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException{ + return getInterceptorForCreate(name).createMBean(className,name,loaderName, + params,signature); + } + + // From MBeanServer + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).registerMBean(object,name); + } + + // From MBeanServer + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + getInterceptorForInstance(name).unregisterMBean(name); + } + + // From MBeanServer + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).getObjectInstance(name); + } + + // From MBeanServer + public Set queryMBeans(ObjectName name, QueryExp query) { + final QueryInterceptor mbs = + getInterceptorForQuery(name); + if (mbs == null) return Collections.emptySet(); + else return mbs.queryMBeans(name,query); + } + + // From MBeanServer + public Set queryNames(ObjectName name, QueryExp query) { + final QueryInterceptor mbs = + getInterceptorForQuery(name); + if (mbs == null) return Collections.emptySet(); + else return mbs.queryNames(name,query); + } + + // From MBeanServer + public boolean isRegistered(ObjectName name) { + final MBeanServer mbs = getInterceptorOrNullFor(name); + if (mbs == null) return false; + else return mbs.isRegistered(name); + } + + // From MBeanServer + public Integer getMBeanCount() { + return getNextInterceptor().getMBeanCount(); + } + + // From MBeanServer + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttribute(name,attribute); + } + + // From MBeanServer + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttributes(name,attributes); + } + + // From MBeanServer + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + getInterceptorForInstance(name).setAttribute(name,attribute); + } + + // From MBeanServer + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).setAttributes(name,attributes); + } + + // From MBeanServer + public Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws InstanceNotFoundException, MBeanException, + ReflectionException { + return getInterceptorForInstance(name).invoke(name,operationName,params, + signature); + } + + // From MBeanServer + public String getDefaultDomain() { + return getNextInterceptor().getDefaultDomain(); + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + public abstract String[] getDomains(); + + // From MBeanServer + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name).addNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name).addNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name).removeNotificationListener(name,listener); + } + + // From MBeanServer + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name).removeNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name).removeNotificationListener(name,listener); + } + + // From MBeanServer + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name).removeNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + return getInterceptorForInstance(name).getMBeanInfo(name); + } + + + // From MBeanServer + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).isInstanceOf(name,className); + } + + // From MBeanServer + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return getInterceptorForInstance(mbeanName).getClassLoaderFor(mbeanName); + } + + // From MBeanServer + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + return getInterceptorForInstance(loaderName).getClassLoader(loaderName); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,322 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.interceptor; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.namespace.DomainInterceptor; +import java.util.Queue; +import java.util.Set; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.namespace.JMXDomain; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +/** + * A dispatcher that dispatch incoming MBeanServer requests to + * DomainInterceptors. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +// +// See comments in DispatchInterceptor. +// +class DomainDispatchInterceptor + extends DispatchInterceptor{ + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final ObjectName ALL_DOMAINS = + JMXDomain.getDomainObjectName("*"); + + + /** + * A QueryInterceptor that perform & aggregates queries spanning several + * domains. + */ + final static class AggregatingQueryInterceptor extends QueryInterceptor { + + private final DomainDispatchInterceptor parent; + AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) { + super(dispatcher.localNamespace); + parent = dispatcher; + } + + /** + * Perform queryNames or queryMBeans, depending on which QueryInvoker + * is passed as argument. This is closures without closures. + **/ + @Override + Set query(ObjectName pattern, QueryExp query, + QueryInvoker invoker, MBeanServer localNamespace) { + final Set local = invoker.query(localNamespace, pattern, query); + + // Add all matching MBeans from local namespace. + final Set res = Util.cloneSet(local); + + final boolean all = (pattern == null || + pattern.getDomain().equals("*")); + if (pattern == null) pattern = ObjectName.WILDCARD; + + final String domain = pattern.getDomain(); + + // If there's no domain pattern, just include the pattern's domain. + // Otherwiae, loop over all virtual domains (parent.getKeys()). + final String[] keys = + (pattern.isDomainPattern() ? + parent.getKeys() : new String[]{domain}); + + // Add all matching MBeans from each virtual domain + // + for (String key : keys) { + // Only invoke those virtual domain which are selected + // by the domain pattern + // + if (!all && !Util.isDomainSelected(key, domain)) + continue; + + try { + final MBeanServer mbs = parent.getInterceptor(key); + + // mbs can be null if the interceptor was removed + // concurrently... + // See handlerMap and getKeys() in DispatchInterceptor + // + if (mbs == null) continue; + + // If the domain is selected, we can replace the pattern + // by the actual domain. This is safer if we want to avoid + // a domain (which could be backed up by an MBeanServer) to + // return names from outside the domain. + // So instead of asking the domain handler for "foo" to + // return all names which match "?o*:type=Bla,*" we're + // going to ask it to return all names which match + // "foo:type=Bla,*" + // + final ObjectName subPattern = pattern.withDomain(key); + res.addAll(invoker.query(mbs, subPattern, query)); + } catch (Exception x) { + LOG.finest("Ignoring exception " + + "when attempting to query namespace "+key+": "+x); + continue; + } + } + return res; + } + } + + private final DefaultMBeanServerInterceptor localNamespace; + private final String mbeanServerName; + private final MBeanServerDelegate delegate; + + /** + * Creates a DomainDispatchInterceptor with the specified + * repository instance. + * + * @param outer A pointer to the MBeanServer object that must be + * passed to the MBeans when invoking their + * {@link javax.management.MBeanRegistration} interface. + * @param delegate A pointer to the MBeanServerDelegate associated + * with the new MBeanServer. The new MBeanServer must register + * this MBean in its MBean repository. + * @param instantiator The MBeanInstantiator that will be used to + * instantiate MBeans and take care of class loading issues. + * @param repository The repository to use for this MBeanServer + */ + public DomainDispatchInterceptor(MBeanServer outer, + MBeanServerDelegate delegate, + MBeanInstantiator instantiator, + Repository repository, + NamespaceDispatchInterceptor namespaces) { + localNamespace = new DefaultMBeanServerInterceptor(outer, + delegate, instantiator,repository,namespaces); + mbeanServerName = Util.getMBeanServerSecurityName(delegate); + this.delegate = delegate; + } + + final boolean isLocalHandlerNameFor(String domain, + ObjectName handlerName) { + if (domain == null) return true; + return handlerName.getDomain().equals(domain) && + JMXDomain.TYPE_ASSIGNMENT.equals( + handlerName.getKeyPropertyListString()); + } + + @Override + void validateHandlerNameFor(String key, ObjectName name) { + super.validateHandlerNameFor(key,name); + final String[] domains = localNamespace.getDomains(); + for (int i=0;i postRegisterQueue) { + final DomainInterceptor ns = + new DomainInterceptor(mbeanServerName,handler,key); + ns.addPostRegisterTask(postRegisterQueue, delegate); + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("DomainInterceptor created: "+ns); + } + return ns; + } + + @Override + final void interceptorReleased(DomainInterceptor interceptor, + Queue postDeregisterQueue) { + interceptor.addPostDeregisterTask(postDeregisterQueue, delegate); + } + + @Override + final DefaultMBeanServerInterceptor getNextInterceptor() { + return localNamespace; + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + @Override + public String[] getDomains() { + // A JMXDomain is registered in its own domain. + // Therefore, localNamespace.getDomains() contains all domains. + // In addition, localNamespace will perform the necessary + // MBeanPermission checks for getDomains(). + // + return localNamespace.getDomains(); + } + + /** + * Returns the number of MBeans registered in the MBean server. + */ + @Override + public Integer getMBeanCount() { + int count = getNextInterceptor().getMBeanCount().intValue(); + final String[] keys = getKeys(); + for (String key:keys) { + final MBeanServer mbs = getInterceptor(key); + if (mbs == null) continue; + count += mbs.getMBeanCount().intValue(); + } + return Integer.valueOf(count); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java --- a/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,35 +25,14 @@ package com.sun.jmx.interceptor; -import java.util.Set; -// RI import -import javax.management.DynamicMBean; -import javax.management.AttributeNotFoundException; +import java.io.ObjectInputStream; +import javax.management.InstanceNotFoundException; import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.QueryExp; -import javax.management.NotificationListener; -import javax.management.NotificationFilter; -import javax.management.ListenerNotFoundException; -import javax.management.IntrospectionException; +import javax.management.MBeanServer; +import javax.management.ObjectName; import javax.management.OperationsException; -import javax.management.MBeanNotificationInfo; -import javax.management.JMRuntimeException; -import javax.management.InstanceNotFoundException; -import javax.management.NotCompliantMBeanException; -import javax.management.MBeanRegistrationException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InvalidAttributeValueException; -import javax.management.ObjectName; -import javax.management.ObjectInstance; -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.RuntimeOperationsException; -import javax.management.MBeanServerConnection; -import javax.management.MBeanServerDelegate; +import javax.management.ReflectionException; import javax.management.loading.ClassLoaderRepository; /** @@ -85,618 +64,67 @@ * * @since 1.5 */ -public interface MBeanServerInterceptor extends MBeanServerConnection { +public interface MBeanServerInterceptor extends MBeanServer { /** - * Instantiates and registers an MBean in the MBean server. The - * MBean server will use its {@link - * javax.management.loading.ClassLoaderRepository Default Loader - * Repository} to load the class of the MBean. An object name is - * associated to the MBean. If the object name given is null, the - * MBean must provide its own name by implementing the {@link - * javax.management.MBeanRegistration MBeanRegistration} interface - * and returning the name from the {@link - * javax.management.MBeanRegistration#preRegister preRegister} method. - * - * @param className The class name of the MBean to be instantiated. - * @param name The object name of the MBean. May be null. - * @param params An array containing the parameters of the - * constructor to be invoked. - * @param signature An array containing the signature of the - * constructor to be invoked. - * - * @return An ObjectInstance
, containing the - *ObjectName
and the Java class name of the newly - * instantiated MBean. - * - * @exception ReflectionException Wraps a - *java.lang.ClassNotFoundException
or a - *java.lang.Exception
that occurred when trying to - * invoke the MBean's constructor. - * @exception InstanceAlreadyExistsException The MBean is already - * under the control of the MBean server. - * @exception MBeanRegistrationException The - *preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The - * MBean will not be registered. - * @exception MBeanException The constructor of the MBean has - * thrown an exception - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The className - * passed in parameter is null, theObjectName
passed - * in parameter contains a pattern or noObjectName
- * is specified for the MBean. + * This method should never be called. + * Usually hrows UnsupportedOperationException. */ - public ObjectInstance createMBean(String className, ObjectName name, - Object params[], String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException; - + public Object instantiate(String className) + throws ReflectionException, MBeanException; /** - * Instantiates and registers an MBean in the MBean server. The - * class loader to be used is identified by its object name. An - * object name is associated to the MBean. If the object name of - * the loader is not specified, the ClassLoader that loaded the - * MBean server will be used. If the MBean object name given is - * null, the MBean must provide its own name by implementing the - * {@link javax.management.MBeanRegistration MBeanRegistration} - * interface and returning the name from the {@link - * javax.management.MBeanRegistration#preRegister preRegister} method. - * - * @param className The class name of the MBean to be instantiated. - * @param name The object name of the MBean. May be null. - * @param params An array containing the parameters of the - * constructor to be invoked. - * @param signature An array containing the signature of the - * constructor to be invoked. - * @param loaderName The object name of the class loader to be used. - * - * @return AnObjectInstance
, containing the - *ObjectName
and the Java class name of the newly - * instantiated MBean. - * - * @exception ReflectionException Wraps a - *java.lang.ClassNotFoundException
or a - *java.lang.Exception
that occurred when trying to - * invoke the MBean's constructor. - * @exception InstanceAlreadyExistsException The MBean is already - * under the control of the MBean server. - * @exception MBeanRegistrationException The - *preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The - * MBean will not be registered. - * @exception MBeanException The constructor of the MBean has - * thrown an exception - * @exception InstanceNotFoundException The specified class loader - * is not registered in the MBean server. - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The className - * passed in parameter is null, theObjectName
passed - * in parameter contains a pattern or noObjectName
- * is specified for the MBean. - * + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object params[], - String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException; - + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException; /** - * Registers a pre-existing object as an MBean with the MBean - * server. If the object name given is null, the MBean must - * provide its own name by implementing the {@link - * javax.management.MBeanRegistration MBeanRegistration} interface - * and returning the name from the {@link - * javax.management.MBeanRegistration#preRegister preRegister} method. - * - * @param object The MBean to be registered as an MBean. - * @param name The object name of the MBean. May be null. - * - * @return TheObjectInstance
for the MBean that has - * been registered. - * - * @exception InstanceAlreadyExistsException The MBean is already - * under the control of the MBean server. - * @exception MBeanRegistrationException The - *preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The - * MBean will not be registered. - * @exception NotCompliantMBeanException This object is not a JMX - * compliant MBean - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The object - * passed in parameter is null or no object name is specified. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException; + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException; /** - * Unregisters an MBean from the MBean server. The MBean is - * identified by its object name. Once the method has been - * invoked, the MBean may no longer be accessed by its object - * name. - * - * @param name The object name of the MBean to be unregistered. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception MBeanRegistrationException The preDeregister - * ((MBeanRegistration
interface) method of the MBean - * has thrown an exception. - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The object - * name in parameter is null or the MBean you are when trying to - * unregister is the {@link javax.management.MBeanServerDelegate - * MBeanServerDelegate} MBean. - * - */ - public void unregisterMBean(ObjectName name) - throws InstanceNotFoundException, MBeanRegistrationException; - - /** - * Gets theObjectInstance
for a given MBean - * registered with the MBean server. - * - * @param name The object name of the MBean. - * - * @return TheObjectInstance
associated to the MBean - * specified by name. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - */ - public ObjectInstance getObjectInstance(ObjectName name) - throws InstanceNotFoundException; - - /** - * Gets MBeans controlled by the MBean server. This method allows - * any of the following to be obtained: All MBeans, a set of - * MBeans specified by pattern matching on the - *ObjectName
and/or a Query expression, a specific - * MBean. When the object name is null or no domain and key - * properties are specified, all objects are to be selected (and - * filtered if a query is specified). It returns the set of - *ObjectInstance
objects (containing the - *ObjectName
and the Java Class name) for the - * selected MBeans. - * - * @param name The object name pattern identifying the MBeans to - * be retrieved. If null or no domain and key properties are - * specified, all the MBeans registered will be retrieved. - * @param query The query expression to be applied for selecting - * MBeans. If null no query expression will be applied for - * selecting MBeans. - * - * @return A set containing theObjectInstance
- * objects for the selected MBeans. If no MBean satisfies the - * query an empty list is returned. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public SetqueryMBeans(ObjectName name, QueryExp query); - - /** - * Gets the names of MBeans controlled by the MBean server. This - * method enables any of the following to be obtained: The names - * of all MBeans, the names of a set of MBeans specified by - * pattern matching on the ObjectName
and/or a Query - * expression, a specific MBean name (equivalent to testing - * whether an MBean is registered). When the object name is null - * or no domain and key properties are specified, all objects are - * selected (and filtered if a query is specified). It returns the - * set of ObjectNames for the MBeans selected. - * - * @param name The object name pattern identifying the MBean names - * to be retrieved. If null oror no domain and key properties are - * specified, the name of all registered MBeans will be retrieved. - * @param query The query expression to be applied for selecting - * MBeans. If null no query expression will be applied for - * selecting MBeans. - * - * @return A set containing the ObjectNames for the MBeans - * selected. If no MBean satisfies the query, an empty list is - * returned. - */ - public SetqueryNames(ObjectName name, QueryExp query); - - /** - * Checks whether an MBean, identified by its object name, is - * already registered with the MBean server. - * - * @param name The object name of the MBean to be checked. - * - * @return True if the MBean is already registered in the MBean - * server, false otherwise. - * - * @exception RuntimeOperationsException Wraps a - * java.lang.IllegalArgumentException
: The object - * name in parameter is null. - */ - public boolean isRegistered(ObjectName name); - - /** - * Returns the number of MBeans registered in the MBean server. - */ - public Integer getMBeanCount(); - - /** - * Gets the value of a specific attribute of a named MBean. The MBean - * is identified by its object name. - * - * @param name The object name of the MBean from which the - * attribute is to be retrieved. - * @param attribute A String specifying the name of the attribute - * to be retrieved. - * - * @return The value of the retrieved attribute. - * - * @exception AttributeNotFoundException The attribute specified - * is not accessible in the MBean. - * @exception MBeanException Wraps an exception thrown by the - * MBean's getter. - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception ReflectionException Wraps a - *java.lang.Exception
thrown when trying to invoke - * the setter. - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The object - * name in parameter is null or the attribute in parameter is - * null. - */ - public Object getAttribute(ObjectName name, String attribute) - throws MBeanException, AttributeNotFoundException, - InstanceNotFoundException, ReflectionException; - - /** - * Enables the values of several attributes of a named MBean. The MBean - * is identified by its object name. - * - * @param name The object name of the MBean from which the - * attributes are retrieved. - * @param attributes A list of the attributes to be retrieved. - * - * @return The list of the retrieved attributes. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception ReflectionException An exception occurred when - * trying to invoke the getAttributes method of a Dynamic MBean. - * @exception RuntimeOperationsException Wrap a - *java.lang.IllegalArgumentException
: The object - * name in parameter is null or attributes in parameter is null. - */ - public AttributeList getAttributes(ObjectName name, String[] attributes) - throws InstanceNotFoundException, ReflectionException; + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException; /** - * Sets the value of a specific attribute of a named MBean. The MBean - * is identified by its object name. - * - * @param name The name of the MBean within which the attribute is - * to be set. - * @param attribute The identification of the attribute to be set - * and the value it is to be set to. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception AttributeNotFoundException The attribute specified - * is not accessible in the MBean. - * @exception InvalidAttributeValueException The value specified - * for the attribute is not valid. - * @exception MBeanException Wraps an exception thrown by the - * MBean's setter. - * @exception ReflectionException Wraps a - *java.lang.Exception
thrown when trying to invoke - * the setter. - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The object - * name in parameter is null or the attribute in parameter is - * null. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void setAttribute(ObjectName name, Attribute attribute) - throws InstanceNotFoundException, AttributeNotFoundException, - InvalidAttributeValueException, MBeanException, - ReflectionException; - - - - /** - * Sets the values of several attributes of a named MBean. The MBean is - * identified by its object name. - * - * @param name The object name of the MBean within which the - * attributes are to be set. - * @param attributes A list of attributes: The identification of - * the attributes to be set and the values they are to be set to. - * - * @return The list of attributes that were set, with their new - * values. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception ReflectionException An exception occurred when - * trying to invoke the getAttributes method of a Dynamic MBean. - * @exception RuntimeOperationsException Wraps a - *java.lang.IllegalArgumentException
: The object - * name in parameter is null or attributes in parameter is null. - */ - public AttributeList setAttributes(ObjectName name, - AttributeList attributes) - throws InstanceNotFoundException, ReflectionException; + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException; /** - * Invokes an operation on an MBean. - * - * @param name The object name of the MBean on which the method is - * to be invoked. - * @param operationName The name of the operation to be invoked. - * @param params An array containing the parameters to be set when - * the operation is invoked - * @param signature An array containing the signature of the - * operation. The class objects will be loaded using the same - * class loader as the one used for loading the MBean on which the - * operation was invoked. - * - * @return The object returned by the operation, which represents - * the result ofinvoking the operation on the MBean specified. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - * @exception MBeanException Wraps an exception thrown by the - * MBean's invoked method. - * @exception ReflectionException Wraps a - *java.lang.Exception
thrown while trying to invoke - * the method. - */ - public Object invoke(ObjectName name, String operationName, - Object params[], String signature[]) - throws InstanceNotFoundException, MBeanException, - ReflectionException; - - /** - * Returns the default domain used for naming the MBean. - * The default domain name is used as the domain part in the ObjectName - * of MBeans if no domain is specified by the user. - */ - public String getDefaultDomain(); - - /** - * Returns the list of domains in which any MBean is currently - * registered. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public String[] getDomains(); - - /** - *Adds a listener to a registered MBean.
- * - *A notification emitted by an MBean will be forwarded by the - * MBeanServer to the listener. If the source of the notification - * is a reference to an MBean object, the MBean server will replace it - * by that MBean's ObjectName. Otherwise the source is unchanged. - * - * @param name The name of the MBean on which the listener should - * be added. - * @param listener The listener object which will handle the - * notifications emitted by the registered MBean. - * @param filter The filter object. If filter is null, no - * filtering will be performed before handling notifications. - * @param handback The context to be sent to the listener when a - * notification is emitted. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; - - - /** - *
Adds a listener to a registered MBean.
- * - *A notification emitted by an MBean will be forwarded by the - * MBeanServer to the listener. If the source of the notification - * is a reference to an MBean object, the MBean server will - * replace it by that MBean's ObjectName. Otherwise the source is - * unchanged.
- * - *The listener object that receives notifications is the one - * that is registered with the given name at the time this method - * is called. Even if it is subsequently unregistered, it will - * continue to receive notifications.
- * - * @param name The name of the MBean on which the listener should - * be added. - * @param listener The object name of the listener which will - * handle the notifications emitted by the registered MBean. - * @param filter The filter object. If filter is null, no - * filtering will be performed before handling notifications. - * @param handback The context to be sent to the listener when a - * notification is emitted. - * - * @exception InstanceNotFoundException The MBean name of the - * notification listener or of the notification broadcaster does - * not match any of the registered MBeans. - * @exception RuntimeOperationsException Wraps an {@link - * IllegalArgumentException}. The MBean named by - *listener
exists but does not implement the {@link - * NotificationListener} interface. - * @exception IOException A communication problem occurred when - * talking to the MBean server. - */ - public void addNotificationListener(ObjectName name, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException; /** - * Removes a listener from a registered MBean. - * - *If the listener is registered more than once, perhaps with - * different filters or callbacks, this method will remove all - * those registrations. - * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener The object name of the listener to be removed. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean. + * This method should never be called. + * Usually hrows UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - ObjectName listener) - throws InstanceNotFoundException, ListenerNotFoundException; - - /** - *
Removes a listener from a registered MBean.
- * - *The MBean must have a listener that exactly matches the - * given
- * - *listener
,filter
, and - *handback
parameters. If there is more than one - * such listener, only one is removed.The
- * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener A listener that was previously added to this - * MBean. - * @param filter The filter that was specified when the listener - * was added. - * @param handback The handback that was specified when the - * listener was added. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean, or it is not registered with the given - * filter and handback. - */ - public void removeNotificationListener(ObjectName name, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; - - - /** - *filter
andhandback
parameters - * may be null if and only if they are null in a listener to be - * removed.Removes a listener from a registered MBean.
- * - *If the listener is registered more than once, perhaps with - * different filters or callbacks, this method will remove all - * those registrations. - * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener The listener object which will handle the - * notifications emitted by the registered MBean. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean. - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException; /** - *
Removes a listener from a registered MBean.
- * - *The MBean must have a listener that exactly matches the - * given
- * - *listener
,filter
, and - *handback
parameters. If there is more than one - * such listener, only one is removed.The
- * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener A listener that was previously added to this - * MBean. - * @param filter The filter that was specified when the listener - * was added. - * @param handback The handback that was specified when the - * listener was added. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean, or it is not registered with the given - * filter and handback. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; - - /** - * This method discovers the attributes and operations that an - * MBean exposes for management. - * - * @param name The name of the MBean to analyze - * - * @return An instance offilter
andhandback
parameters - * may be null if and only if they are null in a listener to be - * removed.MBeanInfo
allowing the - * retrieval of all attributes and operations of this MBean. - * - * @exception IntrospectionException An exception occurred during - * introspection. - * @exception InstanceNotFoundException The MBean specified was - * not found. - * @exception ReflectionException An exception occurred when - * trying to invoke the getMBeanInfo of a Dynamic MBean. - */ - public MBeanInfo getMBeanInfo(ObjectName name) - throws InstanceNotFoundException, IntrospectionException, - ReflectionException; - - - /** - * Returns true if the MBean specified is an instance of the - * specified class, false otherwise. - * - * @param name TheObjectName
of the MBean. - * @param className The name of the class. - * - * @return true if the MBean specified is an instance of the - * specified class, false otherwise. - * - * @exception InstanceNotFoundException The MBean specified is not - * registered in the MBean server. - */ - public boolean isInstanceOf(ObjectName name, String className) - throws InstanceNotFoundException; - - /** - *Return the {@link java.lang.ClassLoader} that was used for - * loading the class of the named MBean. - * @param mbeanName The ObjectName of the MBean. - * @return The ClassLoader used for that MBean. - * @exception InstanceNotFoundException if the named MBean is not found. - */ - public ClassLoader getClassLoaderFor(ObjectName mbeanName) - throws InstanceNotFoundException; - - /** - *
Return the named {@link java.lang.ClassLoader}. - * @param loaderName The ObjectName of the ClassLoader. - * @return The named ClassLoader. - * @exception InstanceNotFoundException if the named ClassLoader is - * not found. - */ - public ClassLoader getClassLoader(ObjectName loaderName) - throws InstanceNotFoundException; + public ClassLoaderRepository getClassLoaderRepository(); } + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,127 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.interceptor; + +import java.io.ObjectInputStream; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.ReflectionException; +import javax.management.loading.ClassLoaderRepository; + +/** + * An abstract class for MBeanServerInterceptorSupport. + * Some methods in MBeanServerInterceptor should never be called. + * This base class provides an implementation of these methods that simply + * throw an {@link UnsupportedOperationException}. + *
+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class MBeanServerInterceptorSupport + implements MBeanServerInterceptor { + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public ClassLoaderRepository getClassLoaderRepository() { + throw new UnsupportedOperationException("Not applicable."); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java --- a/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1341 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ -package com.sun.jmx.interceptor; - -import com.sun.jmx.mbeanserver.Util; -import java.io.ObjectInputStream; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.AttributeNotFoundException; -import javax.management.DynamicMBean; -import javax.management.DynamicWrapperMBean; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.IntrospectionException; -import javax.management.InvalidAttributeValueException; -import javax.management.JMRuntimeException; -import javax.management.ListenerNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanInfo; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationEmitter; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; -import javax.management.ObjectInstance; -import javax.management.ObjectName; -import javax.management.OperationsException; -import javax.management.QueryEval; -import javax.management.QueryExp; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.loading.ClassLoaderRepository; - -/** - *Base class for custom implementations of the {@link MBeanServer} - * interface. The commonest use of this class is as the {@linkplain - * JMXNamespace#getSourceServer() source server} for a {@link - * JMXNamespace}, although this class can be used anywhere an {@code - * MBeanServer} instance is required. Note that the usual ways to - * obtain an {@code MBeanServer} instance are either to use {@link - * java.lang.management.ManagementFactory#getPlatformMBeanServer() - * ManagementFactory.getPlatformMBeanServer()} or to use the {@code - * newMBeanServer} or {@code createMBeanServer} methods from {@link - * javax.management.MBeanServerFactory MBeanServerFactory}. {@code - * MBeanServerSupport} is for certain cases where those are not - * appropriate.
- * - *There are two main use cases for this class: special-purpose MBeanServer implementations, - * and namespaces containing Virtual MBeans. The next - * sections explain these use cases.
- * - *In the simplest case, a subclass needs to implement only two methods:
- * - *- *
- * - *- - * {@link #getNames getNames} which returns the name of - * all MBeans handled by this {@code MBeanServer}. - *
- *- - * {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a - * {@link DynamicMBean} that can be used to invoke operations and - * obtain meta data (MBeanInfo) on a given MBean. - *
- *Subclasses can create such {@link DynamicMBean} MBeans on the fly - for - * instance, using the class {@link javax.management.StandardMBean}, just for - * the duration of an MBeanServer method call.
- * - *Special-purpose MBeanServer implementations
- * - *In some cases - * the general-purpose {@code MBeanServer} that you get from - * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not - * appropriate. You might need different security checks, or you might - * want a mock {@code MBeanServer} suitable for use in tests, or you might - * want a simplified and optimized {@code MBeanServer} for a special purpose.
- * - *As an example of a special-purpose {@code MBeanServer}, the class {@link - * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs - * an {@code MBeanServer} instance every time it filters a notification, - * with just one MBean that represents the notification. Although it could - * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code - * MBeanServer} will be quicker to create, use less memory, and have simpler - * methods that execute faster.
- * - *Here is an example of a special-purpose {@code MBeanServer} - * implementation that contains exactly one MBean, which is specified at the - * time of creation.
- * - *- * public class SingletonMBeanServer extends MBeanServerSupport { - * private final ObjectName objectName; - * private final DynamicMBean mbean; - * - * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) { - * this.objectName = objectName; - * this.mbean = mbean; - * } - * - * @Override - * protected {@code Set- * - *} {@link #getNames getNames}() { - * return Collections.singleton(objectName); - * } - * - * @Override - * public DynamicMBean {@link #getDynamicMBeanFor - * getDynamicMBeanFor}(ObjectName name) - * throws InstanceNotFoundException { - * if (objectName.equals(name)) - * return mbean; - * else - * throw new InstanceNotFoundException(name); - * } - * } - * Using this class, you could make an {@code MBeanServer} that contains - * a {@link javax.management.timer.Timer Timer} MBean like this:
- * - *- * Timer timer = new Timer(); - * DynamicMBean mbean = new {@link javax.management.StandardMBean - * StandardMBean}(timer, TimerMBean.class); - * ObjectName name = new ObjectName("com.example:type=Timer"); - * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean); - *- * - *When {@code getDynamicMBeanFor} always returns the same object for the - * same name, as here, notifications work in the expected way: if the object - * is a {@link NotificationEmitter} then listeners can be added using - * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) MBeanServer.addNotificationListener}. If - * {@code getDynamicMBeanFor} does not always return the same object for the - * same name, more work is needed to make notifications work, as described - * below.
- * - *Namespaces containing Virtual MBeans
- * - *Virtual MBeans are MBeans that do not exist as Java objects, - * except transiently while they are being accessed. This is useful when - * there might be very many of them, or when keeping track of their creation - * and deletion might be expensive or hard. For example, you might have one - * MBean per system process. With an ordinary {@code MBeanServer}, you would - * have to list the system processes in order to create an MBean object for - * each one, and you would have to track the arrival and departure of system - * processes in order to create or delete the corresponding MBeans. With - * Virtual MBeans, you only need the MBean for a given process at the exact - * point where it is referenced with a call such as - * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.
- * - *Here is an example of an {@code MBeanServer} implementation that has - * one MBean for every system property. The system property {@code "java.home"} - * is represented by the MBean called {@code - * com.example:type=Property,name="java.home"}, with an attribute called - * {@code Value} that is the value of the property.
- * - *- * public interface PropertyMBean { - * public String getValue(); - * } - * - * public class PropsMBS extends MBeanServerSupport { - * private static ObjectName newObjectName(String name) { - * try { - * return new ObjectName(name); - * } catch (MalformedObjectNameException e) { - * throw new AssertionError(e); - * } - * } - * - * public static class PropertyImpl implements PropertyMBean { - * private final String name; - * - * public PropertyImpl(String name) { - * this.name = name; - * } - * - * public String getValue() { - * return System.getProperty(name); - * } - * } - * - * @Override - * public DynamicMBean {@link #getDynamicMBeanFor - * getDynamicMBeanFor}(ObjectName name) - * throws InstanceNotFoundException { - * - * // Check that the name is a legal one for a Property MBean - * ObjectName namePattern = newObjectName( - * "com.example:type=Property,name=\"*\""); - * if (!namePattern.apply(name)) - * throw new InstanceNotFoundException(name); - * - * // Extract the name of the property that the MBean corresponds to - * String propName = ObjectName.unquote(name.getKeyProperty("name")); - * if (System.getProperty(propName) == null) - * throw new InstanceNotFoundException(name); - * - * // Construct and return a transient MBean object - * PropertyMBean propMBean = new PropertyImpl(propName); - * return new StandardMBean(propMBean, PropertyMBean.class, false); - * } - * - * @Override - * protected {@code Set- * - *} {@link #getNames getNames}() { - * {@code Set names = new TreeSet ();} - * Properties props = System.getProperties(); - * for (String propName : props.stringPropertyNames()) { - * ObjectName objectName = newObjectName( - * "com.example:type=Property,name=" + - * ObjectName.quote(propName)); - * names.add(objectName); - * } - * return names; - * } - * } - * Because the {@code getDynamicMBeanFor} method - * returns a different object every time it is called, the default handling - * of notifications will not work, as explained below. - * In this case it does not matter, because the object returned by {@code - * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link - * MBeanServer#addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) MBeanServer.addNotificationListener} will - * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean - * for property {@code "foo"} emitted a notification every time that property - * changed, we would need to do it as shown below. (Because there is no API to - * be informed when a property changes, this code assumes that some other code - * calls the {@code propertyChanged} method every time a property changes.)
- * - *- * public class PropsMBS { - * ...as above... - * - * private final {@link VirtualEventManager} vem = new VirtualEventManager(); - * - * @Override - * public NotificationEmitter {@link #getNotificationEmitterFor - * getNotificationEmitterFor}( - * ObjectName name) throws InstanceNotFoundException { - * getDynamicMBeanFor(name); // check that the name is valid - * return vem.{@link VirtualEventManager#getNotificationEmitterFor - * getNotificationEmitterFor}(name); - * } - * - * public void propertyChanged(String name, String newValue) { - * ObjectName objectName = newObjectName( - * "com.example:type=Property,name=" + ObjectName.quote(name)); - * Notification n = new Notification( - * "com.example.property.changed", objectName, 0L, - * "Property " + name + " changed"); - * n.setUserData(newValue); - * vem.{@link VirtualEventManager#publish publish}(objectName, n); - * } - * } - *- * - *MBean creation and deletion
- * - *MBean creation through {@code MBeanServer.createMBean} is disabled - * by default. Subclasses which need to support MBean creation - * through {@code createMBean} need to implement a single method {@link - * #createMBean(String, ObjectName, ObjectName, Object[], String[], - * boolean)}.
- * - *Similarly MBean registration and unregistration through {@code - * registerMBean} and {@code unregisterMBean} are disabled by default. - * Subclasses which need to support MBean registration and - * unregistration will need to implement {@link #registerMBean registerMBean} - * and {@link #unregisterMBean unregisterMBean}.
- * - *Notifications
- * - *By default {@link MBeanServer#addNotificationListener(ObjectName, - * NotificationListener, NotificationFilter, Object) addNotificationListener} - * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor - * getDynamicMBeanFor}
- * - *(name)
returns an object that is a - * {@link NotificationEmitter}. That is appropriate if - * {@code getDynamicMBeanFor}(name)
always returns the - * same object for the same {@code name}. But with - * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object, - * which is discarded as soon as the MBean request has finished. - * So a listener added to that object would be immediately forgotten.The simplest way for a subclass that defines Virtual MBeans - * to support notifications is to create a private {@link VirtualEventManager} - * and override the method {@link - * #getNotificationEmitterFor getNotificationEmitterFor} as follows:
- * - *- * private final VirtualEventManager vem = new VirtualEventManager(); - * - * @Override - * public NotificationEmitter getNotificationEmitterFor( - * ObjectName name) throws InstanceNotFoundException { - * // Check that the name is a valid Virtual MBean. - * // This is the easiest way to do that, but not always the - * // most efficient: - * getDynamicMBeanFor(name); - * - * // Return an object that supports add/removeNotificationListener - * // through the VirtualEventManager. - * return vem.getNotificationEmitterFor(name); - * } - *- * - *A notification {@code n} can then be sent from the Virtual MBean - * called {@code name} by calling {@link VirtualEventManager#publish - * vem.publish}
- * - * @since Java SE 7 - */ -public abstract class MBeanServerSupport implements MBeanServer { - - /** - * A logger for this class. - */ - private static final Logger LOG = - Logger.getLogger(MBeanServerSupport.class.getName()); - - /** - *(name, n)
. See the example - * above.Make a new {@code MBeanServerSupport} instance.
- */ - protected MBeanServerSupport() { - } - - /** - *Returns a dynamically created handle that makes it possible to - * access the named MBean for the duration of a method call.
- * - *An easy way to create such a {@link DynamicMBean} handle is, for - * instance, to create a temporary MXBean instance and to wrap it in - * an instance of - * {@link javax.management.StandardMBean}. - * This handle should remain valid for the duration of the call - * but can then be discarded.
- * @param name the name of the MBean for which a request was received. - * @return a {@link DynamicMBean} handle that can be used to invoke - * operations on the named MBean. - * @throws InstanceNotFoundException if no such MBean is supposed - * to exist. - */ - public abstract DynamicMBean getDynamicMBeanFor(ObjectName name) - throws InstanceNotFoundException; - - /** - *Subclasses should implement this method to return - * the names of all MBeans handled by this object instance.
- * - *The object returned by getNames() should be safely {@linkplain - * Set#iterator iterable} even in the presence of other threads that may - * cause the set of names to change. Typically this means one of the - * following:
- * - *- *
- * - * @return the names of all MBeans handled by this object. - */ - protected abstract Set- the returned set of names is always the same; or - *
- the returned set of names is an object such as a {@link - * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is - * safely iterable even if the set is changed by other threads; or - *
- a new Set is constructed every time this method is called. - *
getNames(); - - /** - * List names matching the given pattern. - * The default implementation of this method calls {@link #getNames()} - * and returns the subset of those names matching {@code pattern}.
- * - * @param pattern an ObjectName pattern - * @return the list of MBean names that match the given pattern. - */ - protected SetgetMatchingNames(ObjectName pattern) { - return Util.filterMatchingNames(pattern, getNames()); - } - - /** - * Returns a {@link NotificationEmitter} which can be used to - * subscribe or unsubscribe for notifications with the named - * mbean.
- * - *The default implementation of this method calls {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object - * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification - * handling.
- * - * @param name The name of the MBean whose notifications are being - * subscribed, or unsuscribed. - * - * @return A {@link NotificationEmitter} that can be used to subscribe or - * unsubscribe for notifications emitted by the named MBean, or {@code - * null} if the MBean does not emit notifications and should not be - * considered as a {@code NotificationEmitter}. - * - * @throws InstanceNotFoundException if {@code name} is not the name of - * an MBean in this {@code MBeanServer}. - */ - public NotificationEmitter getNotificationEmitterFor(ObjectName name) - throws InstanceNotFoundException { - DynamicMBean mbean = getDynamicMBeanFor(name); - if (mbean instanceof NotificationEmitter) - return (NotificationEmitter) mbean; - else - return null; - } - - private NotificationEmitter getNonNullNotificationEmitterFor( - ObjectName name) - throws InstanceNotFoundException { - NotificationEmitter emitter = getNotificationEmitterFor(name); - if (emitter == null) { - IllegalArgumentException iae = new IllegalArgumentException( - "Not a NotificationEmitter: " + name); - throw new RuntimeOperationsException(iae); - } - return emitter; - } - - /** - *Creates a new MBean in the MBean name space. - * This operation is not supported in this base class implementation.
- * The default implementation of this method always throws an {@link - * UnsupportedOperationException} - * wrapped in a {@link RuntimeOperationsException}. - * - *Subclasses may redefine this method to provide an implementation. - * All the various flavors of {@code MBeanServer.createMBean} methods - * will eventually call this method. A subclass that wishes to - * support MBean creation through {@code createMBean} thus only - * needs to provide an implementation for this one method. - * - * @param className The class name of the MBean to be instantiated. - * @param name The object name of the MBean. May be null. - * @param params An array containing the parameters of the - * constructor to be invoked. - * @param signature An array containing the signature of the - * constructor to be invoked. - * @param loaderName The object name of the class loader to be used. - * @param useCLR This parameter is {@code true} when this method - * is called from one of the {@code MBeanServer.createMBean} methods - * whose signature does not include the {@code ObjectName} of an - * MBean class loader to use for loading the MBean class. - * - * @return An
ObjectInstance
, containing the - *ObjectName
and the Java class name of the newly - * instantiated MBean. If the containedObjectName
- * isn
, the contained Java class name is - *{@link javax.management.MBeanServer#getMBeanInfo - * getMBeanInfo(n)}.getClassName()
. - * - * @exception ReflectionException Wraps a - *java.lang.ClassNotFoundException
or a - *java.lang.Exception
that occurred when trying to - * invoke the MBean's constructor. - * @exception InstanceAlreadyExistsException The MBean is already - * under the control of the MBean server. - * @exception MBeanRegistrationException The - *preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The - * MBean will not be registered. - * @exception MBeanException The constructor of the MBean has - * thrown an exception - * @exception NotCompliantMBeanException This class is not a JMX - * compliant MBean - * @exception InstanceNotFoundException The specified class loader - * is not registered in the MBean server. - * @exception RuntimeOperationsException Wraps either: - *- *
- */ - public ObjectInstance createMBean(String className, - ObjectName name, ObjectName loaderName, Object[] params, - String[] signature, boolean useCLR) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - throw newUnsupportedException("createMBean"); - } - - - /** - *- a
- *java.lang.IllegalArgumentException
: The className - * passed in parameter is null, theObjectName
passed in - * parameter contains a pattern or noObjectName
is specified - * for the MBean; or- an {@code UnsupportedOperationException} if creating MBeans is not - * supported by this {@code MBeanServer} implementation. - *
Attempts to determine whether the named MBean should be - * considered as an instance of a given class. The default implementation - * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to get an MBean object. Then its behaviour is the same as the standard - * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
- * - * {@inheritDoc} - */ - public boolean isInstanceOf(ObjectName name, String className) - throws InstanceNotFoundException { - - final DynamicMBean instance = nonNullMBeanFor(name); - - try { - final String mbeanClassName = instance.getMBeanInfo().getClassName(); - - if (mbeanClassName.equals(className)) - return true; - - final Object resource; - final ClassLoader cl; - if (instance instanceof DynamicWrapperMBean) { - DynamicWrapperMBean d = (DynamicWrapperMBean) instance; - resource = d.getWrappedObject(); - cl = d.getWrappedClassLoader(); - } else { - resource = instance; - cl = instance.getClass().getClassLoader(); - } - - final Class> classNameClass = Class.forName(className, false, cl); - - if (classNameClass.isInstance(resource)) - return true; - - if (classNameClass == NotificationBroadcaster.class || - classNameClass == NotificationEmitter.class) { - try { - getNotificationEmitterFor(name); - return true; - } catch (Exception x) { - LOG.finest("MBean " + name + - " is not a notification emitter. Ignoring: "+x); - return false; - } - } - - final Class> resourceClass = Class.forName(mbeanClassName, false, cl); - return classNameClass.isAssignableFrom(resourceClass); - } catch (Exception x) { - /* Could be SecurityException or ClassNotFoundException */ - LOG.logp(Level.FINEST, - MBeanServerSupport.class.getName(), - "isInstanceOf", "Exception calling isInstanceOf", x); - return false; - } - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns the string - * "DefaultDomain".
- */ - public String getDefaultDomain() { - return "DefaultDomain"; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns - * {@link #getNames()}.size().
- */ - public Integer getMBeanCount() { - return getNames().size(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method first calls {@link #getNames - * getNames()} to get a list of all MBean names, - * and from this set of names, derives the set of domains which contain - * MBeans.
- */ - public String[] getDomains() { - final Setnames = getNames(); - final Set res = new TreeSet (); - for (ObjectName n : names) { - if (n == null) continue; // not allowed but you never know. - res.add(n.getDomain()); - } - return res.toArray(new String[res.size()]); - } - - - /** - * {@inheritDoc} - * - * The default implementation of this method will first - * call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle - * to the named MBean, - * and then call {@link DynamicMBean#getAttribute getAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public Object getAttribute(ObjectName name, String attribute) - throws MBeanException, AttributeNotFoundException, - InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to obtain a handle to the named MBean, - * and then call {@link DynamicMBean#setAttribute setAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void setAttribute(ObjectName name, Attribute attribute) - throws InstanceNotFoundException, AttributeNotFoundException, - InvalidAttributeValueException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - mbean.setAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getAttributes getAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList getAttributes(ObjectName name, - String[] attributes) throws InstanceNotFoundException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#setAttributes setAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList setAttributes(ObjectName name, AttributeList attributes) - throws InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.setAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#invoke invoke} - * on that {@link DynamicMBean} handle.
- */ - public Object invoke(ObjectName name, String operationName, - Object[] params, String[] signature) - throws InstanceNotFoundException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.invoke(operationName, params, signature); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} - * on that {@link DynamicMBean} handle.
- */ - public MBeanInfo getMBeanInfo(ObjectName name) - throws InstanceNotFoundException, IntrospectionException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getMBeanInfo(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will call - * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the - * class name to combine with {@code name} to produce a new - * {@code ObjectInstance}.
- */ - public ObjectInstance getObjectInstance(ObjectName name) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(name); - final String className = mbean.getMBeanInfo().getClassName(); - return new ObjectInstance(name, className); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the - * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code - * isRegistered} will return true. If {@code getDynamicMBeanFor} returns - * null or throws {@link InstanceNotFoundException}, {@code isRegistered} - * will return false.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public boolean isRegistered(ObjectName name) { - try { - final DynamicMBean mbean = getDynamicMBeanFor(name); - return mbean!=null; - } catch (InstanceNotFoundException x) { - if (LOG.isLoggable(Level.FINEST)) - LOG.finest("MBean "+name+" is not registered: "+x); - return false; - } - } - - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #queryNames queryNames} - * to get a list of all matching MBeans, and then, for each returned name, - * call {@link #getObjectInstance getObjectInstance(name)}.
- */ - public SetqueryMBeans(ObjectName pattern, QueryExp query) { - final Set names = queryNames(pattern, query); - if (names.isEmpty()) return Collections.emptySet(); - final Set mbeans = new HashSet (); - for (ObjectName name : names) { - try { - mbeans.add(getObjectInstance(name)); - } catch (SecurityException x) { // DLS: OK - continue; - } catch (InstanceNotFoundException x) { // DLS: OK - continue; - } - } - return mbeans; - } - - /** - * {@inheritDoc} - * - * The default implementation of this method calls {@link #getMatchingNames - * getMatchingNames(pattern)} to obtain a list of MBeans matching - * the given name pattern. If the {@code query} parameter is null, - * this will be the result. Otherwise, it will evaluate the - * {@code query} parameter for each of the returned names, exactly - * as an {@code MBeanServer} would. This might result in - * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called - * several times for each returned name.
- */ - public SetqueryNames(ObjectName pattern, QueryExp query) { - try { - final Set res = getMatchingNames(pattern); - return filterListOfObjectNames(res, query); - } catch (Exception x) { - LOG.fine("Unexpected exception raised in queryNames: "+x); - LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x); - } - // We reach here only when an exception was raised. - // - return Collections.emptySet(); - } - - private final static boolean apply(final QueryExp query, - final ObjectName on, - final MBeanServer srv) { - boolean res = false; - MBeanServer oldServer = QueryEval.getMBeanServer(); - query.setMBeanServer(srv); - try { - res = query.apply(on); - } catch (Exception e) { - LOG.finest("QueryExp.apply threw exception, returning false." + - " Cause: "+e); - res = false; - } finally { - /* - * query.setMBeanServer is probably - * QueryEval.setMBeanServer so put back the old - * value. Since that method uses a ThreadLocal - * variable, this code is only needed for the - * unusual case where the user creates a custom - * QueryExp that calls a nested query on another - * MBeanServer. - */ - query.setMBeanServer(oldServer); - } - return res; - } - - /** - * Filters a {@code Set } according to a pattern and a query. - * This might be quite inefficient for virtual name spaces. - */ - Set - filterListOfObjectNames(Set list, - QueryExp query) { - if (list.isEmpty() || query == null) - return list; - - // create a new result set - final Set result = new HashSet (); - - for (ObjectName on : list) { - // if on doesn't match query exclude it. - if (apply(query, on, this)) - result.add(on); - } - return result; - } - - - // Don't use {@inheritDoc}, because we don't want to say that the - // MBeanServer replaces a reference to the MBean by its ObjectName. - /** - * Adds a listener to a registered MBean. A notification emitted by - * the MBean will be forwarded to the listener.
- * - *This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code addNotificationListener} on the - * {@link NotificationEmitter} it returns. - * - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) throws InstanceNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.addNotificationListener(listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - - /** - *
Adds a listener to a registered MBean.
- * - *The default implementation of this method first calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. - * If that successfully returns an object, call it {@code - * mbean}, then (a) if {@code mbean} is an instance of {@link - * NotificationListener} then this method calls {@link - * #addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) addNotificationListener(name, mbean, filter, - * handback)}, otherwise (b) this method throws an exception as specified - * for this case.
- * - *This default implementation is not appropriate for Virtual MBeans, - * although that only matters if the object returned by {@code - * getDynamicMBeanFor} can be an instance of - * {@code NotificationListener}.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void addNotificationListener(ObjectName name, ObjectName listenerName, - NotificationFilter filter, Object handback) - throws InstanceNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - addNotificationListener(name, listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener, filter, handback); - } - - private NotificationListener getListenerMBean(ObjectName listenerName) - throws InstanceNotFoundException { - Object mbean = getDynamicMBeanFor(listenerName); - if (mbean instanceof NotificationListener) - return (NotificationListener) mbean; - else { - throw newIllegalArgumentException( - "MBean is not a NotificationListener: " + listenerName); - } - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link InstanceNotFoundException} wrapping - * {@link UnsupportedOperationException}.
- * - * @return the default implementation of this method never returns. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ClassLoader getClassLoader(ObjectName loaderName) - throws InstanceNotFoundException { - final UnsupportedOperationException failed = - new UnsupportedOperationException("getClassLoader"); - final InstanceNotFoundException x = - new InstanceNotFoundException(String.valueOf(loaderName)); - x.initCause(failed); - throw x; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies - * the logic just described to the result.
- */ - public ClassLoader getClassLoaderFor(ObjectName mbeanName) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(mbeanName); - if (mbean instanceof DynamicWrapperMBean) - return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); - else - return mbean.getClass().getClassLoader(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns a - * {@link ClassLoaderRepository} containing exactly one loader, - * the {@linkplain Thread#getContextClassLoader() context class loader} - * for the current thread. - * Subclasses can override this method to return a different - * {@code ClassLoaderRepository}.
- */ - public ClassLoaderRepository getClassLoaderRepository() { - // We return a new ClassLoaderRepository each time this - // method is called. This is by design, because the - // SingletonClassLoaderRepository is a very small object and - // getClassLoaderRepository() will not be called very often - // (the connector server calls it once) - in the context of - // MBeanServerSupport there's a very good chance that this method will - // *never* be called. - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); - return Util.getSingleClassLoaderRepository(ccl); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException { - throw newUnsupportedException("registerMBean"); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void unregisterMBean(ObjectName name) - throws InstanceNotFoundException, MBeanRegistrationException { - throw newUnsupportedException("unregisterMBean"); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, params, signature, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, params, signature, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className,name, loaderName, params, signature, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, params, signature, false); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, null, null, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, null, null, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, loaderName, null, null, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, null, null, false); - } - - // make sure all exceptions are correctly wrapped in a JMXException - private ObjectInstance safeCreateMBean(String className, - ObjectName name, ObjectName loaderName, Object[] params, - String[] signature, boolean useRepository) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - try { - return createMBean(className, name, loaderName, params, - signature, useRepository); - } catch (ReflectionException x) { throw x; - } catch (InstanceAlreadyExistsException x) { throw x; - } catch (MBeanRegistrationException x) { throw x; - } catch (MBeanException x) { throw x; - } catch (NotCompliantMBeanException x) { throw x; - } catch (InstanceNotFoundException x) { throw x; - } catch (SecurityException x) { throw x; - } catch (JMRuntimeException x) { throw x; - } catch (RuntimeException x) { - throw new RuntimeOperationsException(x, x.toString()); - } catch (Exception x) { - throw new MBeanException(x, x.toString()); - } - } - - - /** - * {@inheritDoc} - * - *
This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className) - throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, Object[] params, - String[] signature) throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName, - Object[] params, String[] signature) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(ObjectName name, byte[] data) - throws InstanceNotFoundException, OperationsException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, byte[] data) - throws OperationsException, ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, - ObjectName loaderName, byte[] data) - throws InstanceNotFoundException, OperationsException, - ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - - // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException - // if the returned mbean is null. - // The DynamicMBean returned by this method is thus guaranteed to be - // non null. - // - private DynamicMBean nonNullMBeanFor(ObjectName name) - throws InstanceNotFoundException { - if (name == null) - throw newIllegalArgumentException("Null ObjectName"); - if (name.getDomain().equals("")) { - String defaultDomain = getDefaultDomain(); - try { - // XXX change to ObjectName.switchDomain - // current code DOES NOT PRESERVE the order of keys - name = new ObjectName(defaultDomain, name.getKeyPropertyList()); - } catch (Exception e) { - throw newIllegalArgumentException( - "Illegal default domain: " + defaultDomain); - } - } - final DynamicMBean mbean = getDynamicMBeanFor(name); - if (mbean!=null) return mbean; - throw new InstanceNotFoundException(String.valueOf(name)); - } - - static RuntimeException newUnsupportedException(String operation) { - return new RuntimeOperationsException( - new UnsupportedOperationException( - operation+": Not supported in this namespace")); - } - - static RuntimeException newIllegalArgumentException(String msg) { - return new RuntimeOperationsException( - new IllegalArgumentException(msg)); - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,236 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.interceptor; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.namespace.NamespaceInterceptor; + +import java.util.Queue; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.JMXNamespace; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +/** + * A dispatcher that dispatches to NamespaceInterceptors. + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class NamespaceDispatchInterceptor + extends DispatchInterceptor{ + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + private final DomainDispatchInterceptor localNamespace; + private final String serverName; + + /** + * Creates a NamespaceDispatchInterceptor with the specified + * repository instance. + * Do not forget to call
+ *initialize(outer,delegate)
+ * before using this object. + * + * @param outer A pointer to the MBeanServer object that must be + * passed to the MBeans when invoking their + * {@link javax.management.MBeanRegistration} interface. + * @param delegate A pointer to the MBeanServerDelegate associated + * with the new MBeanServer. The new MBeanServer must register + * this MBean in its MBean repository. + * @param instantiator The MBeanInstantiator that will be used to + * instantiate MBeans and take care of class loading issues. + * @param repository The repository to use for this MBeanServer + */ + public NamespaceDispatchInterceptor(MBeanServer outer, + MBeanServerDelegate delegate, + MBeanInstantiator instantiator, + Repository repository) { + localNamespace = new DomainDispatchInterceptor(outer,delegate, + instantiator,repository,this); + serverName = Util.getMBeanServerSecurityName(delegate); + } + + // TODO: Should move that to JMXNamespace? or to ObjectName? + /** + * Get first name space in ObjectName path. Ignore leading namespace + * separators. + **/ + public static String getFirstNamespace(ObjectName name) { + if (name == null) return ""; + final String domain = name.getDomain(); + if (domain.equals("")) return ""; + + int first = 0; + int end = domain.indexOf(NAMESPACE_SEPARATOR,first); + while (end == first) { + first = end+NAMESPACE_SEPARATOR_LENGTH; + end = domain.indexOf(NAMESPACE_SEPARATOR,first); + if (end == -1) break; + } + + if (end == -1) return ""; + + final String namespace = domain.substring(first,end); + + return namespace; + } + + /** + * Called by the DefaultMBeanServerInterceptor, just before adding an + * MBean to the repository. + * + * @param resource the MBean to be registered. + * @param logicalName the name of the MBean to be registered. + */ + final void checkLocallyRegistrable(Object resource, + ObjectName logicalName) { + if (!(resource instanceof JMXNamespace) && + logicalName.getDomain().contains(NAMESPACE_SEPARATOR)) + throw new IllegalArgumentException(String.valueOf(logicalName)+ + ": Invalid ObjectName for an instance of " + + resource.getClass().getName()); + } + + final boolean isLocalHandlerNameFor(String namespace, + ObjectName handlerName) { + return handlerName.getDomain().equals(namespace+NAMESPACE_SEPARATOR) && + JMXNamespace.TYPE_ASSIGNMENT.equals( + handlerName.getKeyPropertyListString()); + } + + @Override + final MBeanServer getInterceptorOrNullFor(ObjectName name) { + final String namespace = getFirstNamespace(name); + if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) || + name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { + LOG.finer("dispatching to local name space"); + return localNamespace; + } + final NamespaceInterceptor ns = getInterceptor(namespace); + if (LOG.isLoggable(Level.FINER)) { + if (ns != null) { + LOG.finer("dispatching to name space: " + namespace); + } else { + LOG.finer("no handler for: " + namespace); + } + } + return ns; + } + + @Override + final QueryInterceptor getInterceptorForQuery(ObjectName pattern) { + final String namespace = getFirstNamespace(pattern); + if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) || + pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { + LOG.finer("dispatching to local name space"); + return new QueryInterceptor(localNamespace); + } + final NamespaceInterceptor ns = getInterceptor(namespace); + if (LOG.isLoggable(Level.FINER)) { + if (ns != null) { + LOG.finer("dispatching to name space: " + namespace); + } else { + LOG.finer("no handler for: " + namespace); + } + } + if (ns == null) return null; + return new QueryInterceptor(ns); + } + + @Override + final ObjectName getHandlerNameFor(String key) + throws MalformedObjectNameException { + return ObjectName.getInstance(key+NAMESPACE_SEPARATOR, + "type", JMXNamespace.TYPE); + } + + @Override + final public String getHandlerKey(ObjectName name) { + return getFirstNamespace(name); + } + + @Override + final NamespaceInterceptor createInterceptorFor(String key, + ObjectName name, JMXNamespace handler, + QueuepostRegisterQueue) { + final NamespaceInterceptor ns = + new NamespaceInterceptor(serverName,handler,key); + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("NamespaceInterceptor created: "+ns); + } + return ns; + } + + @Override + final DomainDispatchInterceptor getNextInterceptor() { + return localNamespace; + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + @Override + public String[] getDomains() { + return localNamespace.getDomains(); + } + + @Override + public void addNamespace(ObjectName name, JMXNamespace handler, + Queue postRegisterQueue) { + if (handler instanceof JMXDomain) + localNamespace.addNamespace(name, + (JMXDomain)handler,postRegisterQueue); + else super.addNamespace(name,handler,postRegisterQueue); + } + + @Override + public void removeNamespace(ObjectName name, JMXNamespace handler, + Queue postDeregisterQueue) { + if (handler instanceof JMXDomain) + localNamespace.removeNamespace(name,(JMXDomain)handler, + postDeregisterQueue); + else super.removeNamespace(name,handler,postDeregisterQueue); + } + + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java --- a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java Wed Jul 05 16:41:30 2017 +0200 @@ -51,6 +51,8 @@ import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; import javax.management.remote.IdentityMBeanServerForwarder; public class SingleMBeanForwarder extends IdentityMBeanServerForwarder { @@ -285,14 +287,14 @@ if (!pattern.apply(mbeanName)) return false; -// final String dompat = pattern.getDomain(); -// if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) -// return true; // We already checked that patterns apply. -// -// if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { -// // only matches if pattern ends with // -// return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR); -// } + final String dompat = pattern.getDomain(); + if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + return true; // We already checked that patterns apply. + + if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { + // only matches if pattern ends with // + return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR); + } // should not come here, unless mbeanName contains a // in the // middle of its domain, which would be weird. diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,44 +25,42 @@ package com.sun.jmx.mbeanserver; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.Set; +import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; +import com.sun.jmx.interceptor.NamespaceDispatchInterceptor; + import java.io.ObjectInputStream; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedExceptionAction; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Level; -// RI import -import javax.management.MBeanPermission; -import javax.management.AttributeNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.MBeanInfo; -import javax.management.QueryExp; -import javax.management.NotificationListener; -import javax.management.NotificationFilter; -import javax.management.ListenerNotFoundException; -import javax.management.IntrospectionException; -import javax.management.OperationsException; -import javax.management.InstanceNotFoundException; -import javax.management.NotCompliantMBeanException; -import javax.management.MBeanRegistrationException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InvalidAttributeValueException; -import javax.management.ObjectName; -import javax.management.ObjectInstance; import javax.management.Attribute; import javax.management.AttributeList; -import javax.management.RuntimeOperationsException; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanPermission; +import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; import javax.management.loading.ClassLoaderRepository; -import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; -import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor; -import com.sun.jmx.interceptor.MBeanServerInterceptor; - /** * This is the base class for MBean manipulation on the agent side. It * contains the methods necessary for the creation, registration, and @@ -102,15 +100,14 @@ /** true if interceptors are enabled **/ private final boolean interceptorsEnabled; - /** Revisit: transient ??? **/ - private final transient MBeanServer outerShell; + private final MBeanServer outerShell; + + private volatile MBeanServer mbsInterceptor = null; - /** Revisit: transient ??? **/ - private transient MBeanServerInterceptor mbsInterceptor = null; + /** The MBeanServerDelegate object representing the MBean Server */ + private final MBeanServerDelegate mBeanServerDelegateObject; - /** Revisit: transient ??? **/ - /** The MBeanServerDelegate object representing the MBean Server */ - private final transient MBeanServerDelegate mBeanServerDelegateObject; + private final String mbeanServerName; /** * Package: Creates an MBeanServer with the @@ -243,9 +240,10 @@ final Repository repository = new Repository(domain,fairLock); this.mbsInterceptor = - new DefaultMBeanServerInterceptor(outer, delegate, instantiator, + new NamespaceDispatchInterceptor(outer, delegate, instantiator, repository); this.interceptorsEnabled = interceptors; + this.mbeanServerName = Util.getMBeanServerSecurityName(delegate); initialize(); } @@ -941,7 +939,8 @@ throws ReflectionException, MBeanException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, null, + "instantiate"); return instantiator.instantiate(className); } @@ -978,7 +977,8 @@ InstanceNotFoundException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, + null, "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className, loaderName, myLoader); @@ -1016,7 +1016,8 @@ throws ReflectionException, MBeanException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, null, + "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className, params, signature, @@ -1059,7 +1060,8 @@ InstanceNotFoundException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, + null, "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className,loaderName,params,signature, @@ -1236,7 +1238,7 @@ "Unexpected exception occurred", e); } throw new - IllegalStateException("Can't register delegate."); + IllegalStateException("Can't register delegate.",e); } @@ -1278,7 +1280,7 @@ * are not enabled on this object. * @see #interceptorsEnabled **/ - public synchronized MBeanServerInterceptor getMBeanServerInterceptor() { + public synchronized MBeanServer getMBeanServerInterceptor() { if (interceptorsEnabled) return mbsInterceptor; else throw new UnsupportedOperationException( "MBeanServerInterceptors are disabled."); @@ -1292,7 +1294,7 @@ * @see #interceptorsEnabled **/ public synchronized void - setMBeanServerInterceptor(MBeanServerInterceptor interceptor) { + setMBeanServerInterceptor(MBeanServer interceptor) { if (!interceptorsEnabled) throw new UnsupportedOperationException( "MBeanServerInterceptors are disabled."); if (interceptor == null) throw new @@ -1330,7 +1332,8 @@ **/ public ClassLoaderRepository getClassLoaderRepository() { /* Permission check */ - checkMBeanPermission(null, null, null, "getClassLoaderRepository"); + checkMBeanPermission(mbeanServerName, null, null, + null, "getClassLoaderRepository"); return secureClr; } @@ -1484,14 +1487,16 @@ // SECURITY CHECKS //---------------- - private static void checkMBeanPermission(String classname, + private static void checkMBeanPermission(String serverName, + String classname, String member, ObjectName objectName, String actions) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - Permission perm = new MBeanPermission(classname, + Permission perm = new MBeanPermission(serverName, + classname, member, objectName, actions); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java Wed Jul 05 16:41:30 2017 +0200 @@ -224,7 +224,7 @@ throws InvalidObjectException { String domain = prefix + name.getDomain(); try { - name = switchDomain(domain, name); + name = name.withDomain(domain); } catch (MalformedObjectNameException e) { throw EnvHelp.initCause( new InvalidObjectException(e.getMessage()), e); @@ -242,7 +242,7 @@ "Proxy's name does not start with " + prefix + ": " + name); } try { - name = switchDomain(domain.substring(prefix.length()), name); + name = name.withDomain(domain.substring(prefix.length())); } catch (MalformedObjectNameException e) { throw EnvHelp.initCause(new OpenDataException(e.getMessage()), e); } @@ -269,14 +269,6 @@ currentLookup.set(lookup); } - // Method temporarily added until we have ObjectName.switchDomain in the - // public API. Note that this method DOES NOT PRESERVE the order of - // keys in the ObjectName so it must not be used in the final release. - static ObjectName switchDomain(String domain, ObjectName name) - throws MalformedObjectNameException { - return new ObjectName(domain, name.getKeyPropertyList()); - } - private static final ThreadLocal currentLookup = new ThreadLocal (); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Wed Jul 05 16:41:30 2017 +0200 @@ -45,7 +45,6 @@ import javax.management.RuntimeOperationsException; /** - * The RepositorySupport implements the Repository interface. * This repository does not support persistency. * * @since 1.5 @@ -197,9 +196,9 @@ if (isPropertyValuePattern && pattern.isPropertyValuePattern(keys[i])) { // wildmatch key property values - final char[] val_pattern = values[i].toCharArray(); - final char[] val_string = v.toCharArray(); - if (wildmatch(val_string,val_pattern)) + // values[i] is the pattern; + // v is the string + if (Util.wildmatch(v,values[i])) continue; else return false; @@ -236,86 +235,6 @@ } } - /** Match a string against a shell-style pattern. The only pattern - characters recognised are ?
, standing for any one - character, and*
, standing for any string of - characters, including the empty string. - - @param str the string to match, as a character array. - @param pat the pattern to match the string against, as a - character array. - - @return true if and only if the string matches the pattern. - */ - /* The algorithm is a classical one. We advance pointers in - parallel through str and pat. If we encounter a star in pat, - we remember its position and continue advancing. If at any - stage we get a mismatch between str and pat, we look to see if - there is a remembered star. If not, we fail. If so, we - retreat pat to just past that star and str to the position - after the last one we tried, and we let the match advance - again. - - Even though there is only one remembered star position, the - algorithm works when there are several stars in the pattern. - When we encounter the second star, we forget the first one. - This is OK, because if we get to the second star in A*B*C - (where A etc are arbitrary strings), we have already seen AXB. - We're therefore setting up a match of *C against the remainder - of the string, which will match if that remainder looks like - YC, so the whole string looks like AXBYC. - */ - public static boolean wildmatch(char[] str, char[] pat) { - int stri; // index in str - int pati; // index in pat - int starstri; // index for backtrack if "*" attempt fails - int starpati; // index for backtrack if "*" attempt fails, +1 - final int strlen = str.length; - final int patlen = pat.length; - - stri = pati = 0; - starstri = starpati = -1; - - /* On each pass through this loop, we either advance pati, - or we backtrack pati and advance starstri. Since starstri - is only ever assigned from pati, the loop must terminate. */ - while (true) { - if (pati < patlen) { - final char patc = pat[pati]; - switch (patc) { - case '?': - if (stri == strlen) - break; - stri++; - pati++; - continue; - case '*': - pati++; - starpati = pati; - starstri = stri; - continue; - default: - if (stri < strlen && str[stri] == patc) { - stri++; - pati++; - continue; - } - break; - } - } else if (stri == strlen) - return true; - - // Mismatched, can we backtrack to a "*"? - if (starpati < 0 || starstri == strlen) - return false; - - // Retry the match one position later in str - pati = starpati; - starstri++; - stri = starstri; - } - } - private void addNewDomMoi(final DynamicMBean object, final String dom, final ObjectName name, @@ -370,7 +289,7 @@ if (name.isPattern()) return null; // Extract the domain name. - String dom= name.getDomain().intern(); + String dom = name.getDomain().intern(); // Default domain case if (dom.length() == 0) { @@ -480,7 +399,7 @@ name = Util.newObjectName(domain + name.toString()); // Do we have default domain ? - if (dom == domain) { + if (dom == domain) { // ES: OK (dom & domain are interned) to_default_domain = true; dom = domain; } else { @@ -652,10 +571,9 @@ } // Pattern matching in the domain name (*, ?) - char[] dom2Match = name.getDomain().toCharArray(); + final String dom2Match = name.getDomain(); for (String dom : domainTb.keySet()) { - char[] theDom = dom.toCharArray(); - if (wildmatch(theDom, dom2Match)) { + if (Util.wildpathmatch(dom, dom2Match)) { final MapmoiTb = domainTb.get(dom); if (allNames) result.addAll(moiTb.values()); @@ -726,7 +644,7 @@ // need to reinstantiate a hashtable because of possible // big buckets array size inside table, never cleared, // thus the new ! - if (dom == domain) + if (dom == domain) // ES: OK dom and domain are interned. domainTb.put(domain, new HashMap ()); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java Wed Jul 05 16:41:30 2017 +0200 @@ -28,17 +28,16 @@ import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; -import com.sun.jmx.interceptor.MBeanServerInterceptor; /** - * Extends the MBeanServer and MBeanServerInterceptor interface to + * Extends the MBeanServer interface to * provide methods for getting the MetaData and MBeanServerInstantiator * objects associated with an MBeanServer. * * @since 1.5 */ public interface SunJmxMBeanServer - extends MBeanServerInterceptor, MBeanServer { + extends MBeanServer { /** * Return the MBeanInstantiator associated to this MBeanServer. @@ -68,7 +67,7 @@ * are not enabled on this object. * @see #interceptorsEnabled **/ - public MBeanServerInterceptor getMBeanServerInterceptor(); + public MBeanServer getMBeanServerInterceptor(); /** * Set the MBeanServerInterceptor. @@ -77,7 +76,7 @@ * are not enabled on this object. * @see #interceptorsEnabled **/ - public void setMBeanServerInterceptor(MBeanServerInterceptor interceptor); + public void setMBeanServerInterceptor(MBeanServer interceptor); /** * Return the MBeanServerDelegate representing the MBeanServer. diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,6 +25,8 @@ package com.sun.jmx.mbeanserver; +import com.sun.jmx.defaults.JmxProperties; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -42,11 +44,22 @@ import java.util.TreeMap; import java.util.TreeSet; import java.util.WeakHashMap; +import java.util.logging.Level; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.loading.ClassLoaderRepository; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; public class Util { + private final static int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?"; + + static
+ * @since 1.7 + */ +public abstract class HandlerInterceptorMap newMap() { return new HashMap (); } @@ -145,6 +158,270 @@ return hash; } + /** Match a part of a string against a shell-style pattern. + The only pattern characters recognized are ?
, + standing for any one character, + and*
, standing for any string of + characters, including the empty string. For instance, + {@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match + {@code "and"} against {@code "a?d"}. + + @param str the string containing the sequence to match. + @param pat a string containing a pattern to match the sub string + against. + @param stri the index in the string at which matching should begin. + @param strend the index in the string at which the matching should + end. + @param pati the index in the pattern at which matching should begin. + @param patend the index in the pattern at which the matching should + end. + + @return true if and only if the string matches the pattern. + */ + /* The algorithm is a classical one. We advance pointers in + parallel through str and pat. If we encounter a star in pat, + we remember its position and continue advancing. If at any + stage we get a mismatch between str and pat, we look to see if + there is a remembered star. If not, we fail. If so, we + retreat pat to just past that star and str to the position + after the last one we tried, and we let the match advance + again. + + Even though there is only one remembered star position, the + algorithm works when there are several stars in the pattern. + When we encounter the second star, we forget the first one. + This is OK, because if we get to the second star in A*B*C + (where A etc are arbitrary strings), we have already seen AXB. + We're therefore setting up a match of *C against the remainder + of the string, which will match if that remainder looks like + YC, so the whole string looks like AXBYC. + */ + private static boolean wildmatch(final String str, final String pat, + int stri, final int strend, int pati, final int patend) { + + // System.out.println("matching "+pat.substring(pati,patend)+ + // " against "+str.substring(stri, strend)); + int starstri; // index for backtrack if "*" attempt fails + int starpati; // index for backtrack if "*" attempt fails, +1 + + starstri = starpati = -1; + + /* On each pass through this loop, we either advance pati, + or we backtrack pati and advance starstri. Since starstri + is only ever assigned from pati, the loop must terminate. */ + while (true) { + if (pati < patend) { + final char patc = pat.charAt(pati); + switch (patc) { + case '?': + if (stri == strend) + break; + stri++; + pati++; + continue; + case '*': + pati++; + starpati = pati; + starstri = stri; + continue; + default: + if (stri < strend && str.charAt(stri) == patc) { + stri++; + pati++; + continue; + } + break; + } + } else if (stri == strend) + return true; + + // Mismatched, can we backtrack to a "*"? + if (starpati < 0 || starstri == strend) + return false; + + // Retry the match one position later in str + pati = starpati; + starstri++; + stri = starstri; + } + } + + /** Match a string against a shell-style pattern. The only pattern + characters recognized are?
, standing for any one + character, and*
, standing for any string of + characters, including the empty string. + + @param str the string to match. + @param pat the pattern to match the string against. + + @return true if and only if the string matches the pattern. + */ + public static boolean wildmatch(String str, String pat) { + return wildmatch(str,pat,0,str.length(),0,pat.length()); + } + + /** + * Matches a string against a pattern, as a name space path. + * This is a special matching where * and ?? don't match //. + * The string is split in sub-strings separated by //, and the + * pattern is split in sub-patterns separated by //. Each sub-string + * is matched against its corresponding sub-pattern. + * so// //...// matches // //...// + * only if n==q and for ( i = 1 => n) elt-i matches pat-i. + * + * In addition, if we encounter a pattern element which is exactly + * **, it can match any number of path-elements - but it must match at + * least one element. + * When we encounter such a meta-wildcard, we remember its position + * and the position in the string path, and we advance both the pattern + * and the string. Later, if we encounter a mismatch in pattern & string, + * we rewind the position in pattern to just after the meta-wildcard, + * and we backtrack the string to i+1 element after the position + * we had when we first encountered the meta-wildcard, i being the + * position when we last backtracked the string. + * + * The backtracking logic is an adaptation of the logic in wildmatch + * above. + * See test/javax/mangement/ObjectName/ApplyWildcardTest.java + * + * Note: this thing is called 'wild' - and that's for a reason ;-) + **/ + public static boolean wildpathmatch(String str, String pat) { + final int strlen = str.length(); + final int patlen = pat.length(); + int stri = 0; + int pati = 0; + + int starstri; // index for backtrack if "**" attempt fails + int starpati; // index for backtrack if "**" attempt fails + + starstri = starpati = -1; + + while (true) { + // System.out.println("pati="+pati+", stri="+stri); + final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri); + final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati); + + // no // remaining in either string or pattern: simple wildmatch + // until end of string. + if (strend == -1 && patend == -1) { + // System.out.println("last sub pattern, last sub element..."); + // System.out.println("wildmatch("+str.substring(stri,strlen)+ + // ","+pat.substring(pati,patlen)+")"); + return wildmatch(str,pat,stri,strlen,pati,patlen); + } + + // no // remaining in string, but at least one remaining in + // pattern + // => no match + if (strend == -1) { + // System.out.println("pattern has more // than string..."); + return false; + } + + // strend is != -1, but patend might. + // detect wildcard ** + if (patend == pati+2 && pat.charAt(pati)=='*' && + pat.charAt(pati+1)=='*') { + // if we reach here we know that neither strend nor patend are + // equals to -1. + stri = strend + NAMESPACE_SEPARATOR_LENGTH; + pati = patend + NAMESPACE_SEPARATOR_LENGTH; + starpati = pati; // position just after **// in pattern + starstri = stri; // we eat 1 element in string, and remember + // the position for backtracking and eating + // one more element if needed. + // System.out.println("starpati="+pati); + continue; + } + + // This is a bit hacky: * can match // when // is at the end + // of the string, so we include the // delimiter in the pattern + // matching. Either we're in the middle of the path, so including + // // both at the end of the pattern and at the end of the string + // has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd) + // or we're at the end of the pattern path, in which case + // including // at the end of the string will have the desired + // effect (provided that we detect the end of matching correctly, + // see further on). + // + final int endpat = + ((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen); + final int endstr = + ((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen); + + // if we reach the end of the pattern, or if elt-i & pat-i + // don't match, we have a mismatch. + + // Note: we know that strend != -1, therefore patend==-1 + // indicates a mismatch unless pattern can match + // a // at the end, and strend+2=strlen. + // System.out.println("wildmatch("+str.substring(stri,endstr)+","+ + // pat.substring(pati,endpat)+")"); + if (!wildmatch(str,pat,stri,endstr,pati,endpat)) { + + // System.out.println("nomatch"); + // if we have a mismatch and didn't encounter any meta-wildcard, + // we return false. String & pattern don't match. + if (starpati < 0) return false; + + // If we reach here, we had a meta-wildcard. + // We need to backtrack to the wildcard, and make it eat an + // additional string element. + // + stri = str.indexOf(NAMESPACE_SEPARATOR, starstri); + // System.out.println("eating one additional element? "+stri); + + // If there's no more elements to eat, string and pattern + // don't match => return false. + if (stri == -1) return false; + + // Backtrack to where we were when we last matched against + // the meta-wildcard, make it eat an additional path element, + // remember the new positions, and continue from there... + // + stri = stri + NAMESPACE_SEPARATOR_LENGTH; + starstri = stri; + pati = starpati; + // System.out.println("skiping to stri="+stri); + continue; + } + + // Here we know that strend > -1 but we can have patend == -1. + // + // So if we reach here, we know pat-i+//? has matched + // elt-i+// + // + // If patend==-1, we know that there was no delimiter + // at the end of the pattern, that we are at the last pattern, + // and therefore that pat-i has matched elt-i+// + // + // In that case we can consider that we have a match only if + // elt-i is also the last path element in the string, which is + // equivalent to saying that strend+2==strlen. + // + if (patend == -1 && starpati == -1) + return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen); + + // patend != -1, or starpati > -1 so there remains something + // to match. + + // go to next pair: elt-(i+1) pat-(i+1); + stri = strend + NAMESPACE_SEPARATOR_LENGTH; + pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH); + } + } + + /** + * Returns true if the ObjectName's {@code domain} is selected by the + * given {@code pattern}. + */ + public static boolean isDomainSelected(String domain, String pattern) { + if (domain == null || pattern == null) + throw new IllegalArgumentException("null"); + return Util.wildpathmatch(domain,pattern); + } + /** * Filters a set of ObjectName according to a given pattern. * @@ -167,6 +444,34 @@ return res; } + + /** + * Filters a set of ObjectInstance according to a given pattern. + * + * @param pattern the pattern that the returned names must match. + * @param all the set of instances to filter. + * @return a set of ObjectInstance from which non matching instances + * have been removed. + */ + public static Set + filterMatchingInstances(ObjectName pattern, + Set all) { + // If no pattern, just return all names + if (pattern == null + || all.isEmpty() + || ObjectName.WILDCARD.equals(pattern)) + return all; + + // If there's a pattern, do the matching. + final Set res = equivalentEmptySet(all); + for (ObjectInstance n : all) { + if (n == null) continue; + if (pattern.apply(n.getObjectName())) + res.add(n); + } + return res; + } + /** * An abstract ClassLoaderRepository that contains a single class loader. **/ @@ -216,6 +521,160 @@ return new SingleClassLoaderRepository(loader); } + /** + * Returns the name of the given MBeanServer that should be put in a + * permission you need. + * This corresponds to the + * {@code *[;mbeanServerName= [;*]]} property + * embedded in the MBeanServerId attribute of the + * server's {@link MBeanServerDelegate}. + * + * @param server The MBean server + * @return the name of the MBeanServer, or "*" if the name couldn't be + * obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} + * if there was no name. + */ + public static String getMBeanServerSecurityName(MBeanServer server) { + final String notfound = "*"; + try { + final String mbeanServerId = (String) + server.getAttribute(MBeanServerDelegate.DELEGATE_NAME, + "MBeanServerId"); + final String found = extractMBeanServerName(mbeanServerId); + if (found.length()==0) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return found; + } catch (Exception x) { + logshort("Failed to retrieve MBeanServerName for server, " + + "using \"*\"",x); + return notfound; + } + } + + /** + * Returns the name of the MBeanServer embedded in the given + * mbeanServerId. If the given mbeanServerId doesn't contain any name, + * an empty String is returned. + * The MBeanServerId is expected to be of the form: + * {@code *[;mbeanServerName= [;*]]} + * @param mbeanServerId The MBean server ID + * @return the name of the MBeanServer if found, or "" if the name was + * not present in the mbeanServerId. + */ + public static String extractMBeanServerName(String mbeanServerId) { + if (mbeanServerId==null) return ""; + final String beginMarker=";mbeanServerName="; + final String endMarker=";"; + final int found = mbeanServerId.indexOf(beginMarker); + if (found < 0) return ""; + final int start = found + beginMarker.length(); + final int stop = mbeanServerId.indexOf(endMarker, start); + return mbeanServerId.substring(start, + (stop < 0 ? mbeanServerId.length() : stop)); + } + + /** + * Insert the given mbeanServerName into the given mbeanServerId. + * If mbeanServerName is null, empty, or equals to "-", the returned + * mbeanServerId will not contain any mbeanServerName. + * @param mbeanServerId The mbeanServerId in which to insert + * mbeanServerName + * @param mbeanServerName The mbeanServerName + * @return an mbeanServerId containing the given mbeanServerName + * @throws IllegalArgumentException if mbeanServerId already contains + * a different name, or if the given mbeanServerName is not valid. + */ + public static String insertMBeanServerName(String mbeanServerId, + String mbeanServerName) { + final String found = extractMBeanServerName(mbeanServerId); + if (found.length() > 0 && + found.equals(checkServerName(mbeanServerName))) + return mbeanServerId; + if (found.length() > 0 && !isMBeanServerNameUndefined(found)) + throw new IllegalArgumentException( + "MBeanServerName already defined"); + if (isMBeanServerNameUndefined(mbeanServerName)) + return mbeanServerId; + final String beginMarker=";mbeanServerName="; + return mbeanServerId+beginMarker+checkServerName(mbeanServerName); + } + + /** + * Returns true if the given mbeanServerName corresponds to an + * undefined MBeanServerName. + * The mbeanServerName is considered undefined if it is one of: + * {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}. + * @param mbeanServerName The mbeanServerName, as returned by + * {@link #extractMBeanServerName(String)}. + * @return true if the given name corresponds to one of the forms that + * denotes an undefined MBeanServerName. + */ + public static boolean isMBeanServerNameUndefined(String mbeanServerName) { + return mbeanServerName == null || + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName); + } + /** + * Check that the provided mbeanServername is syntactically valid. + * @param mbeanServerName An mbeanServerName, or {@code null}. + * @return mbeanServerName, or {@value + * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName} + * is {@code null}. + * @throws IllegalArgumentException if mbeanServerName contains illegal + * characters, or is empty, or is {@code "-"}. + * Illegal characters are {@value #ILLEGAL_MBEANSERVER_NAME_CHARS}. + */ + public static String checkServerName(String mbeanServerName) { + if ("".equals(mbeanServerName)) + throw new IllegalArgumentException( + "\"\" is not a valid MBean server name"); + if ("-".equals(mbeanServerName)) + throw new IllegalArgumentException( + "\"-\" is not a valid MBean server name"); + if (isMBeanServerNameUndefined(mbeanServerName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS.toCharArray()) { + if (mbeanServerName.indexOf(c) >= 0) + throw new IllegalArgumentException( + "invalid character in MBeanServer name: "+c); + } + return mbeanServerName; + } + + /** + * Get the MBeanServer name that should be put in a permission you need. + * + * @param delegate The MBeanServerDelegate + * @return The MBeanServer name - or {@value + * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name. + */ + public static String getMBeanServerSecurityName( + MBeanServerDelegate delegate) { + try { + final String serverName = delegate.getMBeanServerName(); + if (isMBeanServerNameUndefined(serverName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return serverName; + } catch (Exception x) { + logshort("Failed to retrieve MBeanServerName from delegate, " + + "using \"*\"",x); + return "*"; + } + } + + // Log the exception and its causes without logging the stack trace. + // Use with care - it is usally preferable to log the whole stack trace! + // We don't want to log the whole stack trace here: logshort() is + // called in those cases where the exception might not be abnormal. + private static void logshort(String msg, Throwable t) { + if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) { + StringBuilder toprint = new StringBuilder(msg); + toprint.append("\nCaused By: ").append(String.valueOf(t)); + while ((t=t.getCause())!=null) + toprint.append("\nCaused By: ").append(String.valueOf(t)); + JmxProperties.MISC_LOGGER.fine(toprint.toString()); + } + } + public static Set cloneSet(Set set) { if (set instanceof SortedSet) { @SuppressWarnings("unchecked") @@ -232,10 +691,19 @@ @SuppressWarnings("unchecked") SortedSet sset = (SortedSet ) set; set = new TreeSet (sset.comparator()); - } else if (set != null) { - set = new HashSet (set.size()); } else set = new HashSet (); return set; } + + // This exception is used when wrapping a class that throws IOException + // in a class that doesn't. + // The typical example for this are JMXNamespaces, when the sub + // MBeanServer can be remote. + // + public static RuntimeException newRuntimeIOException(IOException io) { + final String msg = "Communication failed with underlying resource: "+ + io.getMessage(); + return new RuntimeException(msg,io); + } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,475 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.Util; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanPermission; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.namespace.JMXDomain; + +/** + * A DomainInterceptor wraps a JMXDomain. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class DomainInterceptor extends HandlerInterceptor{ + + // TODO: Ideally DomainInterceptor should be replaced by + // something at Repository level. + // The problem there will be that we may need to + // reinstantiate the 'queryPerformedByRepos' boolean + // [or we will need to wrap the repository in + // a 'RepositoryInterceptor'?] + // Also there's no real need for a DomainInterceptor to + // extend RewritingMBeanServerConnection. + + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private final String domainName; + private volatile ObjectName ALL; + private final String serverName; + private volatile NotificationListener mbsListener; + + private static class PatternNotificationFilter + implements NotificationFilter { + + final ObjectName pattern; + public PatternNotificationFilter(ObjectName pattern) { + this.pattern = pattern; + } + + public boolean isNotificationEnabled(Notification notification) { + if (!(notification instanceof MBeanServerNotification)) + return false; + final MBeanServerNotification mbsn = + (MBeanServerNotification) notification; + if (pattern == null || pattern.apply(mbsn.getMBeanName())) + return true; + return false; + } + + static final long serialVersionUID = 7409950927025262111L; + } + + /** + * Creates a new instance of NamespaceInterceptor + */ + public DomainInterceptor(String serverName, + JMXDomain handler, + String domainName) { + super(handler); + this.domainName = domainName; + this.serverName = serverName; + } + + @Override + public String toString() { + return this.getClass().getName()+"(parent="+serverName+ + ", domain="+this.domainName+")"; + } + + public void connectDelegate(final MBeanServerDelegate delegate) + throws InstanceNotFoundException { + final NotificationFilter filter = + new PatternNotificationFilter(getPatternFor(null)); + synchronized (this) { + if (mbsListener == null) + mbsListener = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + if (filter.isNotificationEnabled(notification)) + delegate.sendNotification(notification); + } + }; + } + + getNamespace(). + addMBeanServerNotificationListener(mbsListener, filter); + } + + public void disconnectDelegate() + throws InstanceNotFoundException, ListenerNotFoundException { + final NotificationListener l; + synchronized (this) { + l = mbsListener; + if (l == null) return; + mbsListener = null; + } + getNamespace().removeMBeanServerNotificationListener(l); + } + + public void addPostRegisterTask(Queue queue, + final MBeanServerDelegate delegate) { + if (queue == null) + throw new IllegalArgumentException("task queue must not be null"); + final Runnable task1 = new Runnable() { + public void run() { + try { + connectDelegate(delegate); + } catch (Exception x) { + throw new UnsupportedOperationException("notification forwarding",x); + } + } + }; + queue.add(task1); + } + + public void addPostDeregisterTask(Queue queue, + final MBeanServerDelegate delegate) { + if (queue == null) + throw new IllegalArgumentException("task queue must not be null"); + final Runnable task1 = new Runnable() { + public void run() { + try { + disconnectDelegate(); + } catch (Exception x) { + throw new UnsupportedOperationException("notification forwarding",x); + } + } + }; + queue.add(task1); + } + + /** + * Throws IllegalArgumentException if targetName.getDomain() is not + * in the domain handled. + **/ + @Override + protected ObjectName toSource(ObjectName targetName) { + if (targetName == null) return null; + if (targetName.isDomainPattern()) return targetName; + final String targetDomain = targetName.getDomain(); + + // TODO: revisit this. RuntimeOperationsException may be better? + // + if (!targetDomain.equals(domainName)) + throw new IllegalArgumentException(targetName.toString()); + return targetName; + } + + @Override + protected ObjectName toTarget(ObjectName sourceName) { + return sourceName; + } + + + + /** + * No rewriting: always return sources - stripping instances for which + * the caller doesn't have permissions. + **/ + @Override + Set processOutputInstances(Set sources) { + if (sources == null || sources.isEmpty() || !checkOn()) + return sources; + final Set res = Util.equivalentEmptySet(sources); + for (ObjectInstance o : sources) { + if (checkQuery(o.getObjectName(), "queryMBeans")) + res.add(o); + } + return res; + } + + + /** + * No rewriting: always return sourceNames - stripping names for which + * the caller doesn't have permissions. + **/ + @Override + Set processOutputNames(Set sourceNames) { + if (sourceNames == null || sourceNames.isEmpty() || !checkOn()) + return sourceNames; + final Set res = Util.equivalentEmptySet(sourceNames); + for (ObjectName o : sourceNames) { + if (checkQuery(o, "queryNames")) + res.add(o); + } + return res; + } + + /** No rewriting: always return source **/ + @Override + ObjectInstance processOutputInstance(ObjectInstance source) { + return source; + } + + @Override + public Set queryNames(ObjectName name, QueryExp query) { + try { + // We don't trust the wrapped JMXDomain... + final ObjectName pattern = getPatternFor(name); + final Set res = super.queryNames(pattern,query); + return Util.filterMatchingNames(pattern,res); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("Unexpected exception raised in queryNames: "+x); + LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); + } + // We reach here only when an exception was raised. + // + final Set empty = Collections.emptySet(); + return empty; + } + + private ObjectName getPatternFor(final ObjectName name) { + try { + if (ALL == null) ALL = ObjectName.getInstance(domainName + ":*"); + if (name == null) return ALL; + if (name.getDomain().equals(domainName)) return name; + return name.withDomain(domainName); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(name),x); + } + } + + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + try { + // We don't trust the wrapped JMXDomain... + final ObjectName pattern = getPatternFor(name); + final Set res = super.queryMBeans(pattern,query); + return Util.filterMatchingInstances(pattern,res); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("Unexpected exception raised in queryNames: "+x); + LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); + } + // We reach here only when an exception was raised. + // + final Set empty = Collections.emptySet(); + return empty; + } + + @Override + public String getDefaultDomain() { + return domainName; + } + + @Override + public String[] getDomains() { + return new String[] {domainName}; + } + + // We call getMBeanCount() on the namespace rather than on the + // source server in order to avoid counting MBeans which are not + // in the domain. + @Override + public Integer getMBeanCount() { + return getNamespace().getMBeanCount(); + } + + private boolean checkOn() { + final SecurityManager sm = System.getSecurityManager(); + return (sm != null); + } + + // + // Implements permission checks. + // + @Override + void check(ObjectName routingName, String member, String action) { + if (!checkOn()) return; + final String act = (action==null)?"-":action.intern(); + if(act == "queryMBeans" || act == "queryNames") { // ES: OK + // This is tricky. check with 3 parameters is called + // by queryNames/queryMBeans before performing the query. + // At this point we must check with no class name. + // Therefore we pass a className of "-". + // The filtering will be done later - processOutputNames and + // processOutputInstance will call checkQuery. + // + check(routingName, "-", "-", act); + } else { + // This is also tricky: + // passing null here will cause check to retrieve the classname, + // if needed. + check(routingName, null, member, act); + } + } + + // + // Implements permission checks. + // + @Override + void checkCreate(ObjectName routingName, String className, String action) { + if (!checkOn()) return; + check(routingName,className,"-",action); + } + + // + // Implements permission checks. + // + void check(ObjectName routingName, String className, String member, + String action) { + if (!checkOn()) return; + final MBeanPermission perm; + + // action is most probably already an intern string. + // string literals are intern strings. + // we create a new intern string for 'action' - just to be on + // the safe side... + // We intern it in order to be able to use == rather than equals + // below, because if we don't, and if action is not one of the + // 4 literals below, we would have to do a full string comparison. + // + final String act = (action==null)?"-":action.intern(); + if (act == "getDomains") { // ES: OK + perm = new MBeanPermission(serverName,"-",member, + routingName,act); + } else { + final String clazz = + (className==null)?getClassName(routingName):className; + perm = new MBeanPermission(serverName,clazz,member, + routingName,act); + } + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(perm); + } + + String getClassName(ObjectName routingName) { + if (routingName == null || routingName.isPattern()) return "-"; + try { + return getNamespace().getSourceServer(). + getObjectInstance(routingName).getClassName(); + } catch (InstanceNotFoundException ex) { + LOG.finest("Can't get class name for "+routingName+ + ", using \"-\". Cause is: "+ex); + return "-"; + } + } + + // + // Implements permission filters for attributes... + // + @Override + AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action) { + if (!checkOn()) return attributes; + final String className = getClassName(routingName); + check(routingName,className,"-",action); + if (attributes == null || attributes.isEmpty()) return attributes; + final AttributeList res = new AttributeList(); + for (Attribute at : attributes.asList()) { + try { + check(routingName,className,at.getName(),action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res; + } + + // + // Implements permission filters for attributes... + // + @Override + String[] checkAttributes(ObjectName routingName, String[] attributes, + String action) { + if (!checkOn()) return attributes; + final String className = getClassName(routingName); + check(routingName,className,"-",action); + if (attributes == null || attributes.length==0) return attributes; + final List res = new ArrayList (attributes.length); + for (String at : attributes) { + try { + check(routingName,className,at,action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res.toArray(new String[res.size()]); + } + + // + // Implements permission filters for domains... + // + @Override + String[] checkDomains(String[] domains, String action) { + if (domains == null || domains.length==0 || !checkOn()) + return domains; + int count=0; + for (int i=0;i + * This API is a Sun internal API and is subject to changes without notice. + * + extends RoutingMBeanServerConnection + implements MBeanServerInterceptor { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + // The wrapped JMXNamespace + private final T handler; + + /** + * Creates a new instance of HandlerInterceptor + */ + public HandlerInterceptor(T handler) { + if (handler == null) throw new IllegalArgumentException("null"); + this.handler = handler; + } + + @Override + protected MBeanServer source() { + return handler.getSourceServer(); + } + + // The MBeanServer on which getClassLoader / getClassLoaderFor + // will be called. + // The NamespaceInterceptor overrides this method - so that it + // getClassLoader / getClassLoaderFor don't trigger the loop + // detection mechanism. + // + MBeanServer getServerForLoading() { + return source(); + } + + T getNamespace() { + return handler; + } + + // If the underlying JMXNamespace throws an IO, the IO will be + // wrapped in a RuntimeOperationsException. + RuntimeException handleIOException(IOException x,String fromMethodName, + Object... params) { + // Must do something here? + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("IO Exception in "+fromMethodName+": "+x+ + " - "+" rethrowing as RuntimeOperationsException."); + } + throw new RuntimeOperationsException( + Util.newRuntimeIOException(x)); + } + + // From MBeanServer: catch & handles IOException + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.getAttributes(name, attributes); + } catch (IOException ex) { + throw handleIOException(ex,"getAttributes",name,attributes); + } + } + + // From MBeanServer + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(mbeanName); + try { + check(mbeanName,null,"getClassLoaderFor"); + return getServerForLoading().getClassLoaderFor(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + + // From MBeanServer + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(loaderName); + try { + check(loaderName,null,"getClassLoader"); + return getServerForLoading().getClassLoader(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // From MBeanServer + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + checkCreate(name,object.getClass().getName(),"registerMBean"); + return processOutputInstance( + source().registerMBean(object,sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name,listener); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public String getDefaultDomain() { + try { + return super.getDefaultDomain(); + } catch (IOException ex) { + throw handleIOException(ex,"getDefaultDomain"); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public String[] getDomains() { + try { + return super.getDomains(); + } catch (IOException ex) { + throw handleIOException(ex,"getDomains"); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public Integer getMBeanCount() { + try { + return super.getMBeanCount(); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanCount"); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + super.setAttribute(name, attribute); + } catch (IOException ex) { + throw handleIOException(ex,"setAttribute",name, attribute); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public Set queryNames(ObjectName name, QueryExp query) { + try { + return super.queryNames(name, query); + } catch (IOException ex) { + throw handleIOException(ex,"queryNames",name, query); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + try { + return super.queryMBeans(name, query); + } catch (IOException ex) { + throw handleIOException(ex,"queryMBeans",name, query); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + return super.isInstanceOf(name, className); + } catch (IOException ex) { + throw handleIOException(ex,"isInstanceOf",name, className); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, loaderName); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + try { + return super.getAttribute(name, attribute); + } catch (IOException ex) { + throw handleIOException(ex,"getAttribute",name, attribute); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public boolean isRegistered(ObjectName name) { + try { + return super.isRegistered(name); + } catch (IOException ex) { + throw handleIOException(ex,"isRegistered",name); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + super.unregisterMBean(name); + } catch (IOException ex) { + throw handleIOException(ex,"unregisterMBean",name); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + try { + return super.getMBeanInfo(name); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanInfo",name); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + return super.getObjectInstance(name); + } catch (IOException ex) { + throw handleIOException(ex,"getObjectInstance",name); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name, params, signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, + params, signature); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName, params, + signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name,loaderName, + params, signature); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public AttributeList setAttributes(ObjectName name,AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.setAttributes(name, attributes); + } catch (IOException ex) { + throw handleIOException(ex,"setAttributes",name, attributes); + } + } + + // From MBeanServer: catch & handles IOException + @Override + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException { + try { + return super.invoke(name, operationName, params, signature); + } catch (IOException ex) { + throw handleIOException(ex,"invoke",name, operationName, + params, signature); + } + } + + // + // These methods are inherited from MBeanServer.... + // + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported instantiate method: " + + "trowing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public ClassLoaderRepository getClassLoaderRepository() { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: getClassLoaderRepository() -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + static RuntimeException newUnsupportedException(String namespace) { + return new RuntimeOperationsException( + new UnsupportedOperationException( + "Not supported in this namespace: "+namespace)); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,369 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + +import com.sun.jmx.defaults.JmxProperties; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServerConnection; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.event.EventClient; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAddressable; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +/** + * A collection of methods that provide JMXConnector wrappers for + * JMXRemoteNamepaces underlying connectors. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public final class JMXNamespaceUtils { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + + private staticMap newWeakHashMap() { + return new WeakHashMap (); + } + + /** Creates a new instance of JMXNamespaces */ + private JMXNamespaceUtils() { + } + + /** + * Returns an unmodifiable option map in which the given keys have been + * filtered out. + * @param keys keys to filter out from the map. + * @return An unmodifiable option map in which the given keys have been + * filtered out. + */ + public static Map filterMap(Map map, K... keys) { + final Map filtered; + filtered=new HashMap (map); + for (K key : keys) { + filtered.remove(key); + } + return unmodifiableMap(filtered); + } + + // returns un unmodifiable view of a map. + public static Map unmodifiableMap(Map aMap) { + if (aMap == null || aMap.isEmpty()) + return Collections.emptyMap(); + return Collections.unmodifiableMap(aMap); + } + + + /** + * A base class that helps writing JMXConnectors that return + * MBeanServerConnection wrappers. + * This base class wraps an inner JMXConnector (the source), and preserve + * its caching policy. If a connection is cached in the source, its wrapper + * will be cached in this connector too. + * Author's note: rewriting this with java.lang.reflect.Proxy could be + * envisaged. It would avoid the combinatory sub-classing introduced by + * JMXAddressable. + * + * Note: all the standard JMXConnector implementations are serializable. + * This implementation here is not. Should it be? + * I believe it must not be serializable unless it becomes + * part of a public API (either standard or officially exposed + * and supported in a documented com.sun package) + **/ + static class JMXCachingConnector + implements JMXConnector { + + // private static final long serialVersionUID = -2279076110599707875L; + + final JMXConnector source; + + // if this object is made serializable, then the variable below + // needs to become volatile transient and be lazyly-created... + private final + Map
+ *connectionMap; + + + public JMXCachingConnector(JMXConnector source) { + this.source = checkNonNull(source, "source"); + connectionMap = newWeakHashMap(); + } + + private MBeanServerConnection + getCached(MBeanServerConnection inner) { + return connectionMap.get(inner); + } + + private MBeanServerConnection putCached(final MBeanServerConnection inner, + final MBeanServerConnection wrapper) { + if (inner == wrapper) return wrapper; + synchronized (this) { + final MBeanServerConnection concurrent = + connectionMap.get(inner); + if (concurrent != null) return concurrent; + connectionMap.put(inner,wrapper); + } + return wrapper; + } + + public void addConnectionNotificationListener(NotificationListener + listener, NotificationFilter filter, Object handback) { + source.addConnectionNotificationListener(listener,filter,handback); + } + + public void close() throws IOException { + source.close(); + } + + public void connect() throws IOException { + source.connect(); + } + + public void connect(Map env) throws IOException { + source.connect(env); + } + + public String getConnectionId() throws IOException { + return source.getConnectionId(); + } + + /** + * Preserve caching policy of the underlying connector. + **/ + public MBeanServerConnection + getMBeanServerConnection() throws IOException { + final MBeanServerConnection inner = + source.getMBeanServerConnection(); + final MBeanServerConnection cached = getCached(inner); + if (cached != null) return cached; + final MBeanServerConnection wrapper = wrap(inner); + return putCached(inner,wrapper); + } + + public MBeanServerConnection + getMBeanServerConnection(Subject delegationSubject) + throws IOException { + final MBeanServerConnection wrapped = + source.getMBeanServerConnection(delegationSubject); + synchronized (this) { + final MBeanServerConnection cached = getCached(wrapped); + if (cached != null) return cached; + final MBeanServerConnection wrapper = + wrapWithSubject(wrapped,delegationSubject); + return putCached(wrapped,wrapper); + } + } + + public void removeConnectionNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + source.removeConnectionNotificationListener(listener); + } + + public void removeConnectionNotificationListener( + NotificationListener l, NotificationFilter f, + Object handback) throws ListenerNotFoundException { + source.removeConnectionNotificationListener(l,f,handback); + } + + /** + * This is the method that subclass will redefine. This method + * is called by {@code this.getMBeanServerConnection()}. + * {@code inner} is the connection returned by + * {@code source.getMBeanServerConnection()}. + **/ + protected MBeanServerConnection wrap(MBeanServerConnection inner) + throws IOException { + return inner; + } + + /** + * Subclass may also want to redefine this method. + * By default it calls wrap(inner). This method + * is called by {@code this.getMBeanServerConnection(Subject)}. + * {@code inner} is the connection returned by + * {@code source.getMBeanServerConnection(Subject)}. + **/ + protected MBeanServerConnection wrapWithSubject( + MBeanServerConnection inner, Subject delegationSubject) + throws IOException { + return wrap(inner); + } + + @Override + public String toString() { + if (source instanceof JMXAddressable) { + final JMXServiceURL address = + ((JMXAddressable)source).getAddress(); + if (address != null) + return address.toString(); + } + return source.toString(); + } + + } + + + /** + * The name space connector can do 'cd' + **/ + static class JMXNamespaceConnector extends JMXCachingConnector { + + // private static final long serialVersionUID = -4813611540843020867L; + + private final String toDir; + private final boolean closeable; + + public JMXNamespaceConnector(JMXConnector source, String toDir, + boolean closeable) { + super(source); + this.toDir = toDir; + this.closeable = closeable; + } + + @Override + public void close() throws IOException { + if (!closeable) + throw new UnsupportedOperationException("close"); + else super.close(); + } + + @Override + protected MBeanServerConnection wrap(MBeanServerConnection wrapped) + throws IOException { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Creating name space proxy connection for source: "+ + "namespace="+toDir); + return JMXNamespaces.narrowToNamespace(wrapped,toDir); + } + + @Override + public String toString() { + return "JMXNamespaces.narrowToNamespace("+ + super.toString()+ + ", \""+toDir+"\")"; + } + + } + + static class JMXEventConnector extends JMXCachingConnector { + + // private static final long serialVersionUID = 4742659236340242785L; + + JMXEventConnector(JMXConnector wrapped) { + super(wrapped); + } + + @Override + protected MBeanServerConnection wrap(MBeanServerConnection inner) + throws IOException { + return EventClient.getEventClientConnection(inner); + } + + + @Override + public String toString() { + return "EventClient.withEventClient("+super.toString()+")"; + } + } + + static class JMXAddressableEventConnector extends JMXEventConnector + implements JMXAddressable { + + // private static final long serialVersionUID = -9128520234812124712L; + + JMXAddressableEventConnector(JMXConnector wrapped) { + super(wrapped); + } + + public JMXServiceURL getAddress() { + return ((JMXAddressable)source).getAddress(); + } + } + + /** + * Creates a connector whose MBeamServerConnection will point to the + * given sub name space inside the source connector. + * @see JMXNamespace + **/ + public static JMXConnector cd(final JMXConnector source, + final String toNamespace, + final boolean closeable) + throws IOException { + + checkNonNull(source, "JMXConnector"); + + if (toNamespace == null || toNamespace.equals("")) + return source; + + return new JMXNamespaceConnector(source,toNamespace,closeable); + } + + + /** + * Returns a JMX Connector that will use an {@link EventClient} + * to subscribe for notifications. If the server doesn't have + * an {@link EventClientDelegateMBean}, then the connector will + * use the legacy notification mechanism instead. + * + * @param source The underlying JMX Connector wrapped by the returned + * connector. + * @return A JMX Connector that will uses an {@link EventClient}, if + * available. + * @see EventClient#getEventClientConnection(MBeanServerConnection) + */ + public static JMXConnector withEventClient(final JMXConnector source) { + checkNonNull(source, "JMXConnector"); + if (source instanceof JMXAddressable) + return new JMXAddressableEventConnector(source); + else + return new JMXEventConnector(source); + } + + public static T checkNonNull(T parameter, String name) { + if (parameter == null) + throw new IllegalArgumentException(name+" must not be null"); + return parameter; + } + + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,449 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.jmx.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespacePermission; + +/** + * A NamespaceInterceptor wraps a JMXNamespace, performing + * ObjectName rewriting. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class NamespaceInterceptor extends HandlerInterceptor{ + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + private static final Logger PROBE_LOG = Logger.getLogger( + JmxProperties.NAMESPACE_LOGGER+".probe"); + + // The target name space in which the NamepsaceHandler is mounted. + private final String targetNs; + + private final String serverName; + + private final ObjectNameRouter proc; + + /** + * Internal hack. The JMXRemoteNamespace can be closed and reconnected. + * Each time the JMXRemoteNamespace connects, a probe should be sent + * to detect cycle. The MBeanServer exposed by JMXRemoteNamespace thus + * implements the DynamicProbe interface, which makes it possible for + * this handler to know that it should send a new probe. + * + * XXX: TODO this probe thing is way too complex and fragile. + * This *must* go away or be replaced by something simpler. + * ideas are welcomed. + **/ + public static interface DynamicProbe { + public boolean isProbeRequested(); + } + + /** + * Creates a new instance of NamespaceInterceptor + */ + public NamespaceInterceptor( + String serverName, + JMXNamespace handler, + String targetNamespace) { + super(handler); + this.serverName = serverName; + this.targetNs = + ObjectNameRouter.normalizeNamespacePath(targetNamespace, + true, true, false); + proc = new ObjectNameRouter(targetNamespace, ""); + } + + @Override + public String toString() { + return this.getClass().getName()+"(parent="+serverName+ + ", namespace="+this.targetNs+")"; + } + + /* + * XXX: TODO this probe thing is way too complex and fragile. + * This *must* go away or be replaced by something simpler. + * ideas are welcomed. + */ + private volatile boolean probed = false; + private volatile ObjectName probe; + + // Query Pattern that we will send through the source server in order + // to detect self-linking namespaces. + // + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + final ObjectName makeProbePattern(ObjectName probe) + throws MalformedObjectNameException { + + // we could probably link the probe pattern with the probe - e.g. + // using the UUID as key in the pattern - but is it worth it? it + // also has some side effects on the context namespace - because + // such a probe may get rejected by the jmx.context// namespace. + // + // The trick here is to devise a pattern that is not likely to + // be blocked by intermediate levels. Querying for all namespace + // handlers in the source (or source namespace) is more likely to + // achieve this goal. + // + return ObjectName.getInstance("*" + + JMXNamespaces.NAMESPACE_SEPARATOR + ":" + + JMXNamespace.TYPE_ASSIGNMENT); + } + + // tell whether the name pattern corresponds to what might have been + // sent as a probe. + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + final boolean isProbePattern(ObjectName name) { + final ObjectName p = probe; + if (p == null) return false; + try { + return String.valueOf(name).endsWith(targetNs+ + JMXNamespaces.NAMESPACE_SEPARATOR + "*" + + JMXNamespaces.NAMESPACE_SEPARATOR + ":" + + JMXNamespace.TYPE_ASSIGNMENT); + } catch (RuntimeException x) { + // should not happen. + PROBE_LOG.finest("Ignoring unexpected exception in self link detection: "+ + x); + return false; + } + } + + // The first time a request reaches this NamespaceInterceptor, the + // interceptor will send a probe to detect whether the underlying + // JMXNamespace links to itslef. + // + // One way to create such self-linking namespace would be for instance + // to create a JMXNamespace whose getSourceServer() method would return: + // JMXNamespaces.narrowToNamespace(getMBeanServer(), + // getObjectName().getDomain()) + // + // If such an MBeanServer is returned, then any call to that MBeanServer + // will trigger an infinite loop. + // There can be even trickier configurations if remote connections are + // involved. + // + // In order to prevent this from happening, the NamespaceInterceptor will + // send a probe, in an attempt to detect whether it will receive it at + // the other end. If the probe is received, an exception will be thrown + // in order to break the recursion. The probe is only sent once - when + // the first request to the namespace occurs. The DynamicProbe interface + // can also be used by a Sun JMXNamespace implementation to request the + // emission of a probe at any time (see JMXRemoteNamespace + // implementation). + // + // Probes work this way: the NamespaceInterceptor sets a flag and sends + // a queryNames() request. If a queryNames() request comes in when the flag + // is on, then it deduces that there is a self-linking loop - and instead + // of calling queryNames() on the source MBeanServer of the JMXNamespace + // handler (which would cause the loop to go on) it breaks the recursion + // by returning the probe ObjectName. + // If the NamespaceInterceptor receives the probe ObjectName as result of + // its original sendProbe() request it knows that it has been looping + // back on itslef and throws an IOException... + // + // + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + // + final void sendProbe(MBeanServerConnection msc) + throws IOException { + try { + PROBE_LOG.fine("Sending probe"); + + // This is just to prevent any other thread to modify + // the probe while the detection cycle is in progress. + // + final ObjectName probePattern; + // we don't want to synchronize on this - we use targetNs + // because it's non null and final. + synchronized (targetNs) { + probed = false; + if (probe != null) { + throw new IOException("concurent connection in progress"); + } + final String uuid = UUID.randomUUID().toString(); + final String endprobe = + JMXNamespaces.NAMESPACE_SEPARATOR + uuid + + ":type=Probe,key="+uuid; + final ObjectName newprobe = + ObjectName.getInstance(endprobe); + probePattern = makeProbePattern(newprobe); + probe = newprobe; + } + + try { + PROBE_LOG.finer("Probe query: "+probePattern+" expecting: "+probe); + final Set res = msc.queryNames(probePattern, null); + final ObjectName expected = probe; + PROBE_LOG.finer("Probe res: "+res); + if (res.contains(expected)) { + throw new IOException("namespace " + + targetNs + " is linking to itself: " + + "cycle detected by probe"); + } + } catch (SecurityException x) { + PROBE_LOG.finer("Can't check for cycles: " + x); + // can't do anything.... + } catch (RuntimeException x) { + PROBE_LOG.finer("Exception raised by queryNames: " + x); + throw x; + } finally { + probe = null; + } + } catch (MalformedObjectNameException x) { + final IOException io = + new IOException("invalid name space: probe failed"); + io.initCause(x); + throw io; + } + PROBE_LOG.fine("Probe returned - no cycles"); + probed = true; + } + + // allows a Sun implementation JMX Namespace, such as the + // JMXRemoteNamespace, to control when a probe should be sent. + // + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + private boolean isProbeRequested(Object o) { + if (o instanceof DynamicProbe) + return ((DynamicProbe)o).isProbeRequested(); + return false; + } + + /** + * This method will send a probe to detect self-linking name spaces. + * A self linking namespace is a namespace that links back directly + * on itslef. Calling a method on such a name space always results + * in an infinite loop going through: + * [1]MBeanServer -> [2]NamespaceDispatcher -> [3]NamespaceInterceptor + * [4]JMXNamespace -> { network // or cd // or ... } -> [5]MBeanServer + * with exactly the same request than [1]... + * + * The namespace interceptor [2] tries to detect such condition the + * *first time* that the connection is used. It does so by setting + * a flag, and sending a queryNames() through the name space. If the + * queryNames comes back, it knows that there's a loop. + * + * The DynamicProbe interface can also be used by a Sun JMXNamespace + * implementation to request the emission of a probe at any time + * (see JMXRemoteNamespace implementation). + */ + private MBeanServer connection() { + try { + final MBeanServer c = super.source(); + if (probe != null) // should not happen + throw new RuntimeException("connection is being probed"); + + if (probed == false || isProbeRequested(c)) { + try { + // Should not happen if class well behaved. + // Never probed. Force it. + //System.err.println("sending probe for " + + // "target="+targetNs+", source="+srcNs); + sendProbe(c); + } catch (IOException io) { + throw new RuntimeException(io.getMessage(), io); + } + } + + if (c != null) { + return c; + } + } catch (RuntimeException x) { + throw x; + } + throw new NullPointerException("getMBeanServerConnection"); + } + + + @Override + protected MBeanServer source() { + return connection(); + } + + @Override + protected MBeanServer getServerForLoading() { + // don't want to send probe on getClassLoader/getClassLoaderFor + return super.source(); + } + + /** + * Calls {@link MBeanServerConnection#queryNames queryNames} + * on the underlying + * {@link #getMBeanServerConnection MBeanServerConnection}. + **/ + @Override + public final Set queryNames(ObjectName name, QueryExp query) { + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + PROBE_LOG.finer("probe is: "+probe+" pattern is: "+name); + if (probe != null && isProbePattern(name)) { + PROBE_LOG.finer("Return probe: "+probe); + return Collections.singleton(probe); + } + return super.queryNames(name, query); + } + + @Override + protected ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException { + return proc.toSourceContext(targetName, true); + } + + @Override + protected ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException { + return proc.toTargetContext(sourceName, false); + } + + // + // Implements permission checks. + // + @Override + void check(ObjectName routingName, String member, String action) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return; + if ("getDomains".equals(action)) return; + final JMXNamespacePermission perm = + new JMXNamespacePermission(serverName,member, + routingName,action); + sm.checkPermission(perm); + } + + @Override + void checkCreate(ObjectName routingName, String className, String action) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return; + final JMXNamespacePermission perm = + new JMXNamespacePermission(serverName,className, + routingName,action); + sm.checkPermission(perm); + } + + // + // Implements permission filters for attributes... + // + @Override + AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action) { + check(routingName,null,action); + if (attributes == null || attributes.isEmpty()) return attributes; + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return attributes; + final AttributeList res = new AttributeList(); + for (Attribute at : attributes.asList()) { + try { + check(routingName,at.getName(),action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res; + } + + // + // Implements permission filters for attributes... + // + @Override + String[] checkAttributes(ObjectName routingName, String[] attributes, + String action) { + check(routingName,null,action); + if (attributes == null || attributes.length==0) return attributes; + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return attributes; + final List res = new ArrayList (attributes.length); + for (String at : attributes) { + try { + check(routingName,at,action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res.toArray(new String[res.size()]); + } + + // + // Implements permission filters for domains... + // + @Override + String[] checkDomains(String[] domains, String action) { + // in principle, this method is never called because + // getDomains() will never be called - since there's + // no way that MBeanServer.getDomains() can be routed + // to a NamespaceInterceptor. + // + // This is also why there's no getDomains() in a + // JMXNamespacePermission... + // + return super.checkDomains(domains, action); + } + + // + // Implements permission filters for queries... + // + @Override + boolean checkQuery(ObjectName routingName, String action) { + try { + check(routingName,null,action); + return true; + } catch (SecurityException x) { // DLS: OK + return false; + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,191 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * The ObjectNameRouter is used to rewrite routing object names. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class ObjectNameRouter { + + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + final String targetPrefix; + final String sourcePrefix; + final int slen; + final int tlen; + final boolean identity; + + + public ObjectNameRouter(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of ObjectNameRouter */ + public ObjectNameRouter(final String remove, final String add) { + this.targetPrefix = (remove==null?"":remove); + this.sourcePrefix = (add==null?"":add); + tlen = targetPrefix.length(); + slen = sourcePrefix.length(); + identity = targetPrefix.equals(sourcePrefix); + } + + public final ObjectName toTargetContext(ObjectName sourceName, + boolean removeLeadingSeparators) { + if (sourceName == null) return null; + if (identity) return sourceName; + String srcDomain = sourceName.getDomain(); + + // if the ObjectName starts with // and removeLeadingSeparators is + // true, then recursively strip leading //. + // Otherwise, do not rewrite ObjectName. + // + if (srcDomain.startsWith(NAMESPACE_SEPARATOR)) { + if (!removeLeadingSeparators) return sourceName; + else srcDomain = normalizeDomain(srcDomain,true); + } + if (slen != 0) { + if (!srcDomain.startsWith(sourcePrefix) || + !srcDomain.startsWith(NAMESPACE_SEPARATOR,slen)) + throw new IllegalArgumentException( + "ObjectName does not start with expected prefix " + + sourcePrefix + ": " + + String.valueOf(sourceName)); + srcDomain = srcDomain.substring(slen+NAMESPACE_SEPARATOR_LENGTH); + } + final String targetDomain = + (tlen>0?targetPrefix+NAMESPACE_SEPARATOR+srcDomain:srcDomain); + try { + return sourceName.withDomain(targetDomain); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(sourceName),x); + } + } + + public final ObjectName toSourceContext(ObjectName targetName, + boolean removeLeadingSeparators) { + if (targetName == null) return null; + if (identity) return targetName; + String targetDomain = targetName.getDomain(); + if (targetDomain.startsWith(NAMESPACE_SEPARATOR)) { + if (!removeLeadingSeparators) return targetName; + else targetDomain = + normalizeDomain(targetDomain,true); + } + if (tlen != 0) { + if (!targetDomain.startsWith(targetPrefix) || + !targetDomain.startsWith(NAMESPACE_SEPARATOR,tlen)) + throw new IllegalArgumentException( + "ObjectName does not start with expected prefix " + + targetPrefix + ": " + + String.valueOf(targetName)); + targetDomain = targetDomain. + substring(tlen+NAMESPACE_SEPARATOR_LENGTH); + } + final String sourceDomain = + (slen>0?sourcePrefix+NAMESPACE_SEPARATOR+targetDomain: + targetDomain); + try { + return targetName.withDomain(sourceDomain); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(targetName),x); + } + } + + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi, + boolean removeLeadingSeparators) { + if (sourceMoi == null) return null; + if (identity) return sourceMoi; + return new ObjectInstance( + toTargetContext(sourceMoi.getObjectName(), + removeLeadingSeparators), + sourceMoi.getClassName()); + } + + /** + * Removes leading, trailing, or duplicate // in a name space path. + **/ + public static String normalizeDomain(String domain, + boolean removeLeadingSep) { + return normalizeNamespacePath(domain,removeLeadingSep,false,true); + } + + /** + * Removes leading, trailing, or duplicate // in a name space path. + **/ + public static String normalizeNamespacePath(String namespacePath, + boolean removeLeadingSep, + boolean removeTrailingSep, + boolean endsWithDomain) { + if (namespacePath.equals("")) + return ""; + final String[] components = namespacePath.split(NAMESPACE_SEPARATOR); + final StringBuilder b = + new StringBuilder(namespacePath.length()+NAMESPACE_SEPARATOR_LENGTH); + String sep = null; + if (!removeLeadingSep && namespacePath.startsWith(NAMESPACE_SEPARATOR)) + b.append(NAMESPACE_SEPARATOR); + int count = 0; + for (int i=0; i0) + b.append(NAMESPACE_SEPARATOR); + return b.toString(); + } + + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + + +import com.sun.jmx.defaults.JmxProperties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServerConnection; +import javax.management.namespace.JMXNamespaces; + + +/** + * A RoutingConnectionProxy is an MBeanServerConnection proxy that proxies a + * source name space in a source MBeanServerConnection. + * It wraps a source MBeanServerConnection, and rewrites routing + * ObjectNames. It is used to implement + * {@code JMXNamespaces.narrowToNamespace(MBeanServerConnection)}. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class RoutingConnectionProxy + extends RoutingProxy{ + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + + /** + * Creates a new instance of RoutingConnectionProxy + */ + public RoutingConnectionProxy(MBeanServerConnection source, + String sourceDir) { + this(source,sourceDir,"",false); + } + + /** + * Creates a new instance of RoutingConnectionProxy + */ + public RoutingConnectionProxy(MBeanServerConnection source, + String sourceDir, + String targetDir, + boolean forwardsContext) { + super(source,sourceDir,targetDir,forwardsContext); + + if (LOG.isLoggable(Level.FINER)) + LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() + + " created"); + } + + @Override + public String toString() { + final String targetNs = getTargetNamespace(); + final String sourceNs = getSourceNamespace(); + String wrapped = String.valueOf(source()); + if ("".equals(targetNs)) { + if (forwardsContext) + wrapped = "ClientContext.withDynamicContext("+wrapped+")"; + return "JMXNamespaces.narrowToNamespace("+ + wrapped+", \""+ + sourceNs+"\")"; + } + return this.getClass().getSimpleName()+"("+wrapped+", \""+ + sourceNs+"\", \""+ + targetNs+"\", "+forwardsContext+")"; + } + + public static MBeanServerConnection cd(MBeanServerConnection source, + String sourcePath) { + if (source == null) throw new IllegalArgumentException("null"); + if (source.getClass().equals(RoutingConnectionProxy.class)) { + // cast is OK here, but findbugs complains unless we use class.cast + final RoutingConnectionProxy other = + RoutingConnectionProxy.class.cast(source); + final String target = other.getTargetNamespace(); + + // Avoid multiple layers of serialization. + // + // We construct a new proxy from the original source instead of + // stacking a new proxy on top of the old one. + // - that is we replace + // cd ( cd ( x, dir1), dir2); + // by + // cd (x, dir1//dir2); + // + // We can do this only when the source class is exactly + // NamespaceConnectionProxy. + // + if (target == null || target.equals("")) { + final String path = + JMXNamespaces.concat(other.getSourceNamespace(), + sourcePath); + return new RoutingConnectionProxy(other.source(),path,"", + other.forwardsContext); + } + // Note: we could do possibly something here - but it would involve + // removing part of targetDir, and possibly adding + // something to sourcePath. + // Too complex to bother! => simply default to stacking... + } + return new RoutingConnectionProxy(source,sourcePath); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,671 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.JMRuntimeException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeMBeanException; +import javax.management.RuntimeOperationsException; + +/** + * A RoutingMBeanServerConnection wraps a MBeanServerConnection, defining + * abstract methods that can be implemented by subclasses to rewrite + * routing ObjectNames. It is used to implement + * HandlerInterceptors (wrapping JMXNamespace instances) and routing + * proxies (used to implement cd operations). + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class RoutingMBeanServerConnection+ implements MBeanServerConnection { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + /** + * Creates a new instance of RoutingMBeanServerConnection + */ + public RoutingMBeanServerConnection() { + } + + /** + * Returns the wrapped source connection. + **/ + protected abstract T source() throws IOException; + + /** + * Converts a target ObjectName to a source ObjectName. + **/ + protected abstract ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException; + + /** + * Converts a source ObjectName to a target ObjectName. + **/ + protected abstract ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException; + + /** + * Can be overridden by subclasses to check the validity of a new + * ObjectName used in createMBean or registerMBean. + * This method is typically used by subclasses which might require + * special handling for "null"; + **/ + protected ObjectName newSourceMBeanName(ObjectName targetName) + throws MBeanRegistrationException { + try { + return toSource(targetName); + } catch (Exception x) { + throw new MBeanRegistrationException(x,"Illegal MBean Name"); + } + } + + // Calls toSource(), Wraps MalformedObjectNameException. + ObjectName toSourceOrRuntime(ObjectName targetName) + throws RuntimeOperationsException { + try { + return toSource(targetName); + } catch (MalformedObjectNameException x) { + final IllegalArgumentException x2 = + new IllegalArgumentException(String.valueOf(targetName),x); + final RuntimeOperationsException x3 = + new RuntimeOperationsException(x2); + throw x3; + } + } + + + // Wraps given exception if needed. + RuntimeException makeCompliantRuntimeException(Exception x) { + if (x instanceof SecurityException) return (SecurityException)x; + if (x instanceof JMRuntimeException) return (JMRuntimeException)x; + if (x instanceof RuntimeException) + return new RuntimeOperationsException((RuntimeException)x); + if (x instanceof IOException) + return Util.newRuntimeIOException((IOException)x); + // shouldn't come here... + final RuntimeException x2 = new UndeclaredThrowableException(x); + return new RuntimeOperationsException(x2); + } + + /** + * This method is a hook to implement permission checking in subclasses. + * By default, this method does nothing and simply returns + * {@code attribute}. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code // }. + * @param attributes The list of attributes to check permission for. + * @param action one of "getAttribute" or "setAttribute" + * @return The list of attributes for which the callers has the + * appropriate {@link + * javax.management.namespace.JMXNamespacePermission}. + */ + String[] checkAttributes(ObjectName routingName, + String[] attributes, String action) { + check(routingName,null,action); + return attributes; + } + + /** + * This method is a hook to implement permission checking in subclasses. + * By default, this method does nothing and simply returns + * {@code attribute}. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code // }. + * @param attributes The list of attributes to check permission for. + * @param action one of "getAttribute" or "setAttribute" + * @return The list of attributes for which the callers has the + * appropriate {@link + * javax.management.namespace.JMXNamespacePermission}. + */ + AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action) { + check(routingName,null,action); + return attributes; + } + + // from MBeanServerConnection + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + final String[] authorized = + checkAttributes(name,attributes,"getAttribute"); + final AttributeList attrList = + source().getAttributes(sourceName,authorized); + return attrList; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + /** + * This method is a hook to implement permission checking in subclasses. + * By default, this method does nothing. + * A subclass may override this method and throw a {@link + * SecurityException} if the permission is denied. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code // }. + * @param member The {@link + * javax.management.namespace.JMXNamespacePermission#getMember member} + * name. + * @param action The {@link + * javax.management.namespace.JMXNamespacePermission#getActions action} + * name. + */ + void check(ObjectName routingName, + String member, String action) { + } + + void checkPattern(ObjectName routingPattern, + String member, String action) { + // pattern is checked only at posteriori by checkQuery. + // checking it a priori usually doesn't work, because ObjectName.apply + // does not work between two patterns. + check(null,null,action); + } + + void checkCreate(ObjectName routingName, String className, + String action) { + } + + // from MBeanServerConnection + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, operationName, "invoke"); + final Object result = + source().invoke(sourceName,operationName,params, + signature); + return result; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, null, "unregisterMBean"); + source().unregisterMBean(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, null, "getMBeanInfo"); + return source().getMBeanInfo(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, null, "getObjectInstance"); + return processOutputInstance( + source().getObjectInstance(sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public boolean isRegistered(ObjectName name) throws IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().isRegistered(sourceName); + } catch (RuntimeMBeanException x) { + throw new RuntimeOperationsException(x.getTargetException()); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + // from MBeanServerConnection + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, + (attribute==null?null:attribute.getName()), + "setAttribute"); + source().setAttribute(sourceName,attribute); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, + ObjectName name, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + // Loader Name is already a sourceLoaderName. + final ObjectName sourceLoaderName = loaderName; + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + final ObjectInstance instance = + source().createMBean(className,sourceName, + sourceLoaderName, + params,signature); + return processOutputInstance(instance); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return processOutputInstance(source().createMBean(className, + sourceName,params,signature)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + // Loader Name is already a source Loader Name. + final ObjectName sourceLoaderName = loaderName; + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return processOutputInstance(source().createMBean(className, + sourceName,sourceLoaderName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return processOutputInstance(source(). + createMBean(className,sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, attribute, "getAttribute"); + return source().getAttribute(sourceName,attribute); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name, null, "isInstanceOf"); + return source().isInstanceOf(sourceName,className); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + final AttributeList authorized = + checkAttributes(name, attributes, "setAttribute"); + return source(). + setAttributes(sourceName,authorized); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // Return names in the target's context. + Set processOutputInstances(Set sources) { + + final Set result = Util.equivalentEmptySet(sources); + for (ObjectInstance i : sources) { + try { + final ObjectInstance target = processOutputInstance(i); + if (!checkQuery(target.getObjectName(), "queryMBeans")) + continue; + result.add(target); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Skiping returned item: " + + "Unexpected exception while processing " + + "ObjectInstance: " + x); + } + continue; + } + } + return result; + } + + /** + * This is a hook to implement permission checking in subclasses. + * + * Checks that the caller has sufficient permission for returning + * information about {@code sourceName} in {@code action}. + * + * By default always return true. Subclass may override this method + * and return false if the caller doesn't have sufficient permissions. + * + * @param routingName The name of the MBean to include or exclude from + * the query, expressed in the enclosing context. + * This is of the form {@code // }. + * @param action one of "queryNames" or "queryMBeans" + * @return true if {@code sourceName} can be returned. + */ + boolean checkQuery(ObjectName routingName, String action) { + return true; + } + + // Return names in the target's context. + ObjectInstance processOutputInstance(ObjectInstance source) { + if (source == null) return null; + final ObjectName sourceName = source.getObjectName(); + try { + final ObjectName targetName = toTarget(sourceName); + return new ObjectInstance(targetName,source.getClassName()); + } catch (MalformedObjectNameException x) { + final IllegalArgumentException x2 = + new IllegalArgumentException(String.valueOf(sourceName),x); + final RuntimeOperationsException x3 = + new RuntimeOperationsException(x2); + throw x3; + } + } + + // Returns names in the target's context. + Set processOutputNames(Set sourceNames) { + + final Set names = Util.equivalentEmptySet(sourceNames); + for (ObjectName n : sourceNames) { + try { + final ObjectName targetName = toTarget(n); + if (!checkQuery(targetName, "queryNames")) continue; + names.add(targetName); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Skiping returned item: " + + "Unexpected exception while processing " + + "ObjectInstance: " + x); + } + continue; + } + } + return names; + } + + // from MBeanServerConnection + public Set queryMBeans(ObjectName name, + QueryExp query) throws IOException { + if (name == null) name=ObjectName.WILDCARD; + final ObjectName sourceName = toSourceOrRuntime(name); + try { + checkPattern(name,null,"queryMBeans"); + return processOutputInstances( + source().queryMBeans(sourceName,query)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + + public Set queryNames(ObjectName name, QueryExp query) + throws IOException { + if (name == null) name=ObjectName.WILDCARD; + final ObjectName sourceName = toSourceOrRuntime(name); + try { + checkPattern(name,null,"queryNames"); + final Set tmp = source().queryNames(sourceName,query); + final Set out = processOutputNames(tmp); + //System.err.println("queryNames: out: "+out); + return out; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, + ListenerNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name,null,"removeNotificationListener"); + source().removeNotificationListener(sourceName,listener); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + // Listener name is already a source listener name. + try { + check(name,null,"addNotificationListener"); + source().addNotificationListener(sourceName,listener, + filter,handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name,null,"addNotificationListener"); + source().addNotificationListener(sourceName, listener, filter, + handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name,null,"removeNotificationListener"); + source().removeNotificationListener(sourceName,listener,filter, + handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + check(name,null,"removeNotificationListener"); + source().removeNotificationListener(sourceName,listener, + filter,handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + // listener name is already a source name... + final ObjectName sourceListener = listener; + try { + check(name,null,"removeNotificationListener"); + source().removeNotificationListener(sourceName,sourceListener); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Integer getMBeanCount() throws IOException { + try { + return source().getMBeanCount(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public String[] getDomains() throws IOException { + try { + check(null,null,"getDomains"); + final String[] domains = source().getDomains(); + return checkDomains(domains,"getDomains"); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + /** + * This method is a hook to implement permission checking in subclasses. + * Checks that the caller as the necessary permissions to view the + * given domain. If not remove the domains for which the caller doesn't + * have permission from the list. + * + * By default, this method always returns {@code domains} + * + * @param domains The domains to return. + * @param action "getDomains" + * @return a filtered list of domains. + */ + String[] checkDomains(String[] domains, String action) { + return domains; + } + + // from MBeanServerConnection + public String getDefaultDomain() throws IOException { + try { + return source().getDefaultDomain(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,282 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanRegistrationException; + +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespaces; + + +/** + * An RoutingProxy narrows on a given name space in a + * source object implementing MBeanServerConnection. + * It is used to implement + * {@code JMXNamespaces.narrowToNamespace(...)}. + * This abstract class has two concrete subclasses: + *
{@link RoutingConnectionProxy}: to cd in an MBeanServerConnection.
+ *{@link RoutingServerProxy}: to cd in an MBeanServer.
+ *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class RoutingProxy+ extends RoutingMBeanServerConnection { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + // The source MBeanServerConnection + private final T source; + + // The name space we're narrowing to (usually some name space in + // the source MBeanServerConnection + private final String sourceNs; + + // The name space we pretend to be mounted in (usually "") + private final String targetNs; + + // The name of the JMXNamespace that handles the source name space + private final ObjectName handlerName; + private final ObjectNameRouter router; + final boolean forwardsContext; + private volatile String defaultDomain = null; + + /** + * Creates a new instance of RoutingProxy + */ + protected RoutingProxy(T source, + String sourceNs, + String targetNs, + boolean forwardsContext) { + if (source == null) throw new IllegalArgumentException("null"); + this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs); + + // Usually sourceNs is not null, except when implementing + // Client Contexts + // + if (sourceNs.equals("")) { + this.handlerName = null; + } else { + // System.err.println("sourceNs: "+sourceNs); + this.handlerName = + JMXNamespaces.getNamespaceObjectName(this.sourceNs); + try { + // System.err.println("handlerName: "+handlerName); + if (!source.isRegistered(handlerName)) + throw new IllegalArgumentException(sourceNs + + ": no such name space"); + } catch (IOException x) { + throw new IllegalArgumentException("source stale: "+x,x); + } + } + this.source = source; + this.targetNs = (targetNs==null?"": + JMXNamespaces.normalizeNamespaceName(targetNs)); + this.router = + new ObjectNameRouter(this.targetNs,this.sourceNs); + this.forwardsContext = forwardsContext; + + if (LOG.isLoggable(Level.FINER)) + LOG.finer("RoutingProxy for " + this.sourceNs + " created"); + } + + @Override + public T source() { return source; } + + ObjectNameRouter getObjectNameRouter() { +// TODO: uncomment this when contexts are added +// if (forwardsContext) +// return ObjectNameRouter.wrapWithContext(router); +// else + return router; + } + + @Override + public ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException { + if (targetName == null) return null; + if (targetName.getDomain().equals("") && targetNs.equals("")) { + try { + if (defaultDomain == null) + defaultDomain = getDefaultDomain(); + } catch(Exception x) { + LOG.log(Level.FINEST,"Failed to get default domain",x); + } + if (defaultDomain != null) + targetName = targetName.withDomain(defaultDomain); + } + final ObjectNameRouter r = getObjectNameRouter(); + return r.toSourceContext(targetName,true); + } + + @Override + protected ObjectName newSourceMBeanName(ObjectName targetName) + throws MBeanRegistrationException { + if (targetName != null) return super.newSourceMBeanName(targetName); + + // OK => we can accept null if sourceNs is empty. + if (sourceNs.equals("")) return null; + + throw new MBeanRegistrationException( + new IllegalArgumentException( + "Can't use null ObjectName with namespaces")); + } + + @Override + public ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException { + if (sourceName == null) return null; + final ObjectNameRouter r = getObjectNameRouter(); + return r.toTargetContext(sourceName,false); + } + + private Object getAttributeFromHandler(String attributeName) + throws IOException { + + try { + return source().getAttribute(handlerName,attributeName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } catch (IOException x) { + throw x; + } catch (MBeanException ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex.getMessage(), + ex.getTargetException()); + } catch (AttributeNotFoundException ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex.getMessage(),ex); + } catch (InstanceNotFoundException ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex.getMessage(),ex); + } catch (ReflectionException ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex.getMessage(),ex); + } + } + + // We cannot call getMBeanCount() on the underlying + // MBeanServerConnection, because it would return the number of + // 'top-level' MBeans, not the number of MBeans in the name space + // we are narrowing to. Instead we're calling getMBeanCount() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public Integer getMBeanCount() throws IOException { + try { + if (handlerName == null) return source().getMBeanCount(); + return (Integer) getAttributeFromHandler("MBeanCount"); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // We cannot call getDomains() on the underlying + // MBeanServerConnection, because it would return the domains of + // 'top-level' MBeans, not the domains of MBeans in the name space + // we are narrowing to. Instead we're calling getDomains() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public String[] getDomains() throws IOException { + try { + if (handlerName == null) return source().getDomains(); + return (String[]) getAttributeFromHandler("Domains"); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // We cannot call getDefaultDomain() on the underlying + // MBeanServerConnection, because it would return the default domain of + // 'top-level' namespace, not the default domain in the name space + // we are narrowing to. Instead we're calling getDefaultDomain() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public String getDefaultDomain() throws IOException { + try { + if (handlerName == null) { + defaultDomain = source().getDefaultDomain(); + } else { + defaultDomain =(String) + getAttributeFromHandler("DefaultDomain"); + } + return defaultDomain; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + public String getSourceNamespace() { + return sourceNs; + } + + public String getTargetNamespace() { + return targetNs; + } + + @Override + public String toString() { + return super.toString()+", sourceNs="+ + sourceNs + (targetNs.equals("")?"": + (" mounted on targetNs="+targetNs)); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,602 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace; + + +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Collections; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.loading.ClassLoaderRepository; +import javax.management.namespace.JMXNamespaces; + +/** + * A RoutingServerProxy is an MBeanServer proxy that proxies a + * source name space in a source MBeanServer. + * It wraps a source MBeanServer, and rewrites routing ObjectNames. + * It is typically use for implementing 'cd' operations, and + * will add the source name space to routing ObjectNames at input, + * and remove it at output. + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * + * @since 1.7 + */ +public class RoutingServerProxy + extends RoutingProxy+ implements MBeanServer { + + /** + * Creates a new instance of RoutingServerProxy + */ + public RoutingServerProxy(MBeanServer source, + String sourceNs) { + this(source,sourceNs,"",false); + } + + public RoutingServerProxy(MBeanServer source, + String sourceNs, + String targetNs, + boolean forwardsContext) { + super(source,sourceNs,targetNs,forwardsContext); + } + + /** + * This method is called each time an IOException is raised when + * trying to forward an operation to the underlying + * MBeanServerConnection, as a result of calling + * {@link #getMBeanServerConnection()} or as a result of invoking the + * operation on the returned connection. + * Subclasses may redefine this method if they need to perform any + * specific handling of IOException (logging etc...). + * @param x The raised IOException. + * @param method The name of the method in which the exception was + * raised. This is one of the methods of the MBeanServer + * interface. + * @return A RuntimeException that should be thrown by the caller. + * In this default implementation, this is an + * {@link UndeclaredThrowableException} wrapping x. + **/ + protected RuntimeException handleIOException(IOException x, + String method) { + return Util.newRuntimeIOException(x); + } + + + //-------------------------------------------- + //-------------------------------------------- + // + // Implementation of the MBeanServer interface + // + //-------------------------------------------- + //-------------------------------------------- + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"addNotificationListener"); + } + } + + @Override + public void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"addNotificationListener"); + } + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name, + params, signature); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + Object params[], + String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName, + params, signature); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[]) + * MBeanServer} + **/ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().deserialize(sourceName,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(String,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + try { + return source().deserialize(className,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, + byte[] data) + throws + InstanceNotFoundException, + OperationsException, + ReflectionException { + try { + return source().deserialize(className,loaderName,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public Object getAttribute(ObjectName name, String attribute) + throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException { + try { + return super.getAttribute(name, attribute); + } catch (IOException x) { + throw handleIOException(x,"getAttribute"); + } + } + + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.getAttributes(name, attributes); + } catch (IOException x) { + throw handleIOException(x,"getAttributes"); + } + } + + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(loaderName); + try { + return source().getClassLoader(sourceName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(mbeanName); + try { + return source().getClassLoaderFor(sourceName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public ClassLoaderRepository getClassLoaderRepository() { + try { + return source().getClassLoaderRepository(); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public String getDefaultDomain() { + try { + return super.getDefaultDomain(); + } catch (IOException x) { + throw handleIOException(x,"getDefaultDomain"); + } + } + + @Override + public String[] getDomains() { + try { + return super.getDomains(); + } catch (IOException x) { + throw handleIOException(x,"getDomains"); + } + } + + @Override + public Integer getMBeanCount() { + try { + return super.getMBeanCount(); + } catch (IOException x) { + throw handleIOException(x,"getMBeanCount"); + } + } + + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws + InstanceNotFoundException, + IntrospectionException, + ReflectionException { + try { + return super.getMBeanInfo(name); + } catch (IOException x) { + throw handleIOException(x,"getMBeanInfo"); + } + } + + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + return super.getObjectInstance(name); + } catch (IOException x) { + throw handleIOException(x,"getObjectInstance"); + } + } + + public Object instantiate(String className) + throws ReflectionException, MBeanException { + try { + return source().instantiate(className); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, + Object params[], + String signature[]) + throws ReflectionException, MBeanException { + try { + return source().instantiate(className, + params,signature); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + final ObjectName srcLoaderName = toSourceOrRuntime(loaderName); + try { + return source().instantiate(className,srcLoaderName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, ObjectName loaderName, + Object params[], String signature[]) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + final ObjectName srcLoaderName = toSourceOrRuntime(loaderName); + try { + return source().instantiate(className,srcLoaderName, + params,signature); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws + InstanceNotFoundException, + MBeanException, + ReflectionException { + try { + return super.invoke(name,operationName,params,signature); + } catch (IOException x) { + throw handleIOException(x,"invoke"); + } + } + + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + return super.isInstanceOf(name, className); + } catch (IOException x) { + throw handleIOException(x,"isInstanceOf"); + } + } + + @Override + public boolean isRegistered(ObjectName name) { + try { + return super.isRegistered(name); + } catch (IOException x) { + throw handleIOException(x,"isRegistered"); + } + } + + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + try { + return super.queryMBeans(name, query); + } catch (IOException x) { + handleIOException(x,"queryMBeans"); + return Collections.emptySet(); + } + } + + @Override + public Set queryNames(ObjectName name, QueryExp query) { + try { + return super.queryNames(name, query); + } catch (IOException x) { + handleIOException(x,"queryNames"); + return Collections.emptySet(); + } + } + + public ObjectInstance registerMBean(Object object, ObjectName name) + throws + InstanceAlreadyExistsException, + MBeanRegistrationException, + NotCompliantMBeanException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + return processOutputInstance( + source().registerMBean(object,sourceName)); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws + InstanceNotFoundException, + AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException { + try { + super.setAttribute(name, attribute); + } catch (IOException x) { + throw handleIOException(x,"setAttribute"); + } + } + + @Override + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.setAttributes(name, attributes); + } catch (IOException x) { + throw handleIOException(x,"setAttributes"); + } + } + + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + super.unregisterMBean(name); + } catch (IOException x) { + throw handleIOException(x,"unregisterMBean"); + } + } + + + public static MBeanServer cd(MBeanServer source, String sourcePath) { + if (source == null) throw new IllegalArgumentException("null"); + if (source.getClass().equals(RoutingServerProxy.class)) { + // cast is OK here, but findbugs complains unless we use class.cast + final RoutingServerProxy other = + RoutingServerProxy.class.cast(source); + final String target = other.getTargetNamespace(); + + // Avoid multiple layers of serialization. + // + // We construct a new proxy from the original source instead of + // stacking a new proxy on top of the old one. + // - that is we replace + // cd ( cd ( x, dir1), dir2); + // by + // cd (x, dir1//dir2); + // + // We can do this only when the source class is exactly + // NamespaceServerProxy. + // + if (target == null || target.equals("")) { + final String path = + JMXNamespaces.concat(other.getSourceNamespace(), + sourcePath); + return new RoutingServerProxy(other.source(),path,"", + other.forwardsContext); + } + // Note: we could do possibly something here - but it would involve + // removing part of targetDir, and possibly adding + // something to sourcePath. + // Too complex to bother! => simply default to stacking... + } + return new RoutingServerProxy(source,sourcePath); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/package.html Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,45 @@ + + + + + The + + + +com.sun.jmx.namespace
packageThe
+com.sun.jmx.namespace
package contains + sun specific implementation classes used to implement the + JMX namespaces. +DO NOT USE THESE CLASSES DIRECTLY
++ This API is a Sun internal API and is subject to changes without notice. +
+The public API through wich these proprietary classes can be + invoked is located in
+ + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,150 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class DefaultRewritingProcessor. Rewrite ObjectName in input & output + * parameters. + *javax.management.namespace
+ package. ++ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +// We know that rewriting using serialization is costly. +// This object tries to determine whether an object needs rewriting prior +// to rewriting, and rewrites by creating a new object in those cases +// where we know how to recreate a new object (e.g. a Notification). +// Rewriting is however usually not used - so this object is just a +// skeleton that eventually uses serialization... +// +class DefaultRewritingProcessor extends RewritingProcessor { + + + private static enum RewriteMode { + INPUT, // Input from target to source (parameters) + OUTPUT // Output from source to target (results) + }; + + private final boolean identity; + + public DefaultRewritingProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of SerialParamProcessor */ + public DefaultRewritingProcessor(final String remove, final String add) { + super(new SerialRewritingProcessor(remove, add)); + identity = remove.equals(add); + } + + private ObjectName rewriteObjectName(RewriteMode mode, + ObjectName name) { + return changeContext(mode, name); + } + + private ObjectInstance rewriteObjectInstance(RewriteMode mode, + ObjectInstance moi) { + final ObjectName srcName = moi.getObjectName(); + final ObjectName targetName = changeContext(mode,srcName); + if (targetName == srcName) return moi; + return new ObjectInstance(targetName,moi.getClassName()); + } + + + private Object processObject(RewriteMode mode, Object obj) { + if (obj == null) return null; + + // Some things which will always needs rewriting: + // ObjectName, ObjectInstance, and Notifications. + // Take care of those we can handle here... + // + if (obj instanceof ObjectName) + return rewriteObjectName(mode,(ObjectName) obj); + else if (obj instanceof ObjectInstance) + return rewriteObjectInstance(mode,(ObjectInstance) obj); + + // TODO: add other standard JMX classes - like e.g. MBeanInfo... + // + + // Well, the object may contain an ObjectName => pass it to + // our serial rewriting delegate... + // + return processAnyObject(mode,obj); + } + + + private Object processAnyObject(RewriteMode mode, Object obj) { + switch (mode) { + case INPUT: + return super.rewriteInput(obj); + case OUTPUT: + return super.rewriteOutput(obj); + default: // can't happen. + throw new AssertionError(); + } + } + + private ObjectName changeContext(RewriteMode mode, ObjectName name) { + switch (mode) { + case INPUT: + return toSourceContext(name); + case OUTPUT: + return toTargetContext(name); + default: // can't happen. + throw new AssertionError(); + } + } + + @Override + public ObjectName toTargetContext(ObjectName srcName) { + if (identity) return srcName; + return super.toTargetContext(srcName); + } + + @Override + public ObjectName toSourceContext(ObjectName targetName) { + if (identity) return targetName; + return super.toSourceContext(targetName); + } + + @SuppressWarnings("unchecked") + @Override + publicT rewriteInput(T input) { + if (identity) return input; + return (T) processObject(RewriteMode.INPUT,input); + } + + @SuppressWarnings("unchecked") + @Override + public T rewriteOutput(T result) { + if (identity) return result; + return (T) processObject(RewriteMode.OUTPUT,result); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input & results... + * + * This API is a Sun internal API and is subject to changes without notice. + *
+ * + * @since 1.7 + */ +class IdentityProcessor extends RewritingProcessor { + + + /** Creates a new instance of SerialRewritingProcessor */ + public IdentityProcessor() { + } + + @Override + publicT rewriteOutput(T result) { + return result; + } + + @Override + public T rewriteInput(T input) { + return input; + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return sourceName; + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return sourceMoi; + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return targetName; + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,145 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + +import com.sun.jmx.defaults.JmxProperties; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * The JMXNamespaceContext class is used to implement a thread local + * serialization / deserialization context for namespaces. + * + * This class is consulted by {@link javax.management.ObjectName} at + * serialization / deserialization time. + * The serialization or deserialization context is established by + * by the {@link SerialRewritingProcessor} defined in this package. + *
+ * These classes are Sun proprietary APIs, subject to change without + * notice. Do not use these classes directly. + * The public API to rewrite ObjectNames embedded in parameters is + * defined in {@link javax.management.namespace.JMXNamespaces}. + * + *
+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class JMXNamespaceContext { + + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + public final String prefixToRemove; + public final String prefixToAdd; + + private JMXNamespaceContext(String add, String remove) { + prefixToRemove = (remove==null?"":remove); + prefixToAdd = (add==null?"":add); + } + + private final static class SerialContext { + private JMXNamespaceContext serializationContext; + private JMXNamespaceContext deserializationContext; + public SerialContext(){ + serializationContext = new JMXNamespaceContext("",""); + deserializationContext = new JMXNamespaceContext("",""); + } + } + + private final static ThreadLocalprefix = + new ThreadLocal () { + @Override + protected SerialContext initialValue() { + return new SerialContext(); + } + }; + + public static JMXNamespaceContext getSerializationContext() { + return prefix.get().serializationContext; + } + + public static JMXNamespaceContext getDeserializationContext() { + return prefix.get().deserializationContext; + } + + private static String[] setSerializationContext(String oldPrefix, + String newPrefix) { + final SerialContext c = prefix.get(); + JMXNamespaceContext dc = c.serializationContext; + String[] old = {dc.prefixToRemove, dc.prefixToAdd}; + c.serializationContext = new JMXNamespaceContext(newPrefix,oldPrefix); + return old; + } + + private static String[] setDeserializationContext(String oldPrefix, + String newPrefix) { + final SerialContext c = prefix.get(); + JMXNamespaceContext dc = c.deserializationContext; + String[] old = {dc.prefixToRemove, dc.prefixToAdd}; + c.deserializationContext = new JMXNamespaceContext(newPrefix,oldPrefix); + return old; + } + + static void serialize(ObjectOutputStream stream, Object obj, + String prefixToRemove, String prefixToAdd) + throws IOException { + final String[] old = + setSerializationContext(prefixToRemove,prefixToAdd); + try { + stream.writeObject(obj); + } finally { + try { + setSerializationContext(old[0],old[1]); + } catch (Exception x) { + LOG.log(Level.FINEST, + "failed to restore serialization context",x); + } + } + } + + static Object deserialize(ObjectInputStream stream, + String prefixToRemove, + String prefixToAdd) + throws IOException, ClassNotFoundException { + final String[] old = + setDeserializationContext(prefixToRemove,prefixToAdd); + try { + return stream.readObject(); + } finally { + try { + setDeserializationContext(old[0],old[1]); + } catch (Exception x) { + LOG.log(Level.FINEST, + "failed to restore serialization context",x); + } + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,362 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * An object that can rewrite ObjectNames contained in input/output + * parameters when entering/leaving a {@link javax.management.namespace + * namespace}. + * When entering a {@link javax.management.namespace + * namespace}, the {@code namespace} prefix is stripped from + * ObjectNames contained in input parameters. When leaving a + * {@code namespace}, + * the {@code namespace} prefix is prepended to the ObjectNames contained in + * the result parameters returned from that {@code namespace}. + *
+ *Objects that need to perform these operations usually use a + * {@code RewritingProcessor} for that purpose.
+ *
+ * The {@code RewritingProcessor} allows a somewhat larger + * transformation in which part of a prefix {@link #newRewritingProcessor + * remove} can be replaced by another prefix {@link #newRewritingProcessor + * add}. The transformation described above correspond to the case where + * {@code remove} is the stripped {@link javax.management.namespace + * namespace} prefix (removed when entering the {@code namespace}) and + * {@code add} is the empty String {@code ""}. + *
+ * It is interesting to note that {@link + * javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace} + * operations use the inverse transformation (that is, {@code remove} is + * the empty String {@code ""} and {@code add} is the {@link + * javax.management.namespace namespace} prefix). + *
+ * On a more general scale, {@link #rewriteInput rewriteInput} removes + * {@link #newRewritingProcessor remove} and the prepend {@link + * #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput} + * does the opposite, removing {@link #newRewritingProcessor add}, and + * then adding {@link #newRewritingProcessor remove}. + *
+ * An implementation of {@code RewritingProcessor} should make sure that + *rewriteInput(rewriteOutput(x,clp),clp)
and + *rewriteOutput(rewriteInput(x,clp),clp)
always return + * {@code x} or an exact clone of {@code x}. + *A default implementation of {@code RewritingProcessor} based on + * Java Object Serialization can be + * obtained from {@link #newRewritingProcessor newRewritingProcessor}. + *
+ *+ * By default, the instances of {@code RewritingProcessor} returned by + * {@link #newRewritingProcessor newRewritingProcessor} will rewrite + * ObjectNames contained in instances of classes they don't know about by + * serializing and then deserializing such object instances. This will + * happen even if such instances don't - or can't contain ObjectNames, + * because the default implementation of {@code RewritingProcessor} will + * not be able to determine whether instances of such classes can/do contain + * instance of ObjectNames before serializing/deserializing them. + *
+ *If you are using custom classes that the default implementation of + * {@code RewritingProcessor} don't know about, it can be interesting to + * prevent an instance of {@code RewritingProcessor} to serialize/deserialize + * instances of such classes for nothing. In that case, you could customize + * the behavior of such a {@code RewritingProcessor} by wrapping it in a + * custom subclass of {@code RewritingProcessor} as shown below: + *
+ * public class MyRewritingProcessor extends RewritingProcessor { + * MyRewritingProcessor(String remove, String add) { + * this(RewritingProcessor.newRewritingProcessor(remove,add)); + * } + * MyRewritingProcessor(RewritingProcessor delegate) { + * super(delegate); + * } + * + *+ *T rewriteInput(T input) { + * if (input == null) return null; + * if (MyClass.equals(input.getClass())) { + * // I know that MyClass doesn't contain any ObjectName + * return (T) input; + * } + * return super.rewriteInput(input); + * } + * T rewriteOutput(T result) { + * if (result == null) return null; + * if (MyClass.equals(result.getClass())) { + * // I know that MyClass doesn't contain any ObjectName + * return (T) result; + * } + * return super.rewriteOutput(result); + * } + * } + * Such a subclass may also provide an alternate way of rewriting + * custom subclasses for which rewriting is needed - for instance: + *
+ * public class MyRewritingProcessor extends RewritingProcessor { + * MyRewritingProcessor(String remove, String add) { + * this(RewritingProcessor.newRewritingProcessor(remove,add)); + * } + * MyRewritingProcessor(RewritingProcessor delegate) { + * super(delegate); + * } + * + *+ *T rewriteInput(T input) { + * if (input == null) return null; + * if (MyClass.equals(input.getClass())) { + * // I know that MyClass doesn't contain any ObjectName + * return (T) input; + * } else if (MyOtherClass.equals(input.getClass())) { + * // Returns a new instance in which ObjectNames have been + * // replaced. + * final ObjectName aname = ((MyOtherClass)input).getName(); + * return (T) (new MyOtherClass(super.rewriteInput(aname))); + * } + * return super.rewriteInput(input,clp); + * } + * T rewriteOutput(T result) { + * if (result == null) return null; + * if (MyClass.equals(result.getClass())) { + * // I know that MyClass doesn't contain any ObjectName + * return (T) result; + * } else if (MyOtherClass.equals(result.getClass())) { + * // Returns a new instance in which ObjectNames have been + * // replaced. + * final ObjectName aname = ((MyOtherClass)result).getName(); + * return (T) (new MyOtherClass(super.rewriteOutput(aname))); + * } + * return super.rewriteOutput(result,clp); + * } + * } + * If your application only uses {@link javax.management.MXBean MXBeans}, + * or MBeans using simple types, and doesn't define any custom subclass of + * {@link javax.management.Notification}, you should never write such + * such {@code RewitingProcessor} implementations. + *
+ *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class RewritingProcessor { + /** + * A logger for this class. + **/ + private final RewritingProcessor delegate; + + /** + * Creates a new instance of RewritingProcessor. + *This is equivalent to calling {@link + * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}. + *
+ **/ + protected RewritingProcessor() { + this(null); + } + + /** + * Creates a new instance of RewritingProcessor, with a delegate. + * @param delegate a {@code RewritingProcessor} to which all the + * calls will be delegated. When implementing a subclass + * of {@code RewritingProcessor}, calling {@link + * #rewriteInput super.rewriteInput} will invoke + * {@code delegate.rewriteInput} and calling {@link + * #rewriteOutput super.rewriteOutput} will invoke + * {@code delegate.rewriteOutput}. + * + **/ + protected RewritingProcessor(RewritingProcessor delegate) { + this.delegate = delegate; + } + + /** + * Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link + * javax.management.namespace namespace}. + *+ * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteOutput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + publicT rewriteOutput(T obj) { + if (obj == null) return null; + if (delegate != null) + return delegate.rewriteOutput(obj); + throw new IllegalArgumentException("can't rewrite "+ + obj.getClass().getName()); + } + + /** + * Rewrites ObjectNames when {@link RewritingProcessor entering} a {@link + * javax.management.namespace namespace}. + * + * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteInput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + publicT rewriteInput(T obj) { + if (obj == null) return null; + if (delegate != null) + return delegate.rewriteInput(obj); + throw new IllegalArgumentException("can't rewrite "+ + obj.getClass().getName()); + } + + /** + * Translate a routing ObjectName from the target (calling) context to + * the source (called) context when {@link RewritingProcessor entering} a + * {@link javax.management.namespace namespace}. + * + * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toSourceContext(targetName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param targetName The routing target ObjectName to translate. + * @return The ObjectName translated to the source context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toSourceContext(ObjectName targetName) { + if (delegate != null) + return delegate.toSourceContext(targetName); + throw new IllegalArgumentException("can't rewrite targetName: "+ + " no delegate."); + } + + /** + * Translate an ObjectName returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceName The routing source ObjectName to translate to the + * target context. + * @return The ObjectName translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toTargetContext(ObjectName sourceName) { + if (delegate != null) + return delegate.toTargetContext(sourceName); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Translate an ObjectInstance returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceMoi)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceMoi The routing source ObjectInstance to translate. + * @return The ObjectInstance translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + if (delegate != null) + return delegate.toTargetContext(sourceMoi); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Creates a new default instance of {@link RewritingProcessor}. + * @param remove The prefix to remove from {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace}. + * @param add The prefix to add to {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace} (this is performed + * after having removed the {@code remove} prefix. + * @return A new {@link RewritingProcessor} processor object that will + * perform the requested operation, using Java serialization if + * necessary. + **/ + public static RewritingProcessor newRewritingProcessor(String remove, + String add) { + return new DefaultRewritingProcessor(remove,add); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + +import com.sun.jmx.namespace.ObjectNameRouter; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input and results... + * + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class RoutingOnlyProcessor extends RewritingProcessor { + + final ObjectNameRouter router; + + public RoutingOnlyProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of RoutingOnlyProcessor */ + public RoutingOnlyProcessor(final String remove, final String add) { + super(new IdentityProcessor()); + if (remove == null || add == null) + throw new IllegalArgumentException("Null argument"); + router = new ObjectNameRouter(remove,add); + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return router.toTargetContext(sourceName,false); + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return router.toSourceContext(targetName,false); + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return router.toTargetContext(sourceMoi,false); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.namespace.serial; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.Queue; + +import javax.management.ObjectName; + +/** + * Class SerialRewritingProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input & results... + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class SerialRewritingProcessor extends RewritingProcessor { + + + private static class CloneOutput extends ObjectOutputStream { + Queue> classQueue = new LinkedList >(); + + CloneOutput(OutputStream out) throws IOException { + super(out); + } + + @Override + protected void annotateClass(Class> c) { + classQueue.add(c); + } + + @Override + protected void annotateProxyClass(Class> c) { + classQueue.add(c); + } + } + + private static class CloneInput extends ObjectInputStream { + private final CloneOutput output; + + CloneInput(InputStream in, CloneOutput output) throws IOException { + super(in); + this.output = output; + } + + @Override + protected Class> resolveClass(ObjectStreamClass osc) + throws IOException, ClassNotFoundException { + Class> c = output.classQueue.poll(); + String expected = osc.getName(); + String found = (c == null) ? null : c.getName(); + if (!expected.equals(found)) { + throw new InvalidClassException("Classes desynchronized: " + + "found " + found + " when expecting " + expected); + } + return c; + } + + @Override + protected Class> resolveProxyClass(String[] interfaceNames) + throws IOException, ClassNotFoundException { + return output.classQueue.poll(); + } + } + + + final String targetPrefix; + final String sourcePrefix; + final boolean identity; + + + public SerialRewritingProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of SerialRewritingProcessor */ + public SerialRewritingProcessor(final String remove, final String add) { + super(new RoutingOnlyProcessor(remove,add)); + this.targetPrefix = remove; + this.sourcePrefix = add; + identity = targetPrefix.equals(sourcePrefix); + } + + private T switchContext(T result, String from,String to) + throws IOException, ClassNotFoundException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final CloneOutput ostream = new CloneOutput(baos); + + JMXNamespaceContext.serialize(ostream,result,from,null); + ostream.flush(); + + final byte[] bytes = baos.toByteArray(); + final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + final CloneInput istream = new CloneInput(bais, ostream); + @SuppressWarnings("unchecked") + final T clone = (T) JMXNamespaceContext.deserialize(istream,null,to); + return clone; + } + + @Override + @SuppressWarnings("unchecked") + public T rewriteOutput(T result) { + if (identity) return result; + return (T) processOutput(result); + } + + private Object processOutput(Object result) { + try { + if (result instanceof ObjectName) + return toTargetContext((ObjectName) result); + return switchContext(result,sourcePrefix,targetPrefix); + } catch (ClassNotFoundException x) { + throw new IllegalArgumentException("Can't process result: "+x,x); + } catch (IOException x) { + throw new IllegalArgumentException("Can't process result: "+x,x); + } + } + + @Override + @SuppressWarnings("unchecked") + public T rewriteInput(T input) { + if (identity) return input; + return (T) processInput(input); + } + + private Object processInput(Object input) { + try { + if (input instanceof ObjectName) + return toSourceContext((ObjectName) input); + return switchContext(input,targetPrefix,sourcePrefix); + } catch (ClassNotFoundException x) { + throw new IllegalArgumentException("Can't process input: "+x,x); + } catch (IOException x) { + throw new IllegalArgumentException("Can't process input: "+x,x); + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/namespace/serial/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/package.html Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,44 @@ + + + + + The + + + +com.sun.jmx.namespace.serial
packageThe
+com.sun.jmx.namespace.serial
package contains + sun specific implementation classes used to switch namespace + prefixes in ObjectName during serialization. +NEVER USE THESE CLASSES DIRECTLY
++ This API is a Sun internal API and is subject to changes without notice. +
+The public API through which these proprietary classes can be invoked is + located in
+ + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java --- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java Wed Jul 05 16:41:30 2017 +0200 @@ -57,6 +57,7 @@ public class ServerNotifForwarder { + public ServerNotifForwarder(MBeanServer mbeanServer, Map env, NotificationBuffer notifBuffer, @@ -85,7 +86,8 @@ // Explicitly check MBeanPermission for addNotificationListener // - checkMBeanPermission(name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); if (notificationAccessController != null) { notificationAccessController.addNotificationListener( connectionId, name, getSubject()); @@ -155,7 +157,8 @@ // Explicitly check MBeanPermission for removeNotificationListener // - checkMBeanPermission(name, "removeNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "removeNotificationListener"); if (notificationAccessController != null) { notificationAccessController.removeNotificationListener( connectionId, name, getSubject()); @@ -330,13 +333,7 @@ * Explicitly check the MBeanPermission for * the current access control context. */ - private void checkMBeanPermission(final ObjectName name, - final String actions) - throws InstanceNotFoundException, SecurityException { - checkMBeanPermission(mbeanServer, name, actions); - } - - public static void checkMBeanPermission( + public static void checkMBeanPermission(String serverName, final MBeanServer mbs, final ObjectName name, final String actions) throws InstanceNotFoundException, SecurityException { SecurityManager sm = System.getSecurityManager(); @@ -355,7 +352,9 @@ throw (InstanceNotFoundException) extractException(e); } String classname = oi.getClassName(); - MBeanPermission perm = new MBeanPermission(classname, + MBeanPermission perm = new MBeanPermission( + serverName, + classname, null, name, actions); @@ -370,8 +369,8 @@ TargetedNotification tn) { try { if (checkNotificationEmission) { - checkMBeanPermission( - name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); } if (notificationAccessController != null) { notificationAccessController.fetchNotification( @@ -433,11 +432,27 @@ } } + private String getMBeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedActionjavax.management.namespace.JMXNamespaces
+action = new PrivilegedAction () { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + + //------------------ // PRIVATE VARIABLES //------------------ private MBeanServer mbeanServer; + private volatile String mbeanServerName; private final String connectionId; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java --- a/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,6 +25,7 @@ package com.sun.jmx.remote.util; +import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.event.EventClientFactory; import java.lang.reflect.InvocationHandler; @@ -45,6 +46,7 @@ import javax.management.ObjectName; import javax.management.event.EventClient; import javax.management.event.EventClientDelegate; +import javax.management.namespace.JMXNamespaces; /** * Class EventClientConnection - a {@link Proxy} that wraps an @@ -63,12 +65,10 @@ /** * A logger for this class. **/ - private static final Logger LOG = - Logger.getLogger(EventClientConnection.class.getName()); + private static final Logger LOG = JmxProperties.NOTIFICATION_LOGGER; - private static final String NAMESPACE_SEPARATOR = "//"; private static final int NAMESPACE_SEPARATOR_LENGTH = - NAMESPACE_SEPARATOR.length(); + JMXNamespaces.NAMESPACE_SEPARATOR.length(); /** * Creates a new {@code EventClientConnection}. @@ -212,9 +212,9 @@ } final ObjectName mbean = (ObjectName) args[0]; - final EventClient client = getEventClient(); + final EventClient evtClient = getEventClient(); - // Fails if client is null AND the MBean we try to listen to is + // Fails if evtClient is null AND the MBean we try to listen to is // in a subnamespace. We fail here because we know this will not // work. // @@ -222,15 +222,15 @@ // earlier agent (JDK 1.6 or earlier), then the EventClient will // be null (we can't use the event service with earlier JDKs). // - // In principle a null client indicates that the remote VM is of + // In principle a null evtClient indicates that the remote VM is of // an earlier version, in which case it shouldn't contain any namespace. // - // So having a null client AND an MBean contained in a namespace is + // So having a null evtClient AND an MBean contained in a namespace is // clearly an error case. // - if (client == null) { + if (evtClient == null) { final String domain = mbean.getDomain(); - final int index = domain.indexOf(NAMESPACE_SEPARATOR); + final int index = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); if (index > -1 && index < (domain.length()-NAMESPACE_SEPARATOR_LENGTH)) { throw new UnsupportedOperationException(method.getName()+ @@ -256,9 +256,9 @@ final NotificationFilter filter = (NotificationFilter) args[2]; final Object handback = args[3]; - if (client != null) { + if (evtClient != null) { // general case - client.addNotificationListener(mbean,listener,filter,handback); + evtClient.addNotificationListener(mbean,listener,filter,handback); } else { // deprecated case. Only works for mbean in local namespace. connection.addNotificationListener(mbean,listener,filter, @@ -274,9 +274,9 @@ switch (nargs) { case 2: - if (client != null) { + if (evtClient != null) { // general case - client.removeNotificationListener(mbean,listener); + evtClient.removeNotificationListener(mbean,listener); } else { // deprecated case. Only works for mbean in local namespace. connection.removeNotificationListener(mbean, listener); @@ -286,8 +286,8 @@ case 4: NotificationFilter filter = (NotificationFilter) args[2]; Object handback = args[3]; - if (client != null) { - client.removeNotificationListener(mbean, + if (evtClient != null) { + evtClient.removeNotificationListener(mbean, listener, filter, handback); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/tools/extcheck/ExtCheck.java --- a/jdk/src/share/classes/com/sun/tools/extcheck/ExtCheck.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/extcheck/ExtCheck.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,13 +256,13 @@ private boolean isNotOlderThan(String already,String target) throws NumberFormatException { - if (already == null || already.length() < 1) { + if (already == null || already.length() < 1) { throw new NumberFormatException("Empty version string"); } - // Until it matches scan and compare numbers - StringTokenizer dtok = new StringTokenizer(target, ".", true); - StringTokenizer stok = new StringTokenizer(already, ".", true); + // Until it matches scan and compare numbers + StringTokenizer dtok = new StringTokenizer(target, ".", true); + StringTokenizer stok = new StringTokenizer(already, ".", true); while (dtok.hasMoreTokens() || stok.hasMoreTokens()) { int dver; int sver; @@ -276,19 +276,19 @@ } else sver = 0; - if (sver < dver) - return false; // Known to be incompatible - if (sver > dver) - return true; // Known to be compatible + if (sver < dver) + return false; // Known to be incompatible + if (sver > dver) + return true; // Known to be compatible - // Check for and absorb separators - if (dtok.hasMoreTokens()) - dtok.nextToken(); - if (stok.hasMoreTokens()) - stok.nextToken(); - // Compare next component - } - // All components numerically equal + // Check for and absorb separators + if (dtok.hasMoreTokens()) + dtok.nextToken(); + if (stok.hasMoreTokens()) + stok.nextToken(); + // Compare next component + } + // All components numerically equal return true; } @@ -307,11 +307,10 @@ } /** - * Print out the error message and exit from the program + * Throws a RuntimeException with a message describing the error. */ - static void error(String message){ - System.err.println(message); - System.exit(-1); + static void error(String message) throws RuntimeException { + throw new RuntimeException(message); } @@ -356,19 +355,19 @@ } private JarFile findJarFile(URL url) throws IOException { - // Optimize case where url refers to a local jar file - if ("file".equals(url.getProtocol())) { - String path = url.getFile().replace('/', File.separatorChar); - File file = new File(path); - if (!file.exists()) { - throw new FileNotFoundException(path); - } - return new JarFile(path); - } - URLConnection uc = getBaseURL().openConnection(); - //uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION); - return ((JarURLConnection)uc).getJarFile(); - } + // Optimize case where url refers to a local jar file + if ("file".equals(url.getProtocol())) { + String path = url.getFile().replace('/', File.separatorChar); + File file = new File(path); + if (!file.exists()) { + throw new FileNotFoundException(path); + } + return new JarFile(path); + } + URLConnection uc = getBaseURL().openConnection(); + //uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION); + return ((JarURLConnection)uc).getJarFile(); + } /* diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/tools/extcheck/Main.java --- a/jdk/src/share/classes/com/sun/tools/extcheck/Main.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/extcheck/Main.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,10 @@ */ public final class Main { - + public static final String INSUFFICIENT = "Insufficient number of arguments"; + public static final String MISSING = "Missing argument"; + public static final String DOES_NOT_EXIST = "Jarfile does not exist: "; + public static final String EXTRA = "Extra command line argument: "; /** * Terminates with one of the following codes @@ -40,26 +43,36 @@ * 0 No newer jar file was found * -1 An internal error occurred */ - public static void main(String args[]){ + public static void main(String args[]) { + try { + realMain(args); + } catch (Exception ex) { + System.err.println(ex.getMessage()); + System.exit(-1); + } + } - if (args.length < 1){ - System.err.println("Usage: extcheck [-verbose] "); - System.exit(-1); + public static void realMain(String[] args) throws Exception { + if (args.length < 1) { + usage(INSUFFICIENT); } int argIndex = 0; boolean verboseFlag = false; - if (args[argIndex].equals("-verbose")){ + if (args[argIndex].equals("-verbose")) { verboseFlag = true; argIndex++; + if (argIndex >= args.length) { + usage(MISSING); + } } String jarName = args[argIndex]; argIndex++; File jarFile = new File(jarName); if (!jarFile.exists()){ - ExtCheck.error("Jarfile " + jarName + " does not exist"); + usage(DOES_NOT_EXIST + jarName); } if (argIndex < args.length) { - ExtCheck.error("Extra command line argument :"+args[argIndex]); + usage(EXTRA + args[argIndex]); } ExtCheck jt = ExtCheck.create(jarFile,verboseFlag); boolean result = jt.checkInstalledAgainstTarget(); @@ -68,7 +81,10 @@ } else { System.exit(1); } - } + private static void usage(String msg) throws Exception { + throw new Exception(msg + "\nUsage: extcheck [-verbose] "); + } } + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java Wed Jul 05 16:41:30 2017 +0200 @@ -120,7 +120,7 @@ private int version; // The version of .hprof being read private int debugLevel; - private int currPos; // Current position in the file + private long currPos; // Current position in the file private int dumpsToSkip; private boolean callStack; // If true, read the call stack of objects @@ -196,7 +196,9 @@ break; } in.readInt(); // Timestamp of this record - int length = in.readInt(); + // Length of record: readInt() will return negative value for record + // length >2GB. so store 32bit value in long to keep it unsigned. + long length = in.readInt() & 0xffffffffL; if (debugLevel > 0) { System.out.println("Read record type " + type + ", length " + length @@ -211,7 +213,7 @@ switch (type) { case HPROF_UTF8: { long id = readID(); - byte[] chars = new byte[length - identifierSize]; + byte[] chars = new byte[(int)length - identifierSize]; in.readFully(chars); names.put(new Long(id), new String(chars)); break; @@ -351,8 +353,8 @@ return snapshot; } - private void skipBytes(int length) throws IOException { - in.skipBytes(length); + private void skipBytes(long length) throws IOException { + in.skipBytes((int)length); } private int readVersionHeader() throws IOException { @@ -381,7 +383,7 @@ throw new IOException("Version string not recognized at byte " + (pos+3)); } - private void readHeapDump(int bytesLeft, int posAtEnd) throws IOException { + private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException { while (bytesLeft > 0) { int type = in.readUnsignedByte(); if (debugLevel > 0) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Button.java --- a/jdk/src/share/classes/java/awt/Button.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Button.java Wed Jul 05 16:41:30 2017 +0200 @@ -213,8 +213,8 @@ } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Checkbox.java --- a/jdk/src/share/classes/java/awt/Checkbox.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Checkbox.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -284,8 +284,8 @@ } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Choice.java --- a/jdk/src/share/classes/java/awt/Choice.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Choice.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,9 +207,7 @@ } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -269,9 +267,7 @@ } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -299,9 +295,7 @@ } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -323,9 +317,7 @@ } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -367,9 +359,7 @@ } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Component.java --- a/jdk/src/share/classes/java/awt/Component.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Component.java Wed Jul 05 16:41:30 2017 +0200 @@ -350,7 +350,7 @@ * @see #validate * @see #invalidate */ - volatile boolean valid = false; + private volatile boolean valid = false; /** * The DropTarget
associated with this component. @@ -639,11 +639,21 @@ */ private PropertyChangeSupport changeSupport; - // Note: this field is considered final, though readObject() prohibits - // initializing final fields. - private transient Object changeSupportLock = new Object(); - private Object getChangeSupportLock() { - return changeSupportLock; + /* + * In some cases using "this" as an object to synchronize by + * can lead to a deadlock if client code also uses synchronization + * by a component object. For every such situation revealed we should + * consider possibility of replacing "this" with the package private + * objectLock object introduced below. So far there're 2 issues known: + * - CR 6708322 (the getName/setName methods); + * - CR 6608764 (the PropertyChangeListener machinery). + * + * Note: this field is considered final, though readObject() prohibits + * initializing final fields. + */ + private transient Object objectLock = new Object(); + Object getObjectLock() { + return objectLock; } boolean isPacked = false; @@ -816,7 +826,7 @@ */ public String getName() { if (name == null && !nameExplicitlySet) { - synchronized(this) { + synchronized(getObjectLock()) { if (name == null && !nameExplicitlySet) name = constructComponentName(); } @@ -833,7 +843,7 @@ */ public void setName(String name) { String oldName; - synchronized(this) { + synchronized(getObjectLock()) { oldName = this.name; this.name = name; nameExplicitlySet = true; @@ -1708,9 +1718,9 @@ // This could change the preferred size of the Component. // Fix for 6213660. Should compare old and new fonts and do not // call invalidate() if they are equal. - if (valid && f != oldFont && (oldFont == null || + if (f != oldFont && (oldFont == null || !oldFont.equals(f))) { - invalidate(); + invalidateIfValid(); } } @@ -1767,9 +1777,7 @@ firePropertyChange("locale", oldValue, l); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -2078,8 +2086,8 @@ if (resized) { invalidate(); } - if (parent != null && parent.valid) { - parent.invalidate(); + if (parent != null) { + parent.invalidateIfValid(); } } if (needNotify) { @@ -2135,7 +2143,7 @@ Toolkit.getEventQueue().postEvent(e); } } else { - if (this instanceof Container && ((Container)this).ncomponents > 0) { + if (this instanceof Container && ((Container)this).countComponents() > 0) { boolean enabledOnToolkit = Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK); if (resized) { @@ -2648,7 +2656,8 @@ public void validate() { synchronized (getTreeLock()) { ComponentPeer peer = this.peer; - if (!valid && peer != null) { + boolean wasValid = isValid(); + if (!wasValid && peer != null) { Font newfont = getFont(); Font oldfont = peerFont; if (newfont != oldfont && (oldfont == null @@ -2659,6 +2668,9 @@ peer.layout(); } valid = true; + if (!wasValid) { + mixOnValidating(); + } } } @@ -2687,9 +2699,17 @@ if (!isMaximumSizeSet()) { maxSize = null; } - if (parent != null && parent.valid) { - parent.invalidate(); - } + if (parent != null) { + parent.invalidateIfValid(); + } + } + } + + /** Invalidates the component unless it is already invalid. + */ + final void invalidateIfValid() { + if (isValid()) { + invalidate(); } } @@ -5794,7 +5814,7 @@ } } - transient EventQueueItem[] eventCache; + transient sun.awt.EventQueueItem[] eventCache; /** * @see #isCoalescingEnabled @@ -7545,9 +7565,7 @@ Container rootAncestor = getTraversalRoot(); Component comp = this; while (rootAncestor != null && - !(rootAncestor.isShowing() && - rootAncestor.isFocusable() && - rootAncestor.isEnabled())) + !(rootAncestor.isShowing() && rootAncestor.canBeFocusOwner())) { comp = rootAncestor; rootAncestor = comp.getFocusCycleRootAncestor(); @@ -7596,9 +7614,7 @@ Container rootAncestor = getTraversalRoot(); Component comp = this; while (rootAncestor != null && - !(rootAncestor.isShowing() && - rootAncestor.isFocusable() && - rootAncestor.isEnabled())) + !(rootAncestor.isShowing() && rootAncestor.canBeFocusOwner())) { comp = rootAncestor; rootAncestor = comp.getFocusCycleRootAncestor(); @@ -7777,7 +7793,7 @@ protected String paramString() { String thisName = getName(); String str = (thisName != null? thisName : "") + "," + x + "," + y + "," + width + "x" + height; - if (!valid) { + if (!isValid()) { str += ",invalid"; } if (!visible) { @@ -7905,7 +7921,7 @@ */ public void addPropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -7931,7 +7947,7 @@ */ public void removePropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -7954,7 +7970,7 @@ * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners() { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -7996,7 +8012,7 @@ public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -8026,7 +8042,7 @@ public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -8050,7 +8066,7 @@ */ public PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -8071,7 +8087,7 @@ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { PropertyChangeSupport changeSupport; - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { changeSupport = this.changeSupport; } if (changeSupport == null || @@ -8373,7 +8389,7 @@ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - changeSupportLock = new Object(); + objectLock = new Object(); s.defaultReadObject(); @@ -8537,9 +8553,7 @@ firePropertyChange("componentOrientation", oldValue, o); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -8575,6 +8589,14 @@ setComponentOrientation(orientation); } + final boolean canBeFocusOwner() { + // It is enabled, visible, focusable. + if (isEnabled() && isDisplayable() && isVisible() && isFocusable()) { + return true; + } + return false; + } + /** * Checks that this component meets the prerequesites to be focus owner: * - it is enabled, visible, focusable @@ -8584,9 +8606,9 @@ * this component as focus owner * @since 1.5 */ - final boolean canBeFocusOwner() { + final boolean canBeFocusOwnerRecursively() { // - it is enabled, visible, focusable - if (!(isEnabled() && isDisplayable() && isVisible() && isFocusable())) { + if (!canBeFocusOwner()) { return false; } @@ -9381,7 +9403,8 @@ */ private boolean areBoundsValid() { Container cont = getContainer(); - return cont == null || cont.isValid() || cont.getLayout() == null; + return cont == null || cont.isValid() + || cont.getLayout() == null; } /** @@ -9652,5 +9675,10 @@ } } + void mixOnValidating() { + // This method gets overriden in the Container. Obviously, a plain + // non-container components don't need to handle validation. + } + // ****************** END OF MIXING CODE ******************************** } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Container.java --- a/jdk/src/share/classes/java/awt/Container.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Container.java Wed Jul 05 16:41:30 2017 +0200 @@ -44,8 +44,6 @@ import java.util.Arrays; import java.util.EventListener; import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; import java.util.Set; import java.util.logging.*; @@ -90,21 +88,14 @@ private static final Logger log = Logger.getLogger("java.awt.Container"); private static final Logger eventLog = Logger.getLogger("java.awt.event.Container"); - /** - * The number of components in this container. - * This value can be null. - * @see #getComponent - * @see #getComponents - * @see #getComponentCount - */ - int ncomponents; + private static final Component[] EMPTY_ARRAY = new Component[0]; /** * The components in this container. * @see #add * @see #getComponents */ - Component component[] = new Component[0]; + private java.util.Listcomponent = new java.util.ArrayList (); /** * Layout manager for this container. @@ -290,7 +281,9 @@ */ @Deprecated public int countComponents() { - return ncomponents; + synchronized (getTreeLock()) { + return component.size(); + } } /** @@ -302,10 +295,10 @@ */ public Component getComponent(int n) { synchronized (getTreeLock()) { - if ((n < 0) || (n >= ncomponents)) { + if ((n < 0) || (n >= component.size())) { throw new ArrayIndexOutOfBoundsException("No such child: " + n); } - return component[n]; + return component.get(n); } } @@ -322,7 +315,7 @@ // DO NOT INVOKE CLIENT CODE ON THIS THREAD! final Component[] getComponents_NoClientCode() { synchronized (getTreeLock()) { - return Arrays.copyOf(component, ncomponents); + return component.toArray(EMPTY_ARRAY); } } // getComponents_NoClientCode() @@ -422,6 +415,29 @@ } /** + * Checks that the component + * isn't supposed to be added into itself. + */ + private void checkAddToSelf(Component comp){ + if (comp instanceof Container) { + for (Container cn = this; cn != null; cn=cn.parent) { + if (cn == comp) { + throw new IllegalArgumentException("adding container's parent to itself"); + } + } + } + } + + /** + * Checks that the component is not a Window instance. + */ + private void checkNotAWindow(Component comp){ + if (comp instanceof Window) { + throw new IllegalArgumentException("adding a window to a container"); + } + } + + /** * Checks that the component comp can be added to this container * Checks : index in bounds of container's size, * comp is not one of this container's parents, @@ -437,26 +453,18 @@ GraphicsConfiguration thisGC = getGraphicsConfiguration(); - if (index > ncomponents || index < 0) { + if (index > component.size() || index < 0) { throw new IllegalArgumentException("illegal component position"); } if (comp.parent == this) { - if (index == ncomponents) { + if (index == component.size()) { throw new IllegalArgumentException("illegal component position " + - index + " should be less then " + ncomponents); + index + " should be less then " + component.size()); } } - if (comp instanceof Container) { - for (Container cn = this; cn != null; cn=cn.parent) { - if (cn == comp) { - throw new IllegalArgumentException("adding container's parent to itself"); - } - } - - if (comp instanceof Window) { - throw new IllegalArgumentException("adding a window to a container"); - } - } + checkAddToSelf(comp); + checkNotAWindow(comp); + Window thisTopLevel = getContainingWindow(); Window compTopLevel = comp.getContainingWindow(); if (thisTopLevel != compTopLevel) { @@ -495,25 +503,17 @@ adjustDescendants(-(comp.countHierarchyMembers())); comp.parent = null; - System.arraycopy(component, index + 1, - component, index, - ncomponents - index - 1); - component[--ncomponents] = null; - - if (valid) { - invalidate(); - } + component.remove(index); + + invalidateIfValid(); } else { - if (newIndex > index) { // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452 - if (newIndex-index > 0) { - System.arraycopy(component, index+1, component, index, newIndex-index); - } - } else { // 4->2: 012345 -> 014235 - if (index-newIndex > 0) { - System.arraycopy(component, newIndex, component, newIndex+1, index-newIndex); - } - } - component[newIndex] = comp; + // We should remove component and then + // add it by the newIndex without newIndex decrement if even we shift components to the left + // after remove. Consult the rules below: + // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452 + // 4->2: 012345 -> 014235 + component.remove(index); + component.add(newIndex, comp); } if (comp.parent == null) { // was actually removed if (containerListener != null || @@ -779,17 +779,11 @@ // Check if moving between containers if (curParent != this) { - /* Add component to list; allocate new array if necessary. */ - if (ncomponents == component.length) { - component = Arrays.copyOf(component, ncomponents * 2 + 1); - } - if (index == -1 || index == ncomponents) { - component[ncomponents++] = comp; + //index == -1 means add to the end. + if (index == -1) { + component.add(comp); } else { - System.arraycopy(component, index, component, - index + 1, ncomponents - index); - component[index] = comp; - ncomponents++; + component.add(index, comp); } comp.parent = this; @@ -799,14 +793,12 @@ comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); adjustDescendants(comp.countHierarchyMembers()); } else { - if (index < ncomponents) { - component[index] = comp; + if (index < component.size()) { + component.set(index, comp); } } - if (valid) { - invalidate(); - } + invalidateIfValid(); if (peer != null) { if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one comp.addNotify(); @@ -860,11 +852,11 @@ // If component is focus owner or parent container of focus owner check that after reparenting // focus owner moved out if new container prohibit this kind of focus owner. - if (comp.isFocusOwner() && !comp.canBeFocusOwner()) { + if (comp.isFocusOwner() && !comp.canBeFocusOwnerRecursively()) { comp.transferFocus(); } else if (comp instanceof Container) { Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - if (focusOwner != null && isParentOf(focusOwner) && !focusOwner.canBeFocusOwner()) { + if (focusOwner != null && isParentOf(focusOwner) && !focusOwner.canBeFocusOwnerRecursively()) { focusOwner.transferFocus(); } } @@ -901,14 +893,8 @@ if (comp.parent != this) { return -1; } - for (int i = 0; i < ncomponents; i++) { - if (component[i] == comp) { - return i; - } - } + return component.indexOf(comp); } - // To please javac - return -1; } /** @@ -1042,22 +1028,12 @@ */ GraphicsConfiguration thisGC = this.getGraphicsConfiguration(); - if (index > ncomponents || (index < 0 && index != -1)) { + if (index > component.size() || (index < 0 && index != -1)) { throw new IllegalArgumentException( "illegal component position"); } - if (comp instanceof Container) { - for (Container cn = this; cn != null; cn=cn.parent) { - if (cn == comp) { - throw new IllegalArgumentException( - "adding container's parent to itself"); - } - } - if (comp instanceof Window) { - throw new IllegalArgumentException( - "adding a window to a container"); - } - } + checkAddToSelf(comp); + checkNotAWindow(comp); if (thisGC != null) { comp.checkGD(thisGC.getDevice().getIDstring()); } @@ -1065,22 +1041,16 @@ /* Reparent the component and tidy up the tree's state. */ if (comp.parent != null) { comp.parent.remove(comp); - if (index > ncomponents) { + if (index > component.size()) { throw new IllegalArgumentException("illegal component position"); } } - /* Add component to list; allocate new array if necessary. */ - if (ncomponents == component.length) { - component = Arrays.copyOf(component, ncomponents * 2 + 1); - } - if (index == -1 || index == ncomponents) { - component[ncomponents++] = comp; + //index == -1 means add to the end. + if (index == -1) { + component.add(comp); } else { - System.arraycopy(component, index, component, - index + 1, ncomponents - index); - component[index] = comp; - ncomponents++; + component.add(index, comp); } comp.parent = this; @@ -1090,9 +1060,7 @@ comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); adjustDescendants(comp.countHierarchyMembers()); - if (valid) { - invalidate(); - } + invalidateIfValid(); if (peer != null) { comp.addNotify(); } @@ -1129,11 +1097,9 @@ * IllegalArgumentException. */ void checkGD(String stringID) { - Component tempComp; - for (int i = 0; i < component.length; i++) { - tempComp= component[i]; - if (tempComp != null) { - tempComp.checkGD(stringID); + for (Component comp : component) { + if (comp != null) { + comp.checkGD(stringID); } } } @@ -1163,10 +1129,10 @@ */ public void remove(int index) { synchronized (getTreeLock()) { - if (index < 0 || index >= ncomponents) { + if (index < 0 || index >= component.size()) { throw new ArrayIndexOutOfBoundsException(index); } - Component comp = component[index]; + Component comp = component.get(index); if (peer != null) { comp.removeNotify(); } @@ -1181,14 +1147,9 @@ adjustDescendants(-(comp.countHierarchyMembers())); comp.parent = null; - System.arraycopy(component, index + 1, - component, index, - ncomponents - index - 1); - component[--ncomponents] = null; - - if (valid) { - invalidate(); - } + component.remove(index); + + invalidateIfValid(); if (containerListener != null || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { @@ -1229,14 +1190,9 @@ public void remove(Component comp) { synchronized (getTreeLock()) { if (comp.parent == this) { - /* Search backwards, expect that more recent additions - * are more likely to be removed. - */ - Component component[] = this.component; - for (int i = ncomponents; --i >= 0; ) { - if (component[i] == comp) { - remove(i); - } + int index = component.indexOf(comp); + if (index >= 0) { + remove(index); } } } @@ -1258,9 +1214,8 @@ -listeningBoundsChildren); adjustDescendants(-descendantsCount); - while (ncomponents > 0) { - Component comp = component[--ncomponents]; - component[ncomponents] = null; + while (!component.isEmpty()) { + Component comp = component.remove(component.size()-1); if (peer != null) { comp.removeNotify(); @@ -1286,9 +1241,7 @@ if (peer != null && layoutMgr == null && isVisible()) { updateCursorImmediately(); } - if (valid) { - invalidate(); - } + invalidateIfValid(); } } @@ -1300,8 +1253,8 @@ if (eventLog.isLoggable(Level.FINE)) { // Verify listeningChildren is correct int sum = 0; - for (int i = 0; i < ncomponents; i++) { - sum += component[i].numListening(mask); + for (Component comp : component) { + sum += comp.numListening(mask); } if (listeningChildren != sum) { eventLog.log(Level.FINE, "Assertion (listeningChildren == sum) failed"); @@ -1312,8 +1265,8 @@ if (eventLog.isLoggable(Level.FINE)) { // Verify listeningBoundsChildren is correct int sum = 0; - for (int i = 0; i < ncomponents; i++) { - sum += component[i].numListening(mask); + for (Component comp : component) { + sum += comp.numListening(mask); } if (listeningBoundsChildren != sum) { eventLog.log(Level.FINE, "Assertion (listeningBoundsChildren == sum) failed"); @@ -1375,8 +1328,8 @@ if (log.isLoggable(Level.FINE)) { // Verify descendantsCount is correct int sum = 0; - for (int i = 0; i < ncomponents; i++) { - sum += component[i].countHierarchyMembers(); + for (Component comp : component) { + sum += comp.countHierarchyMembers(); } if (descendantsCount != sum) { log.log(Level.FINE, "Assertion (descendantsCount == sum) failed"); @@ -1408,7 +1361,7 @@ int listeners = getListenersCount(id, enabledOnToolkit); for (int count = listeners, i = 0; count > 0; i++) { - count -= component[i].createHierarchyEvents(id, changed, + count -= component.get(i).createHierarchyEvents(id, changed, changedParent, changeFlags, enabledOnToolkit); } return listeners + @@ -1420,13 +1373,13 @@ boolean enabledOnToolkit) { assert Thread.holdsLock(getTreeLock()); - if (ncomponents == 0) { + if (component.isEmpty()) { return; } int listeners = getListenersCount(id, enabledOnToolkit); for (int count = listeners, i = 0; count > 0; i++) { - count -= component[i].createHierarchyEvents(id, this, parent, + count -= component.get(i).createHierarchyEvents(id, this, parent, changeFlags, enabledOnToolkit); } } @@ -1448,9 +1401,7 @@ */ public void setLayout(LayoutManager mgr) { layoutMgr = mgr; - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -1522,10 +1473,10 @@ */ public void validate() { /* Avoid grabbing lock unless really necessary. */ - if (!valid) { + if (!isValid()) { boolean updateCur = false; synchronized (getTreeLock()) { - if (!valid && peer != null) { + if (!isValid() && peer != null) { ContainerPeer p = null; if (peer instanceof ContainerPeer) { p = (ContainerPeer) peer; @@ -1534,7 +1485,6 @@ p.beginValidate(); } validateTree(); - valid = true; if (p != null) { p.endValidate(); updateCur = isVisible(); @@ -1557,17 +1507,16 @@ * @see #validate */ protected void validateTree() { - if (!valid) { + if (!isValid()) { if (peer instanceof ContainerPeer) { ((ContainerPeer)peer).beginLayout(); } doLayout(); - Component component[] = this.component; - for (int i = 0 ; i < ncomponents ; ++i) { - Component comp = component[i]; + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); if ( (comp instanceof Container) - && !(comp instanceof Window) - && !comp.valid) { + && !(comp instanceof Window) + && !comp.isValid()) { ((Container)comp).validateTree(); } else { comp.validate(); @@ -1577,7 +1526,7 @@ ((ContainerPeer)peer).endLayout(); } } - valid = true; + super.validate(); } /** @@ -1586,20 +1535,16 @@ */ void invalidateTree() { synchronized (getTreeLock()) { - for (int i = 0; i < ncomponents; ++i) { - Component comp = component[i]; + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); if (comp instanceof Container) { ((Container)comp).invalidateTree(); } else { - if (comp.valid) { - comp.invalidate(); - } + comp.invalidateIfValid(); } } - if (valid) { - invalidate(); - } + invalidateIfValid(); } } @@ -1838,7 +1783,7 @@ // super.paint(); -- Don't bother, since it's a NOP. GraphicsCallback.PaintCallback.getInstance(). - runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS); + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.LIGHTWEIGHTS); } } @@ -1893,7 +1838,7 @@ } GraphicsCallback.PrintCallback.getInstance(). - runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS); + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.LIGHTWEIGHTS); } } @@ -1906,7 +1851,7 @@ public void paintComponents(Graphics g) { if (isShowing()) { GraphicsCallback.PaintAllCallback.getInstance(). - runComponents(component, g, GraphicsCallback.TWO_PASSES); + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.TWO_PASSES); } } @@ -1928,7 +1873,7 @@ void paintHeavyweightComponents(Graphics g) { if (isShowing()) { GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance(). - runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS | + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); } } @@ -1942,7 +1887,7 @@ public void printComponents(Graphics g) { if (isShowing()) { GraphicsCallback.PrintAllCallback.getInstance(). - runComponents(component, g, GraphicsCallback.TWO_PASSES); + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.TWO_PASSES); } } @@ -1964,7 +1909,7 @@ void printHeavyweightComponents(Graphics g) { if (isShowing()) { GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance(). - runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS | + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); } } @@ -2260,11 +2205,9 @@ boolean searchHeavyweightChildren, boolean searchHeavyweightDescendants) { synchronized (getTreeLock()) { - int ncomponents = this.ncomponents; - Component component[] = this.component; - - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; + + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); if (comp != null && comp.visible && ((!searchHeavyweightChildren && comp.peer instanceof LightweightPeer) || @@ -2415,8 +2358,8 @@ } synchronized (getTreeLock()) { // Two passes: see comment in sun.awt.SunGraphicsCallback - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); if (comp != null && !(comp.peer instanceof LightweightPeer)) { if (comp.contains(x - comp.x, y - comp.y)) { @@ -2424,8 +2367,8 @@ } } } - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); if (comp != null && comp.peer instanceof LightweightPeer) { if (comp.contains(x - comp.x, y - comp.y)) { @@ -2544,43 +2487,43 @@ if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) { return null; } - int ncomponents = this.ncomponents; - Component component[] = this.component; // Two passes: see comment in sun.awt.SunGraphicsCallback - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; - if (comp != null && - !(comp.peer instanceof LightweightPeer)) { - if (comp instanceof Container) { - comp = ((Container)comp).findComponentAtImpl(x - comp.x, - y - comp.y, - ignoreEnabled); - } else { - comp = comp.locate(x - comp.x, y - comp.y); - } - if (comp != null && comp.visible && - (ignoreEnabled || comp.enabled)) - { - return comp; + synchronized (getTreeLock()) { + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); + if (comp != null && + !(comp.peer instanceof LightweightPeer)) { + if (comp instanceof Container) { + comp = ((Container)comp).findComponentAtImpl(x - comp.x, + y - comp.y, + ignoreEnabled); + } else { + comp = comp.locate(x - comp.x, y - comp.y); + } + if (comp != null && comp.visible && + (ignoreEnabled || comp.enabled)) + { + return comp; + } } } - } - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; - if (comp != null && - comp.peer instanceof LightweightPeer) { - if (comp instanceof Container) { - comp = ((Container)comp).findComponentAtImpl(x - comp.x, - y - comp.y, - ignoreEnabled); - } else { - comp = comp.locate(x - comp.x, y - comp.y); - } - if (comp != null && comp.visible && - (ignoreEnabled || comp.enabled)) - { - return comp; + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); + if (comp != null && + comp.peer instanceof LightweightPeer) { + if (comp instanceof Container) { + comp = ((Container)comp).findComponentAtImpl(x - comp.x, + y - comp.y, + ignoreEnabled); + } else { + comp = comp.locate(x - comp.x, y - comp.y); + } + if (comp != null && comp.visible && + (ignoreEnabled || comp.enabled)) + { + return comp; + } } } } @@ -2632,10 +2575,14 @@ if (! (peer instanceof LightweightPeer)) { dispatcher = new LightweightDispatcher(this); } - int ncomponents = this.ncomponents; - Component component[] = this.component; - for (int i = 0 ; i < ncomponents ; i++) { - component[i].addNotify(); + + // We shouldn't use iterator because of the Swing menu + // implementation specifics: + // the menu is being assigned as a child to JLayeredPane + // instead of particular component so always affect + // collection of component if menu is becoming shown or hidden. + for (int i = 0; i < component.size(); i++) { + component.get(i).addNotify(); } // Update stacking order if native platform allows ContainerPeer cpeer = (ContainerPeer)peer; @@ -2658,21 +2605,25 @@ */ public void removeNotify() { synchronized (getTreeLock()) { - int ncomponents = this.ncomponents; - Component component[] = this.component; - for (int i = ncomponents - 1; i >= 0; i--) { - if( component[i] != null ) { + // We shouldn't use iterator because of the Swing menu + // implementation specifics: + // the menu is being assigned as a child to JLayeredPane + // instead of particular component so always affect + // collection of component if menu is becoming shown or hidden. + for (int i = component.size()-1 ; i >= 0 ; i--) { + Component comp = component.get(i); + if (comp != null) { // Fix for 6607170. // We want to suppress focus change on disposal // of the focused component. But because of focus // is asynchronous, we should suppress focus change // on every component in case it receives native focus // in the process of disposal. - component[i].setAutoFocusTransferOnDisposal(false); - component[i].removeNotify(); - component[i].setAutoFocusTransferOnDisposal(true); - } - } + comp.setAutoFocusTransferOnDisposal(false); + comp.removeNotify(); + comp.setAutoFocusTransferOnDisposal(true); + } + } // If some of the children had focus before disposal then it still has. // Auto-transfer focus to the next (or previous) component if auto-transfer // is enabled. @@ -2683,7 +2634,7 @@ } if ( dispatcher != null ) { dispatcher.dispose(); - dispatcher = null; + dispatcher = null; } super.removeNotify(); } @@ -2873,12 +2824,12 @@ */ public void list(PrintStream out, int indent) { super.list(out, indent); - int ncomponents = this.ncomponents; - Component component[] = this.component; - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; - if (comp != null) { - comp.list(out, indent+1); + synchronized(getTreeLock()) { + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); + if (comp != null) { + comp.list(out, indent+1); + } } } } @@ -2899,12 +2850,12 @@ */ public void list(PrintWriter out, int indent) { super.list(out, indent); - int ncomponents = this.ncomponents; - Component component[] = this.component; - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; - if (comp != null) { - comp.list(out, indent+1); + synchronized(getTreeLock()) { + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); + if (comp != null) { + comp.list(out, indent+1); + } } } } @@ -3414,9 +3365,11 @@ */ public void applyComponentOrientation(ComponentOrientation o) { super.applyComponentOrientation(o); - - for (int i = 0 ; i < ncomponents ; ++i) { - component[i].applyComponentOrientation(o); + synchronized (getTreeLock()) { + for (int i = 0; i < component.size(); i++) { + Component comp = component.get(i); + comp.applyComponentOrientation(o); + } } } @@ -3534,8 +3487,8 @@ */ private void writeObject(ObjectOutputStream s) throws IOException { ObjectOutputStream.PutField f = s.putFields(); - f.put("ncomponents", ncomponents); - f.put("component", component); + f.put("ncomponents", component.size()); + f.put("component", component.toArray(EMPTY_ARRAY)); f.put("layoutMgr", layoutMgr); f.put("dispatcher", dispatcher); f.put("maxSize", maxSize); @@ -3574,8 +3527,12 @@ throws ClassNotFoundException, IOException { ObjectInputStream.GetField f = s.readFields(); - ncomponents = f.get("ncomponents", 0); - component = (Component[])f.get("component", new Component[0]); + Component [] tmpComponent = (Component[])f.get("component", EMPTY_ARRAY); + int ncomponents = (Integer) f.get("ncomponents", 0); + component = new java.util.ArrayList (ncomponents); + for (int i = 0; i < ncomponents; ++i) { + component.add(tmpComponent[i]); + } layoutMgr = (LayoutManager)f.get("layoutMgr", null); dispatcher = (LightweightDispatcher)f.get("dispatcher", null); // Old stream. Doesn't contain maxSize among Component's fields. @@ -3585,16 +3542,14 @@ focusCycleRoot = f.get("focusCycleRoot", false); containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1); focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false); - - Component component[] = this.component; - for(int i = 0; i < ncomponents; i++) { - component[i].parent = this; + java.util.List component = this.component; + for(Component comp : component) { + comp.parent = this; adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, - component[i].numListening(AWTEvent.HIERARCHY_EVENT_MASK)); + comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, - component[i].numListening( - AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); - adjustDescendants(component[i].countHierarchyMembers()); + comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); + adjustDescendants(comp.countHierarchyMembers()); } Object keyOrNull; @@ -4111,6 +4066,21 @@ } } + @Override + void mixOnValidating() { + synchronized (getTreeLock()) { + if (mixingLog.isLoggable(Level.FINE)) { + mixingLog.fine("this = " + this); + } + + if (hasHeavyweightDescendants()) { + recursiveApplyCurrentShape(); + } + + super.mixOnValidating(); + } + } + // ****************** END OF MIXING CODE ******************************** } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java --- a/jdk/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java Wed Jul 05 16:41:30 2017 +0200 @@ -556,8 +556,7 @@ * enabled, and focusable; false
otherwise */ protected boolean accept(Component aComponent) { - if (!(aComponent.isVisible() && aComponent.isDisplayable() && - aComponent.isFocusable() && aComponent.isEnabled())) { + if (!aComponent.canBeFocusOwner()) { return false; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java --- a/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Wed Jul 05 16:41:30 2017 +0200 @@ -154,7 +154,7 @@ private boolean doRestoreFocus(Component toFocus, Component vetoedComponent, boolean clearOnFailure) { - if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.isFocusable() && + if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() && toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK)) { return true; @@ -500,8 +500,11 @@ } } - if (!(newFocusOwner.isFocusable() && newFocusOwner.isEnabled() - && newFocusOwner.isShowing())) + if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() && + // Refuse focus on a disabled component if the focus event + // isn't of UNKNOWN reason (i.e. not a result of a direct request + // but traversal, activation or system generated). + (newFocusOwner.isEnabled() || cause.equals(CausedFocusEvent.Cause.UNKNOWN)))) { // we should not accept focus on such component, so reject it. dequeueKeyEvents(-1, newFocusOwner); @@ -742,8 +745,7 @@ public boolean dispatchKeyEvent(KeyEvent e) { Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent(); - if (focusOwner != null && focusOwner.isShowing() && - focusOwner.isFocusable() && focusOwner.isEnabled()) { + if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) { if (!e.isConsumed()) { Component comp = e.getComponent(); if (comp != null && comp.isEnabled()) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Dialog.java --- a/jdk/src/share/classes/java/awt/Dialog.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Dialog.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1327,8 +1327,8 @@ // the insets of the Dialog. If we could, we'd call invalidate() // from the peer, but we need to guarantee that we're not holding // the Dialog lock when we call invalidate(). - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/EventQueue.java --- a/jdk/src/share/classes/java/awt/EventQueue.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/EventQueue.java Wed Jul 05 16:41:30 2017 +0200 @@ -42,6 +42,7 @@ import sun.awt.AWTAutoShutdown; import sun.awt.PeerEvent; import sun.awt.SunToolkit; +import sun.awt.EventQueueItem; /** *EventQueue
is a platform-independent class @@ -359,7 +360,7 @@ entry != null; entry = entry.next) { // Give Component.coalesceEvents a chance - if (entry.event.getSource() == source && entry.id == id) { + if (entry.event.getSource() == source && entry.event.getID() == id) { AWTEvent coalescedEvent = source.coalesceEvents( entry.event, e); if (coalescedEvent != null) { @@ -499,7 +500,7 @@ for (EventQueueItem entry = queues[i].head, prev = null; entry != null; prev = entry, entry = entry.next) { - if (entry.id == id) { + if (entry.event.getID() == id) { if (prev == null) { queues[i].head = entry.next; } else { @@ -545,7 +546,7 @@ for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { EventQueueItem q = queues[i].head; for (; q != null; q = q.next) { - if (q.id == id) { + if (q.event.getID() == id) { return q.event; } } @@ -1051,14 +1052,3 @@ EventQueueItem head; EventQueueItem tail; } - -class EventQueueItem { - AWTEvent event; - int id; - EventQueueItem next; - - EventQueueItem(AWTEvent evt) { - event = evt; - id = evt.getID(); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Frame.java --- a/jdk/src/share/classes/java/awt/Frame.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Frame.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -590,9 +590,7 @@ if (peer != null) { mbManagement = true; menuBar.addNotify(); - if (valid) { - invalidate(); - } + invalidateIfValid(); peer.setMenuBar(menuBar); } } @@ -633,8 +631,8 @@ // the insets of the Frame. If we could, we'd call invalidate() // from the peer, but we need to guarantee that we're not holding // the Frame lock when we call invalidate(). - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } firePropertyChange("resizable", oldResizable, resizable); } @@ -907,9 +905,7 @@ FramePeer peer = (FramePeer)this.peer; if (peer != null) { mbManagement = true; - if (valid) { - invalidate(); - } + invalidateIfValid(); peer.setMenuBar(null); m.removeNotify(); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Label.java --- a/jdk/src/share/classes/java/awt/Label.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Label.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,8 +257,8 @@ } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/ScrollPane.java --- a/jdk/src/share/classes/java/awt/ScrollPane.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/ScrollPane.java Wed Jul 05 16:41:30 2017 +0200 @@ -357,7 +357,7 @@ */ public void setScrollPosition(int x, int y) { synchronized (getTreeLock()) { - if (ncomponents <= 0) { + if (getComponentCount()==0) { throw new NullPointerException("child is null"); } hAdjustable.setValue(x); @@ -393,10 +393,12 @@ */ @Transient public Point getScrollPosition() { - if (ncomponents <= 0) { - throw new NullPointerException("child is null"); + synchronized (getTreeLock()) { + if (getComponentCount()==0) { + throw new NullPointerException("child is null"); + } + return new Point(hAdjustable.getValue(), vAdjustable.getValue()); } - return new Point(hAdjustable.getValue(), vAdjustable.getValue()); } /** @@ -486,26 +488,27 @@ */ @Deprecated public void layout() { - if (ncomponents > 0) { - Component c = getComponent(0); - Point p = getScrollPosition(); - Dimension cs = calculateChildSize(); - Dimension vs = getViewportSize(); - Insets i = getInsets(); + if (getComponentCount()==0) { + return; + } + Component c = getComponent(0); + Point p = getScrollPosition(); + Dimension cs = calculateChildSize(); + Dimension vs = getViewportSize(); + Insets i = getInsets(); - c.reshape(i.left - p.x, i.top - p.y, cs.width, cs.height); - ScrollPanePeer peer = (ScrollPanePeer)this.peer; - if (peer != null) { - peer.childResized(cs.width, cs.height); - } + c.reshape(i.left - p.x, i.top - p.y, cs.width, cs.height); + ScrollPanePeer peer = (ScrollPanePeer)this.peer; + if (peer != null) { + peer.childResized(cs.width, cs.height); + } - // update adjustables... the viewport size may have changed - // with the scrollbars coming or going so the viewport size - // is updated before the adjustables. - vs = getViewportSize(); - hAdjustable.setSpan(0, cs.width, vs.width); - vAdjustable.setSpan(0, cs.height, vs.height); - } + // update adjustables... the viewport size may have changed + // with the scrollbars coming or going so the viewport size + // is updated before the adjustables. + vs = getViewportSize(); + hAdjustable.setSpan(0, cs.width, vs.width); + vAdjustable.setSpan(0, cs.height, vs.height); } /** @@ -515,20 +518,21 @@ * @see Component#printAll */ public void printComponents(Graphics g) { - if (ncomponents > 0) { - Component c = component[0]; - Point p = c.getLocation(); - Dimension vs = getViewportSize(); - Insets i = getInsets(); + if (getComponentCount()==0) { + return; + } + Component c = getComponent(0); + Point p = c.getLocation(); + Dimension vs = getViewportSize(); + Insets i = getInsets(); - Graphics cg = g.create(); - try { - cg.clipRect(i.left, i.top, vs.width, vs.height); - cg.translate(p.x, p.y); - c.printAll(cg); - } finally { - cg.dispose(); - } + Graphics cg = g.create(); + try { + cg.clipRect(i.left, i.top, vs.width, vs.height); + cg.translate(p.x, p.y); + c.printAll(cg); + } finally { + cg.dispose(); } } @@ -589,7 +593,7 @@ default: sdpStr = "invalid display policy"; } - Point p = ncomponents > 0? getScrollPosition() : new Point(0,0); + Point p = (getComponentCount()>0)? getScrollPosition() : new Point(0,0); Insets i = getInsets(); return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+ ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/SystemTray.java --- a/jdk/src/share/classes/java/awt/SystemTray.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/SystemTray.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,6 +125,8 @@ transient private SystemTrayPeer peer; + private static final TrayIcon[] EMPTY_TRAY_ARRAY = new TrayIcon[0]; + /** * PrivateSystemTray
constructor. * @@ -201,17 +203,18 @@ * functionality is supported for the current platform */ public static boolean isSupported() { - initializeSystemTrayIfNeeded(); - - if (Toolkit.getDefaultToolkit() instanceof SunToolkit) { - - return ((SunToolkit)Toolkit.getDefaultToolkit()).isTraySupported(); - - } else if (Toolkit.getDefaultToolkit() instanceof HeadlessToolkit) { - - return ((HeadlessToolkit)Toolkit.getDefaultToolkit()).isTraySupported(); + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof SunToolkit) { + // connecting tray to native resource + initializeSystemTrayIfNeeded(); + return ((SunToolkit)toolkit).isTraySupported(); + } else if (toolkit instanceof HeadlessToolkit) { + // skip initialization as the init routine + // throws HeadlessException + return ((HeadlessToolkit)toolkit).isTraySupported(); + } else { + return false; } - return false; } /** @@ -323,7 +326,7 @@ if (icons != null) { return (TrayIcon[])icons.toArray(new TrayIcon[icons.size()]); } - return new TrayIcon[0]; + return EMPTY_TRAY_ARRAY; } /** @@ -475,7 +478,12 @@ synchronized void addNotify() { if (peer == null) { - peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this); + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof SunToolkit) { + peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this); + } else if (toolkit instanceof HeadlessToolkit) { + peer = ((HeadlessToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this); + } } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/TextField.java --- a/jdk/src/share/classes/java/awt/TextField.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/TextField.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,9 +296,7 @@ super.setText(t); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/TrayIcon.java --- a/jdk/src/share/classes/java/awt/TrayIcon.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/TrayIcon.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.awt.peer.TrayIconPeer; import sun.awt.AppContext; import sun.awt.SunToolkit; +import sun.awt.HeadlessToolkit; import java.util.EventObject; /** @@ -142,9 +143,6 @@ */ public TrayIcon(Image image) { this(); - if (image == null) { - throw new IllegalArgumentException("creating TrayIcon with null Image"); - } setImage(image); } @@ -433,7 +431,7 @@ * @see java.awt.event.MouseListener */ public synchronized MouseListener[] getMouseListeners() { - return (MouseListener[])(getListeners(MouseListener.class)); + return AWTEventMulticaster.getListeners(mouseListener, MouseListener.class); } /** @@ -494,7 +492,7 @@ * @see java.awt.event.MouseMotionListener */ public synchronized MouseMotionListener[] getMouseMotionListeners() { - return (MouseMotionListener[]) (getListeners(MouseMotionListener.class)); + return AWTEventMulticaster.getListeners(mouseMotionListener, MouseMotionListener.class); } /** @@ -581,7 +579,7 @@ * @see java.awt.event.ActionListener */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[])(getListeners(ActionListener.class)); + return AWTEventMulticaster.getListeners(actionListener, ActionListener.class); } /** @@ -635,7 +633,7 @@ TrayIconPeer peer = this.peer; if (peer != null) { - peer.displayMessage(caption, text, messageType.toString()); + peer.displayMessage(caption, text, messageType.name()); } } @@ -657,24 +655,17 @@ // **************************************************************** // **************************************************************** -T[] getListeners(Class listenerType) { - EventListener l = null; - if (listenerType == MouseListener.class) { - l = mouseListener; - } else if (listenerType == MouseMotionListener.class) { - l = mouseMotionListener; - } else if (listenerType == ActionListener.class) { - l = actionListener; - } - return AWTEventMulticaster.getListeners(l, listenerType); - } - void addNotify() throws AWTException { synchronized (this) { if (peer == null) { - peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createTrayIcon(this); + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof SunToolkit) { + peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createTrayIcon(this); + } else if (toolkit instanceof HeadlessToolkit) { + peer = ((HeadlessToolkit)Toolkit.getDefaultToolkit()).createTrayIcon(this); + } } } peer.setToolTip(tooltip); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/Window.java --- a/jdk/src/share/classes/java/awt/Window.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Window.java Wed Jul 05 16:41:30 2017 +0200 @@ -3145,9 +3145,7 @@ Component previousComp = temporaryLostComponent; // Check that "component" is an acceptable focus owner and don't store it otherwise // - or later we will have problems with opposite while handling WINDOW_GAINED_FOCUS - if (component == null - || (component.isDisplayable() && component.isVisible() && component.isEnabled() && component.isFocusable())) - { + if (component == null || component.canBeFocusOwner()) { temporaryLostComponent = component; } else { temporaryLostComponent = null; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/awt/dnd/DragSourceContext.java --- a/jdk/src/share/classes/java/awt/dnd/DragSourceContext.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/awt/dnd/DragSourceContext.java Wed Jul 05 16:41:30 2017 +0200 @@ -486,6 +486,8 @@ Cursor c = null; switch (status) { + default: + targetAct = DnDConstants.ACTION_NONE; case ENTER: case OVER: case CHANGED: @@ -506,10 +508,6 @@ else c = DragSource.DefaultCopyDrop; } - break; - default: - targetAct = DnDConstants.ACTION_NONE; - } setCursorImpl(c); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/lang/Thread.java --- a/jdk/src/share/classes/java/lang/Thread.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/lang/Thread.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; -import java.util.Collections; import java.util.concurrent.locks.LockSupport; import sun.misc.SoftCache; import sun.nio.ch.Interruptible; @@ -120,6 +119,10 @@ * Every thread has a name for identification purposes. More than * one thread may have the same name. If a name is not specified when * a thread is created, a new name is generated for it. + * + * Unless otherwise noted, passing a {@code null} argument to a constructor + * or method in this class will cause a {@link NullPointerException} to be + * thrown. * * @author unascribed * @see Runnable @@ -348,6 +351,10 @@ */ private void init(ThreadGroup g, Runnable target, String name, long stackSize) { + if (name == null) { + throw new NullPointerException("name cannot be null"); + } + Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { @@ -379,7 +386,6 @@ } } - g.addUnstarted(); this.group = g; @@ -403,160 +409,175 @@ tid = nextThreadID(); } - /** - * Allocates a new
Thread
object. This constructor has - * the same effect asThread(null, null,
- * gname)
, where gname is - * a newly generated name. Automatically generated names are of the - * form"Thread-"+
n, where n is an integer. - * - * @see #Thread(ThreadGroup, Runnable, String) + /** + * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (null, null, gname)}, where {@code gname} is a newly generated + * name. Automatically generated names are of the form + * {@code "Thread-"+}n, where n is an integer. */ public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } /** - * Allocates a newThread
object. This constructor has - * the same effect asThread(null, target,
- * gname)
, where gname is - * a newly generated name. Automatically generated names are of the - * form"Thread-"+
n, where n is an integer. + * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (null, target, gname)}, where {@code gname} is a newly generated + * name. Automatically generated names are of the form + * {@code "Thread-"+}n, where n is an integer. * - * @param target the object whoserun
method is called. - * @see #Thread(ThreadGroup, Runnable, String) + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this classes {@code run} method does + * nothing. */ public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } /** - * Allocates a newThread
object. This constructor has - * the same effect asThread(group, target,
- * gname)
, where gname is - * a newly generated name. Automatically generated names are of the - * form"Thread-"+
n, where n is an integer. + * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (group, target, gname)} ,where {@code gname} is a newly generated + * name. Automatically generated names are of the form + * {@code "Thread-"+}n, where n is an integer. * - * @param group the thread group. - * @param target the object whoserun
method is called. - * @exception SecurityException if the current thread cannot create a - * thread in the specified thread group. - * @see #Thread(ThreadGroup, Runnable, String) + * @param group + * the thread group. If {@code null} and there is a security + * manager, the group is determined by {@linkplain + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. + * If there is not a security manager or {@code + * SecurityManager.getThreadGroup()} returns {@code null}, the group + * is set to the current thread's thread group. + * + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this thread's run method is invoked. + * + * @throws SecurityException + * if the current thread cannot create a thread in the specified + * thread group */ public Thread(ThreadGroup group, Runnable target) { init(group, target, "Thread-" + nextThreadNum(), 0); } /** - * Allocates a newThread
object. This constructor has - * the same effect asThread(null, null, name)
. + * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (null, null, name)}. * - * @param name the name of the new thread. - * @see #Thread(ThreadGroup, Runnable, String) + * @param name + * the name of the new thread */ public Thread(String name) { init(null, null, name, 0); } /** - * Allocates a newThread
object. This constructor has - * the same effect asThread(group, null, name)
+ * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (group, null, name)}. * - * @param group the thread group. - * @param name the name of the new thread. - * @exception SecurityException if the current thread cannot create a - * thread in the specified thread group. - * @see #Thread(ThreadGroup, Runnable, String) + * @param group + * the thread group. If {@code null} and there is a security + * manager, the group is determined by {@linkplain + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. + * If there is not a security manager or {@code + * SecurityManager.getThreadGroup()} returns {@code null}, the group + * is set to the current thread's thread group. + * + * @param name + * the name of the new thread + * + * @throws SecurityException + * if the current thread cannot create a thread in the specified + * thread group */ public Thread(ThreadGroup group, String name) { init(group, null, name, 0); } /** - * Allocates a newThread
object. This constructor has - * the same effect asThread(null, target, name)
. + * Allocates a new {@code Thread} object. This constructor has the same + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} + * {@code (null, target, name)}. * - * @param target the object whoserun
method is called. - * @param name the name of the new thread. - * @see #Thread(ThreadGroup, Runnable, String) + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this thread's run method is invoked. + * + * @param name + * the name of the new thread */ public Thread(Runnable target, String name) { init(null, target, name, 0); } /** - * Allocates a newThread
object so that it has - *target
as its run object, has the specified - *name
as its name, and belongs to the thread group - * referred to bygroup
. - *- * If
group
isnull
and there is a - * security manager, the group is determined by the security manager's - *getThreadGroup
method. Ifgroup
is - *null
and there is not a security manager, or the - * security manager'sgetThreadGroup
method returns - *null
, the group is set to be the same ThreadGroup - * as the thread that is creating the new thread. + * Allocates a new {@code Thread} object so that it has {@code target} + * as its run object, has the specified {@code name} as its name, + * and belongs to the thread group referred to by {@code group}. * - *If there is a security manager, its
checkAccess
- * method is called with the ThreadGroup as its argument. - *In addition, its
checkPermission
- * method is called with the - *RuntimePermission("enableContextClassLoaderOverride")
+ *If there is a security manager, its + * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess} + * method is invoked with the ThreadGroup as its argument. + * + *
In addition, its {@code checkPermission} method is invoked with + * the {@code RuntimePermission("enableContextClassLoaderOverride")} * permission when invoked directly or indirectly by the constructor - * of a subclass which overrides the
getContextClassLoader
- * orsetContextClassLoader
methods. - * This may result in a SecurityException. - - *- * If the
target
argument is notnull
, the - *run
method of thetarget
is called when - * this thread is started. If the target argument is - *null
, this thread'srun
method is called - * when this thread is started. - *- * The priority of the newly created thread is set equal to the + * of a subclass which overrides the {@code getContextClassLoader} + * or {@code setContextClassLoader} methods. + * + *
The priority of the newly created thread is set equal to the * priority of the thread creating it, that is, the currently running - * thread. The method
setPriority
may be used to - * change the priority to a new value. - *- * The newly created thread is initially marked as being a daemon + * thread. The method {@linkplain #setPriority setPriority} may be + * used to change the priority to a new value. + * + *
The newly created thread is initially marked as being a daemon * thread if and only if the thread creating it is currently marked - * as a daemon thread. The method
setDaemon
may be used - * to change whether or not a thread is a daemon. + * as a daemon thread. The method {@linkplain #setDaemon setDaemon} + * may be used to change whether or not a thread is a daemon. * - * @param group the thread group. - * @param target the object whoserun
method is called. - * @param name the name of the new thread. - * @exception SecurityException if the current thread cannot create a - * thread in the specified thread group or cannot - * override the context class loader methods. - * @see Runnable#run() - * @see #run() - * @see #setDaemon(boolean) - * @see #setPriority(int) - * @see ThreadGroup#checkAccess() - * @see SecurityManager#checkAccess + * @param group + * the thread group. If {@code null} and there is a security + * manager, the group is determined by {@linkplain + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. + * If there is not a security manager or {@code + * SecurityManager.getThreadGroup()} returns {@code null}, the group + * is set to the current thread's thread group. + * + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this thread's run method is invoked. + * + * @param name + * the name of the new thread + * + * @throws SecurityException + * if the current thread cannot create a thread in the specified + * thread group or cannot override the context class loader methods. */ public Thread(ThreadGroup group, Runnable target, String name) { init(group, target, name, 0); } /** - * Allocates a newThread
object so that it has - *target
as its run object, has the specified - *name
as its name, belongs to the thread group referred to - * bygroup
, and has the specified stack size. + * Allocates a new {@code Thread} object so that it has {@code target} + * as its run object, has the specified {@code name} as its name, + * and belongs to the thread group referred to by {@code group}, and has + * the specified stack size. * *This constructor is identical to {@link * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact * that it allows the thread stack size to be specified. The stack size * is the approximate number of bytes of address space that the virtual * machine is to allocate for this thread's stack. The effect of the - * stackSize parameter, if any, is highly platform dependent. + * {@code stackSize} parameter, if any, is highly platform dependent. * *
On some platforms, specifying a higher value for the - * stackSize parameter may allow a thread to achieve greater + * {@code stackSize} parameter may allow a thread to achieve greater * recursion depth before throwing a {@link StackOverflowError}. * Similarly, specifying a lower value may allow a greater number of * threads to exist concurrently without throwing an {@link @@ -564,9 +585,9 @@ * the relationship between the value of the stackSize parameter * and the maximum recursion depth and concurrency level are * platform-dependent. On some platforms, the value of the - * stackSize parameter may have no effect whatsoever. + * {@code stackSize} parameter may have no effect whatsoever. * - *
The virtual machine is free to treat the stackSize + *
The virtual machine is free to treat the {@code stackSize} * parameter as a suggestion. If the specified value is unreasonably low * for the platform, the virtual machine may instead use some * platform-specific minimum value; if the specified value is unreasonably @@ -574,9 +595,9 @@ * maximum. Likewise, the virtual machine is free to round the specified * value up or down as it sees fit (or to ignore it completely). * - *
Specifying a value of zero for the stackSize parameter will + *
Specifying a value of zero for the {@code stackSize} parameter will * cause this constructor to behave exactly like the - * Thread(ThreadGroup, Runnable, String) constructor. + * {@code Thread(ThreadGroup, Runnable, String)} constructor. * *
Due to the platform-dependent nature of the behavior of this * constructor, extreme care should be exercised in its use. @@ -588,15 +609,32 @@ * *
Implementation note: Java platform implementers are encouraged to * document their implementation's behavior with respect to the - * stackSize parameter. + * {@code stackSize} parameter. + * + * + * @param group + * the thread group. If {@code null} and there is a security + * manager, the group is determined by {@linkplain + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. + * If there is not a security manager or {@code + * SecurityManager.getThreadGroup()} returns {@code null}, the group + * is set to the current thread's thread group. * - * @param group the thread group. - * @param target the object whose
run
method is called. - * @param name the name of the new thread. - * @param stackSize the desired stack size for the new thread, or - * zero to indicate that this parameter is to be ignored. - * @exception SecurityException if the current thread cannot create a - * thread in the specified thread group. + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this thread's run method is invoked. + * + * @param name + * the name of the new thread + * + * @param stackSize + * the desired stack size for the new thread, or zero to indicate + * that this parameter is to be ignored. + * + * @throws SecurityException + * if the current thread cannot create a thread in the specified + * thread group + * * @since 1.4 */ public Thread(ThreadGroup group, Runnable target, String name, @@ -669,6 +707,7 @@ * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ + @Override public void run() { if (target != null) { target.run(); @@ -1386,28 +1425,25 @@ * Returns the context ClassLoader for this Thread. The context * ClassLoader is provided by the creator of the thread for use * by code running in this thread when loading classes and resources. - * If not set, the default is the ClassLoader context of the parent - * Thread. The context ClassLoader of the primordial thread is - * typically set to the class loader used to load the application. + * If not {@linkplain #setContextClassLoader set}, the default is the + * ClassLoader context of the parent Thread. The context ClassLoader of the + * primordial thread is typically set to the class loader used to load the + * application. * - *First, if there is a security manager, and the caller's class - * loader is not null and the caller's class loader is not the same as or - * an ancestor of the context class loader for the thread whose - * context class loader is being requested, then the security manager's - *
checkPermission
- * method is called with a - *RuntimePermission("getClassLoader")
permission - * to see if it's ok to get the context ClassLoader.. + *If a security manager is present, and the invoker's class loader is not + * {@code null} and is not the same as or an ancestor of the context class + * loader, then this method invokes the security manager's {@link + * SecurityManager#checkPermission(java.security.Permission) checkPermission} + * method with a {@link RuntimePermission RuntimePermission}{@code + * ("getClassLoader")} permission to verify that retrieval of the context + * class loader is permitted. * - * @return the context ClassLoader for this Thread + * @return the context ClassLoader for this Thread, or {@code null} + * indicating the system class loader (or, failing that, the + * bootstrap class loader) * - * @throws SecurityException - * if a security manager exists and its - *
checkPermission
method doesn't allow - * getting the context ClassLoader. - * @see #setContextClassLoader - * @see SecurityManager#checkPermission - * @see RuntimePermission + * @throws SecurityException + * if the current thread cannot get the context ClassLoader * * @since 1.2 */ @@ -1428,21 +1464,22 @@ /** * Sets the context ClassLoader for this Thread. The context * ClassLoader can be set when a thread is created, and allows - * the creator of the thread to provide the appropriate class loader - * to code running in the thread when loading classes and resources. - * - *First, if there is a security manager, its
checkPermission
- * method is called with a - *RuntimePermission("setContextClassLoader")
permission - * to see if it's ok to set the context ClassLoader.. + * the creator of the thread to provide the appropriate class loader, + * through {@code getContextClassLoader}, to code running in the thread + * when loading classes and resources. * - * @param cl the context ClassLoader for this Thread + *If a security manager is present, its {@link + * SecurityManager#checkPermission(java.security.Permission) checkPermission} + * method is invoked with a {@link RuntimePermission RuntimePermission}{@code + * ("setContextClassLoader")} permission to see if setting the context + * ClassLoader is permitted. * - * @exception SecurityException if the current thread cannot set the - * context ClassLoader. - * @see #getContextClassLoader - * @see SecurityManager#checkPermission - * @see RuntimePermission + * @param cl + * the context ClassLoader for this Thread, or null indicating the + * system class loader (or, failing that, the bootstrap class loader) + * + * @throws SecurityException + * if the current thread cannot set the context ClassLoader * * @since 1.2 */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/lang/management/PlatformComponent.java --- a/jdk/src/share/classes/java/lang/management/PlatformComponent.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/lang/management/PlatformComponent.java Wed Jul 05 16:41:30 2017 +0200 @@ -32,6 +32,7 @@ import java.util.Set; import java.util.logging.LoggingMXBean; import java.util.logging.LogManager; +import java.nio.BufferPoolMXBean; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; @@ -188,6 +189,23 @@ } }), + + /** + * Buffer pools. + */ + BUFFER_POOL( + "java.nio.BufferPoolMXBean", + "java.nio", "BufferPool", keyProperties("name"), + new MXBeanFetcher
* * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, Object params[], String signature[]) @@ -302,6 +339,8 @@ * is sent as described above. * * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object params[], diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MBeanServerConnection.java --- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java Wed Jul 05 16:41:30 2017 +0200 @@ -78,19 +78,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If the() { + public List getMXBeans() { + List pools = new ArrayList (2); + pools.add( sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPoolMXBean() ); + pools.add( sun.nio.ch.FileChannelImpl.getMappedBufferPoolMXBean() ); + return pools; + } + }), + + // Sun Platform Extension /** diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/net/NetworkInterface.java --- a/jdk/src/share/classes/java/net/NetworkInterface.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/net/NetworkInterface.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,7 +25,6 @@ package java.net; -import java.net.SocketException; import java.util.Enumeration; import java.util.NoSuchElementException; import sun.security.action.*; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/net/ProtocolFamily.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/net/ProtocolFamily.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * Represents a family of communication protocols. + * + * @since 1.7 + */ + +public interface ProtocolFamily { + /** + * Returns the name of the protocol family. + */ + String name(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/net/SocketOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/net/SocketOption.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * A socket option associated with a socket. + * + * In the {@link java.nio.channels channels} package, the {@link + * java.nio.channels.NetworkChannel} interface defines the {@link + * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption} + * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption} + * methods to set and query the channel's socket options. + * + * @param
* * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) @@ -289,6 +324,8 @@ * is sent as described above.The type of the socket option value. + * + * @since 1.7 + * + * @see StandardSocketOption + */ + +public interface SocketOption { + + /** + * Returns the name of the socket option. + */ + String name(); + + /** + * Returns the type of the socket option value. + */ + Class type(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/net/StandardProtocolFamily.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/net/StandardProtocolFamily.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * Defines the standard family of communication protocols. + * + * @since 1.7 + */ + +public enum StandardProtocolFamily implements ProtocolFamily { + + /** + * Internet Protocol Version 4 (IPv4) + */ + INET, + + /** + * Internet Protocol Version 6 (IPv6) + */ + INET6 +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/net/StandardSocketOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/net/StandardSocketOption.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,352 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * Defines the standard socket options. + * + * The {@link SocketOption#name name} of each socket option defined by this + * class is its field name. + * + *
In this release, the socket options defined here are used by {@link + * java.nio.channels.NetworkChannel network} channels in the {@link + * java.nio.channels channels} package. + * + * @since 1.7 + */ + +public final class StandardSocketOption { + private StandardSocketOption() { } + + // -- SOL_SOCKET -- + + /** + * Allow transmission of broadcast datagrams. + * + *
The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. The option is specific to + * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4} + * broadcast addresses. When the socket option is enabled then the socket + * can be used to send broadcast datagrams. + * + *
The initial value of this socket option is {@code FALSE}. The socket + * option may be enabled or disabled at any time. Some operating systems may + * require that the Java virtual machine be started with implementation + * specific privileges to enable this option or send broadcast datagrams. + * + * @see RFC 929: + * Broadcasting Internet Datagrams + */ + public static final SocketOption
* * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, @@ -276,6 +309,8 @@ * is sent as described above.SO_BROADCAST = + new StdSocketOption ("SO_BROADCAST", Boolean.class); + + /** + * Keep connection alive. + * + * The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE} + * option is enabled the operating system may use a keep-alive + * mechanism to periodically probe the other end of a connection when the + * connection is otherwise idle. The exact semantics of the keep alive + * mechanism is system dependent and therefore unspecified. + * + *
The initial value of this socket option is {@code FALSE}. The socket + * option may be enabled or disabled at any time. + * + * @see RFC 1122 + * Requirements for Internet Hosts -- Communication Layers + */ + public static final SocketOption
* * * @@ -264,6 +295,8 @@ * is sent as described above.SO_KEEPALIVE = + new StdSocketOption ("SO_KEEPALIVE", Boolean.class); + + /** + * The size of the socket send buffer. + * + * The value of this socket option is an {@code Integer} that is the + * size of the socket send buffer in bytes. The socket send buffer is an + * output buffer used by the networking implementation. It may need to be + * increased for high-volume connections. The value of the socket option is + * a hint to the implementation to size the buffer and the actual + * size may differ. The socket option can be queried to retrieve the actual + * size. + * + *
For datagram-oriented sockets, the size of the send buffer may limit + * the size of the datagrams that may be sent by the socket. Whether + * datagrams larger than the buffer size are sent or discarded is system + * dependent. + * + *
The initial/default size of the socket send buffer and the range of + * allowable values is system dependent although a negative size is not + * allowed. An attempt to set the socket send buffer to larger than its + * maximum size causes it to be set to its maximum size. + * + *
An implementation allows this socket option to be set before the + * socket is bound or connected. Whether an implementation allows the + * socket send buffer to be changed after the socket is bound is system + * dependent. + */ + public static final SocketOption
* *SO_SNDBUF = + new StdSocketOption ("SO_SNDBUF", Integer.class); + + + /** + * The size of the socket receive buffer. + * + * The value of this socket option is an {@code Integer} that is the + * size of the socket receive buffer in bytes. The socket receive buffer is + * an input buffer used by the networking implementation. It may need to be + * increased for high-volume connections or decreased to limit the possible + * backlog of incoming data. The value of the socket option is a + * hint to the implementation to size the buffer and the actual + * size may differ. + * + *
For datagram-oriented sockets, the size of the receive buffer may + * limit the size of the datagrams that can be received. Whether datagrams + * larger than the buffer size can be received is system dependent. + * Increasing the socket receive buffer may be important for cases where + * datagrams arrive in bursts faster than they can be processed. + * + *
In the case of stream-oriented sockets and the TCP/IP protocol, the + * size of the socket receive buffer may be used when advertising the size + * of the TCP receive window to the remote peer. + * + *
The initial/default size of the socket receive buffer and the range + * of allowable values is system dependent although a negative size is not + * allowed. An attempt to set the socket receive buffer to larger than its + * maximum size causes it to be set to its maximum size. + * + *
An implementation allows this socket option to be set before the + * socket is bound or connected. Whether an implementation allows the + * socket receive buffer to be changed after the socket is bound is system + * dependent. + * + * @see RFC 1323: TCP + * Extensions for High Performance + */ + public static final SocketOption
* *SO_RCVBUF = + new StdSocketOption ("SO_RCVBUF", Integer.class); + + /** + * Re-use address. + * + * The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. The exact semantics of this + * socket option are socket type and system dependent. + * + *
In the case of stream-oriented sockets, this socket option will + * usually determine whether the socket can be bound to a socket address + * when a previous connection involving that socket address is in the + * TIME_WAIT state. On implementations where the semantics differ, + * and the socket option is not required to be enabled in order to bind the + * socket when a previous connection is in this state, then the + * implementation may choose to ignore this option. + * + *
For datagram-oriented sockets the socket option is used to allow + * multiple programs bind to the same address. This option should be enabled + * when the socket is to be used for Internet Protocol (IP) multicasting. + * + *
An implementation allows this socket option to be set before the + * socket is bound or connected. Changing the value of this socket option + * after the socket is bound has no effect. The default value of this + * socket option is system dependent. + * + * @see RFC 793: Transmission + * Control Protocol + */ + public static final SocketOption
* *SO_REUSEADDR = + new StdSocketOption ("SO_REUSEADDR", Boolean.class); + + /** + * Linger on close if data is present. + * + * The value of this socket option is an {@code Integer} that controls + * the action taken when unsent data is queued on the socket and a method + * to close the socket is invoked. If the value of the socket option is zero + * or greater, then it represents a timeout value, in seconds, known as the + * linger interval. The linger interval is the timeout for the + * {@code close} method to block while the operating system attempts to + * transmit the unsent data or it decides that it is unable to transmit the + * data. If the value of the socket option is less than zero then the option + * is disabled. In that case the {@code close} method does not wait until + * unsent data is transmitted; if possible the operating system will transmit + * any unsent data before the connection is closed. + * + *
This socket option is intended for use with sockets that are configured + * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode + * only. The behavior of the {@code close} method when this option is + * enabled on a non-blocking socket is not defined. + * + *
The initial value of this socket option is a negative value, meaning + * that the option is disabled. The option may be enabled, or the linger + * interval changed, at any time. The maximum value of the linger interval + * is system dependent. Setting the linger interval to a value that is + * greater than its maximum value causes the linger interval to be set to + * its maximum value. + */ + public static final SocketOption
* *SO_LINGER = + new StdSocketOption ("SO_LINGER", Integer.class); + + + // -- IPPROTO_IP -- + + /** + * The Type of Service (ToS) octet in the Internet Protocol (IP) header. + * + * The value of this socket option is an {@code Integer}, the least + * significant 8 bits of which represents the value of the ToS octet in IP + * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4} + * socket. The interpretation of the ToS octet is network specific and + * is not defined by this class. Further information on the ToS octet can be + * found in RFC 1349 + * and RFC 2474. The + * value of the socket option is a hint. An implementation may + * ignore the value, or ignore specific values. + * + *
The initial/default value of the TOS field in the ToS octet is + * implementation specific but will typically be {@code 0}. For + * datagram-oriented sockets the option may be configured at any time after + * the socket has been bound. The new value of the octet is used when sending + * subsequent datagrams. It is system dependent whether this option can be + * queried or changed prior to binding the socket. + * + *
The behavior of this socket option on a stream-oriented socket, or an + * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this + * release. + */ + public static final SocketOption
* *IP_TOS = + new StdSocketOption ("IP_TOS", Integer.class); + + /** + * The network interface for Internet Protocol (IP) multicast datagrams. + * + * The value of this socket option is a {@link NetworkInterface} that + * represents the outgoing interface for multicast datagrams sent by the + * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6} + * sockets then it is system dependent whether setting this option also + * sets the outgoing interface for multlicast datagrams sent to IPv4 + * addresses. + * + *
The initial/default value of this socket option may be {@code null} + * to indicate that outgoing interface will be selected by the operating + * system, typically based on the network routing tables. An implementation + * allows this socket option to be set after the socket is bound. Whether + * the socket option can be queried or changed prior to binding the socket + * is system dependent. + * + * @see java.nio.channels.MulticastChannel + */ + public static final SocketOption
* *IP_MULTICAST_IF = + new StdSocketOption ("IP_MULTICAST_IF", NetworkInterface.class); + + /** + * The time-to-live for Internet Protocol (IP) multicast datagrams. + * + * The value of this socket option is an {@code Integer} in the range + * 0 <= value <= 255. It is used to control + * the scope of multicast datagrams sent by the datagram-oriented socket. + * In the case of an {@link StandardProtocolFamily#INET IPv4} socket + * the option is the time-to-live (TTL) on multicast datagrams sent by the + * socket. Datagrams with a TTL of zero are not transmitted on the network + * but may be delivered locally. In the case of an {@link + * StandardProtocolFamily#INET6 IPv6} socket the option is the + * hop limit which is number of hops that the datagram can + * pass through before expiring on the network. For IPv6 sockets it is + * system dependent whether the option also sets the time-to-live + * on multicast datagrams sent to IPv4 addresses. + * + *
The initial/default value of the time-to-live setting is typically + * {@code 1}. An implementation allows this socket option to be set after + * the socket is bound. Whether the socket option can be queried or changed + * prior to binding the socket is system dependent. + * + * @see java.nio.channels.MulticastChannel + */ + public static final SocketOption
* *IP_MULTICAST_TTL = + new StdSocketOption ("IP_MULTICAST_TTL", Integer.class); + + /** + * Loopback for Internet Protocol (IP) multicast datagrams. + * + * The value of this socket option is a {@code Boolean} that controls + * the loopback of multicast datagrams. The value of the socket + * option represents if the option is enabled or disabled. + * + *
The exact semantics of this socket options are system dependent. + * In particular, it is system dependent whether the loopback applies to + * multicast datagrams sent from the socket or received by the socket. + * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is + * system dependent whether the option also applies to multicast datagrams + * sent to IPv4 addresses. + * + *
The initial/default value of this socket option is {@code TRUE}. An + * implementation allows this socket option to be set after the socket is + * bound. Whether the socket option can be queried or changed prior to + * binding the socket is system dependent. + * + * @see java.nio.channels.MulticastChannel + */ + public static final SocketOption
+ * MBean, + *IP_MULTICAST_LOOP = + new StdSocketOption ("IP_MULTICAST_LOOP", Boolean.class); + + + // -- IPPROTO_TCP -- + + /** + * Disable the Nagle algorithm. + * + * The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. The socket option is specific to + * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm + * known as The Nagle Algorithm to coalesce short segments and + * improve network efficiency. + * + *
The default value of this socket option is {@code FALSE}. The + * socket option should only be enabled in cases where it is known that the + * coalescing impacts performance. The socket option may be enabled at any + * time. In other words, the Nagle Algorithm can be disabled. Once the option + * is enabled, it is system dependent whether it can be subsequently + * disabled. In that case, invoking the {@code setOption} method to disable + * the option has no effect. + * + * @see RFC 1122: + * Requirements for Internet Hosts -- Communication Layers + */ + public static final SocketOption
+ * connected. + * + *TCP_NODELAY = + new StdSocketOption ("TCP_NODELAY", Boolean.class); + + + private static class StdSocketOption implements SocketOption { + private final String name; + private final Class type; + StdSocketOption(String name, Class type) { + this.name = name; + this.type = type; + } + @Override public String name() { return name; } + @Override public Class type() { return type; } + @Override public String toString() { return name; } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/Bits.java --- a/jdk/src/share/classes/java/nio/Bits.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/Bits.java Wed Jul 05 16:41:30 2017 +0200 @@ -29,6 +29,8 @@ import java.security.PrivilegedAction; import sun.misc.Unsafe; import sun.misc.VM; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; /** * Access to bits, native and otherwise. @@ -625,13 +627,15 @@ // direct buffer memory. This value may be changed during VM // initialization if it is launched with "-XX:MaxDirectMemorySize= ". private static volatile long maxMemory = VM.maxDirectMemory(); - private static volatile long reservedMemory = 0; + private static volatile long reservedMemory; + private static volatile long usedMemory; + private static volatile long count; private static boolean memoryLimitSet = false; // These methods should be called whenever direct memory is allocated or // freed. They allow the user to control the amount of direct memory // which a process may access. All sizes are specified in bytes. - static void reserveMemory(long size) { + static void reserveMemory(long size, int cap) { synchronized (Bits.class) { if (!memoryLimitSet && VM.isBooted()) { @@ -640,6 +644,8 @@ } if (size <= maxMemory - reservedMemory) { reservedMemory += size; + usedMemory += cap; + count++; return; } } @@ -655,17 +661,71 @@ if (reservedMemory + size > maxMemory) throw new OutOfMemoryError("Direct buffer memory"); reservedMemory += size; + usedMemory += cap; + count++; } } - static synchronized void unreserveMemory(long size) { + static synchronized void unreserveMemory(long size, int cap) { if (reservedMemory > 0) { reservedMemory -= size; + usedMemory -= cap; + count--; assert (reservedMemory > -1); } } + // -- Management interface for monitoring of direct buffer usage -- + + static { + // setup access to this package in SharedSecrets + sun.misc.SharedSecrets.setJavaNioAccess( + new sun.misc.JavaNioAccess() { + @Override + public BufferPoolMXBean getDirectBufferPoolMXBean() { + return LazyInitialization.directBufferPoolMXBean; + } + } + ); + } + + // Lazy initialization of management interface + private static class LazyInitialization { + static final BufferPoolMXBean directBufferPoolMXBean = directBufferPoolMXBean(); + + private static BufferPoolMXBean directBufferPoolMXBean() { + final String pool = "direct"; + final ObjectName obj; + try { + obj = new ObjectName("java.nio:type=BufferPool,name=" + pool); + } catch (MalformedObjectNameException x) { + throw new AssertionError(x); + } + return new BufferPoolMXBean() { + @Override + public ObjectName getObjectName() { + return obj; + } + @Override + public String getName() { + return pool; + } + @Override + public long getCount() { + return Bits.count; + } + @Override + public long getTotalCapacity() { + return Bits.usedMemory; + } + @Override + public long getMemoryUsed() { + return Bits.reservedMemory; + } + }; + } + } // -- Bulk get/put acceleration -- @@ -675,14 +735,68 @@ static final int JNI_COPY_TO_ARRAY_THRESHOLD = 6; static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6; + // This number limits the number of bytes to copy per call to Unsafe's + // copyMemory method. A limit is imposed to allow for safepoint polling + // during a large copy + static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L; + // These methods do no bounds checking. Verification that the copy will not // result in memory corruption should be done prior to invocation. // All positions and lengths are specified in bytes. - static native void copyFromByteArray(Object src, long srcPos, long dstAddr, - long length); - static native void copyToByteArray(long srcAddr, Object dst, long dstPos, - long length); + /** + * Copy from given source array to destination address. + * + * @param src + * source array + * @param srcBaseOffset + * offset of first element of storage in source array + * @param srcPos + * offset within source array of the first element to read + * @param dstAddr + * destination address + * @param length + * number of bytes to copy + */ + static void copyFromArray(Object src, long srcBaseOffset, long srcPos, + long dstAddr, long length) + { + long offset = srcBaseOffset + srcPos; + while (length > 0) { + long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; + unsafe.copyMemory(src, offset, null, dstAddr, size); + length -= size; + offset += size; + dstAddr += size; + } + } + + /** + * Copy from source address into given destination array. + * + * @param srcAddr + * source address + * @param dst + * destination array + * @param dstBaseOffset + * offset of first element of storage in destination array + * @param dstPos + * offset within destination array of the first element to write + * @param length + * number of bytes to copy + */ + static void copyToArray(long srcAddr, Object dst, long dstBaseOffset, long dstPos, + long length) + { + long offset = dstBaseOffset + dstPos; + while (length > 0) { + long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; + unsafe.copyMemory(null, srcAddr, dst, offset, size); + length -= size; + srcAddr += size; + offset += size; + } + } static void copyFromCharArray(Object src, long srcPos, long dstAddr, long length) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/BufferPoolMXBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/BufferPoolMXBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio; + +import java.lang.management.PlatformManagedObject; + +/** + * The management interface for a buffer pool. + * + * A class implementing this interface is an MXBean. A Java + * virtual machine has one or more implementations of this interface. The {@link + * java.lang.management.ManagementFactory#getPlatformMXBeans getPlatformMXBeans} + * method can be used to obtain the list of {@code BufferPoolMXBean} objects + * representing the management interfaces for pools of buffers as follows: + *
+ * List<BufferPoolMXBean> pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + *+ * + *The management interfaces are also registered with the platform {@link + * javax.management.MBeanServer MBeanServer}. The {@link + * javax.management.ObjectName ObjectName} that uniquely identifies the + * management interface within the {@code MBeanServer} takes the form: + *
+ * java.nio:type=BufferPool,name=pool name + *+ * where pool name is the {@link #getName name} of the buffer pool. + * + * @since 1.7 + */ + +public interface BufferPoolMXBean extends PlatformManagedObject { + + /** + * Returns the name representing this buffer pool. + * + * @return The name of this buffer pool. + */ + String getName(); + + /** + * Returns an estimate of the number of buffers in the pool. + * + * @return An estimate of the number of buffers in this pool + */ + long getCount(); + + /** + * Returns an estimate of the total capacity of the buffers in this pool. + * A buffer's capacity is the number of elements it contains and the value + * returned by this method is an estimate of the total capacity of buffers + * in the pool in bytes. + * + * @return An estimate of the total capacity of the buffers in this pool + * in bytes + */ + long getTotalCapacity(); + + /** + * Returns an estimate of the memory that the Java virtual machine is using + * for this buffer pool. The value returned by this method may differ + * from the estimate of the total {@link #getTotalCapacity capacity} of + * the buffers in this pool. This difference is explained by alignment, + * memory allocator, and other implementation specific reasons. + * + * @return An estimate of the memory that the Java virtual machine is using + * for this buffer pool in bytes, or {@code -1L} if an estimate of + * the memory usage is not available + */ + long getMemoryUsed(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/Direct-X-Buffer.java --- a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java Wed Jul 05 16:41:30 2017 +0200 @@ -47,6 +47,9 @@ // Cached unsafe-access object protected static final Unsafe unsafe = Bits.unsafe(); + // Cached array base offset + private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class); + // Cached unaligned-access capability protected static final boolean unaligned = Bits.unaligned(); @@ -71,11 +74,13 @@ private static Unsafe unsafe = Unsafe.getUnsafe(); private long address; + private long size; private int capacity; - private Deallocator(long address, int capacity) { + private Deallocator(long address, long size, int capacity) { assert (address != 0); this.address = address; + this.size = size; this.capacity = capacity; } @@ -86,7 +91,7 @@ } unsafe.freeMemory(address); address = 0; - Bits.unreserveMemory(capacity); + Bits.unreserveMemory(size, capacity); } } @@ -110,23 +115,25 @@ Direct$Type$Buffer$RW$(int cap) { // package-private #if[rw] super(-1, 0, cap, cap, false); - Bits.reserveMemory(cap); int ps = Bits.pageSize(); + int size = cap + ps; + Bits.reserveMemory(size, cap); + long base = 0; try { - base = unsafe.allocateMemory(cap + ps); + base = unsafe.allocateMemory(size); } catch (OutOfMemoryError x) { - Bits.unreserveMemory(cap); + Bits.unreserveMemory(size, cap); throw x; } - unsafe.setMemory(base, cap + ps, (byte) 0); + unsafe.setMemory(base, size, (byte) 0); if (base % ps != 0) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } - cleaner = Cleaner.create(this, new Deallocator(base, cap)); + cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); #else[rw] super(cap); #end[rw] @@ -238,14 +245,16 @@ if (length > rem) throw new BufferUnderflowException(); +#if[!byte] if (order() != ByteOrder.nativeOrder()) Bits.copyTo$Memtype$Array(ix(pos), dst, offset << $LG_BYTES_PER_VALUE$, length << $LG_BYTES_PER_VALUE$); else - Bits.copyToByteArray(ix(pos), dst, - offset << $LG_BYTES_PER_VALUE$, - length << $LG_BYTES_PER_VALUE$); +#end[!byte] + Bits.copyToArray(ix(pos), dst, arrayBaseOffset, + offset << $LG_BYTES_PER_VALUE$, + length << $LG_BYTES_PER_VALUE$); position(pos + length); } else { super.get(dst, offset, length); @@ -328,12 +337,14 @@ if (length > rem) throw new BufferOverflowException(); +#if[!byte] if (order() != ByteOrder.nativeOrder()) Bits.copyFrom$Memtype$Array(src, offset << $LG_BYTES_PER_VALUE$, ix(pos), length << $LG_BYTES_PER_VALUE$); else - Bits.copyFromByteArray(src, offset << $LG_BYTES_PER_VALUE$, - ix(pos), length << $LG_BYTES_PER_VALUE$); +#end[!byte] + Bits.copyFromArray(src, arrayBaseOffset, offset << $LG_BYTES_PER_VALUE$, + ix(pos), length << $LG_BYTES_PER_VALUE$); position(pos + length); } else { super.put(src, offset, length); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/DatagramChannel.java --- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Wed Jul 05 16:41:30 2017 +0200 @@ -26,28 +26,21 @@ package java.nio.channels; import java.io.IOException; +import java.net.ProtocolFamily; import java.net.DatagramSocket; +import java.net.SocketOption; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.spi.*; - /** * A selectable channel for datagram-oriented sockets. * - * - *Datagram channels are not a complete abstraction of network datagram - * sockets. Binding and the manipulation of socket options must be done - * through an associated {@link java.net.DatagramSocket} object obtained by - * invoking the {@link #socket() socket} method. It is not possible to create - * a channel for an arbitrary, pre-existing datagram socket, nor is it possible - * to specify the {@link java.net.DatagramSocketImpl} object to be used by a - * datagram socket associated with a datagram channel. - * - *
A datagram channel is created by invoking the {@link #open open} method - * of this class. A newly-created datagram channel is open but not connected. - * A datagram channel need not be connected in order for the {@link #send send} - * and {@link #receive receive} methods to be used. A datagram channel may be + *
A datagram channel is created by invoking one of the {@link #open open} methods + * of this class. It is not possible to create a channel for an arbitrary, + * pre-existing datagram socket. A newly-created datagram channel is open but not + * connected. A datagram channel need not be connected in order for the {@link #send + * send} and {@link #receive receive} methods to be used. A datagram channel may be * connected, by invoking its {@link #connect connect} method, in order to * avoid the overhead of the security checks are otherwise performed as part of * every send and receive operation. A datagram channel must be connected in @@ -59,11 +52,57 @@ * disconnected or closed. Whether or not a datagram channel is connected may * be determined by invoking its {@link #isConnected isConnected} method. * + *
Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Datagram channels support the following options: + *
+ *+ * Additional (implementation specific) options may also be supported. + * *+ *
+ *+ * + *Option Name + *Description + *+ * + *{@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} + *The size of the socket send buffer + *+ * + *{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} + *The size of the socket receive buffer + *+ * + *{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} + *Re-use address + *+ * + *{@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} + *Allow transmission of broadcast datagrams + *+ * + *{@link java.net.StandardSocketOption#IP_TOS IP_TOS} + *The Type of Service (ToS) octet in the Internet Protocol (IP) header + *+ * + *{@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} + *The network interface for Internet Protocol (IP) multicast datagrams + *+ * + *{@link java.net.StandardSocketOption#IP_MULTICAST_TTL + * IP_MULTICAST_TTL} + *The time-to-live for Internet Protocol (IP) multicast + * datagrams + *+ * + *{@link java.net.StandardSocketOption#IP_MULTICAST_LOOP + * IP_MULTICAST_LOOP} + *Loopback for Internet Protocol (IP) multicast datagrams + *Datagram channels are safe for use by multiple concurrent threads. They * support concurrent reading and writing, though at most one thread may be * reading and at most one thread may be writing at any given time.
* - * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 @@ -71,7 +110,7 @@ public abstract class DatagramChannel extends AbstractSelectableChannel - implements ByteChannel, ScatteringByteChannel, GatheringByteChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel { /** @@ -88,7 +127,13 @@ * java.nio.channels.spi.SelectorProvider#openDatagramChannel() * openDatagramChannel} method of the system-wide default {@link * java.nio.channels.spi.SelectorProvider} object. The channel will not be - * connected.The {@link ProtocolFamily ProtocolFamily} of the channel's socket + * is platform (and possibly configuration) dependent and therefore unspecified. + * The {@link #open(ProtocolFamily) open} allows the protocol family to be + * selected when opening a datagram channel, and should be used to open + * datagram channels that are intended for Internet Protocol multicasting. * * @return A new datagram channel * @@ -100,6 +145,39 @@ } /** + * Opens a datagram channel. + * + *
The {@code family} parameter is used to specify the {@link + * ProtocolFamily}. If the datagram channel is to be used for IP multicasing + * then this should correspond to the address type of the multicast groups + * that this channel will join. + * + *
The new channel is created by invoking the {@link + * java.nio.channels.spi.SelectorProvider#openDatagramChannel(ProtocolFamily) + * openDatagramChannel} method of the system-wide default {@link + * java.nio.channels.spi.SelectorProvider} object. The channel will not be + * connected. + * + * @param family + * The protocol family + * + * @return A new datagram channel + * + * @throws UnsupportedOperationException + * If the specified protocol family is not supported. For example, + * suppose the parameter is specified as {@link + * java.net.StandardProtocolFamily#INET6 StandardProtocolFamily.INET6} + * but IPv6 is not enabled on the platform. + * @throws IOException + * If an I/O error occurs + * + * @since 1.7 + */ + public static DatagramChannel open(ProtocolFamily family) throws IOException { + return SelectorProvider.provider().openDatagramChannel(family); + } + + /** * Returns an operation set identifying this channel's supported * operations. * @@ -118,6 +196,32 @@ // -- Socket-specific operations -- /** + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies the + * operation + * + * @since 1.7 + */ + public abstract DatagramChannel bind(SocketAddress local) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * + * @since 1.7 + */ + public abstract
* *DatagramChannel setOption(SocketOption name, T value) + throws IOException; + + + /** * Retrieves a datagram socket associated with this channel. * * The returned object will not declare any public methods that are not @@ -128,10 +232,10 @@ public abstract DatagramSocket socket(); /** - * Tells whether or not this channel's socket is connected.
+ * Tells whether or not this channel's socket is connected. * - * @return true if, and only if, this channel's socket - * is connected + * @return {@code true} if, and only if, this channel's socket + * is {@link #isOpen open} and connected */ public abstract boolean isConnected(); @@ -207,6 +311,19 @@ public abstract DatagramChannel disconnect() throws IOException; /** + * Returns the remote address to which this channel's socket is connected. + * + * @return The remote address; {@code null} if the channel is not {@link + * #isOpen open} or the channel's socket is not connected + * + * @throws IOException + * If an I/O error occurs + * + * @since 1.7 + */ + public abstract SocketAddress getConnectedAddress() throws IOException; + + /** * Receives a datagram via this channel. * *If a datagram is immediately available, or if this channel is in diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/MembershipKey.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,183 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.io.IOException; +import java.util.List; + +/** + * A token representing the membership of an Internet Protocol (IP) multicast + * group. + * + *
A membership key may represent a membership to receive all datagrams sent + * to the group, or it may be source-specific, meaning that it + * represents a membership that receives only datagrams from a specific source + * address. Whether or not a membership key is source-specific may be determined + * by invoking its {@link #getSourceAddress() getSourceAddress} method. + * + *
A membership key is valid upon creation and remains valid until the + * membership is dropped by invoking the {@link #drop() drop} method, or + * the channel is closed. The validity of the membership key may be tested + * by invoking its {@link #isValid() isValid} method. + * + *
Where a membership key is not source-specific and the underlying operation + * system supports source filtering, then the {@link #block block} and {@link + * #unblock unblock} methods can be used to block or unblock multicast datagrams + * from particular source addresses. + * + * @see MulticastChannel + * + * @since 1.7 + */ +public abstract class MembershipKey { + + /** + * Initializes a new instance of this class. + */ + protected MembershipKey() { + } + + /** + * Tells whether or not this membership is valid. + * + *
A multicast group membership is valid upon creation and remains + * valid until the membership is dropped by invoking the {@link #drop() drop} + * method, or the channel is closed. + * + * @return {@code true} if this membership key is valid, {@code false} + * otherwise + */ + public abstract boolean isValid(); + + /** + * Drop membership. + * + *
If the membership key represents a membership to receive all datagrams + * then the membership is dropped and the channel will no longer receive any + * datagrams sent to the group. If the membership key is source-specific + * then the channel will no longer receive datagrams sent to the group from + * that source address. + * + *
After membership is dropped it may still be possible to receive + * datagrams sent to the group. This can arise when datagrams are waiting to + * be received in the socket's receive buffer. After membership is dropped + * then the channel may {@link MulticastChannel#join join} the group again + * in which case a new membership key is returned. + * + *
Upon return, this membership object will be {@link #isValid() invalid}. + * If the multicast group membership is already invalid then invoking this + * method has no effect. Once a multicast group membership is invalid, + * it remains invalid forever. + * + * @throws IOException + * If an I/O error occurs + */ + public abstract void drop() throws IOException; + + /** + * Block multicast datagrams from the given source address. + * + *
If this membership key is not source-specific, and the underlying + * operating system supports source filtering, then this method blocks + * multicast datagrams from the given source address. If the given source + * address is already blocked then this method has no effect. + * After a source address is blocked it may still be possible to receive + * datagams from that source. This can arise when datagrams are waiting to + * be received in the socket's receive buffer. + * + * @param source + * The source address to block + * + * @return This membership key + * + * @throws IllegalArgumentException + * If the {@code source} parameter is not a unicast address or + * is not the same address type as the multicast group + * @throws IllegalStateException + * If this membership key is source-specific or is no longer valid + * @throws UnsupportedOperationException + * If the underlying operating system does not support source + * filtering + * @throws IOException + * If an I/O error occurs + */ + public abstract MembershipKey block(InetAddress source) throws IOException; + + /** + * Unblock multicast datagrams from the given source address that was + * previously blocked using the {@link #block(InetAddress) block} method. + * + * @param source + * The source address to unblock + * + * @return This membership key + * + * @throws IllegalStateException + * If the given source address is not currently blocked or the + * membership key is no longer valid + * @throws IOException + * If an I/O error occurs + */ + public abstract MembershipKey unblock(InetAddress source) throws IOException; + + /** + * Returns the channel for which this membership key was created. This + * method will continue to return the channel even after the membership + * becomes {@link #isValid invalid}. + * + * @return the channel + */ + public abstract MulticastChannel getChannel(); + + /** + * Returns the multicast group for which this membership key was created. + * This method will continue to return the group even after the membership + * becomes {@link #isValid invalid}. + * + * @return the multicast group + */ + public abstract InetAddress getGroup(); + + /** + * Returns the network interface for which this membership key was created. + * This method will continue to return the network interface even after the + * membership becomes {@link #isValid invalid}. + * + * @return the network interface + */ + public abstract NetworkInterface getNetworkInterface(); + + /** + * Returns the source address if this membership key is source-specific, + * or {@code null} if this membership is not source-specific. + * + * @return The source address if this membership key is source-specific, + * otherwise {@code null} + */ + public abstract InetAddress getSourceAddress(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/MulticastChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,211 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.io.IOException; +import java.net.ProtocolFamily; // javadoc +import java.net.StandardProtocolFamily; // javadoc +import java.net.StandardSocketOption; // javadoc + +/** + * A network channel that supports Internet Protocol (IP) multicasting. + * + *
IP multicasting is the transmission of IP datagrams to members of + * a group that is zero or more hosts identified by a single destination + * address. + * + *
In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket, + * the underlying operating system supports + * RFC 2236: Internet Group Management Protocol, Version 2 (IGMPv2). + * It may optionally support source filtering as specified by RFC 3376: Internet Group + * Management Protocol, Version 3 (IGMPv3). + * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent + * standards are RFC 2710: + * Multicast Listener Discovery (MLD) for IPv6 and RFC 3810: Multicast Listener + * Discovery Version 2 (MLDv2) for IPv6. + * + *
The {@link #join(InetAddress,NetworkInterface)} method is used to + * join a group and receive all multicast datagrams sent to the group. A channel + * may join several multicast groups and may join the same group on several + * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link + * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the + * underlying platform supports source filtering then the {@link MembershipKey#block + * block} and {@link MembershipKey#unblock unblock} methods can be used to block or + * unblock multicast datagrams from particular source addresses. + * + *
The {@link #join(InetAddress,NetworkInterface,InetAddress)} method + * is used to begin receiving datagrams sent to a group whose source address matches + * a given source address. This method throws {@link UnsupportedOperationException} + * if the underlying platform does not support source filtering. Membership is + * cumulative and this method may be invoked again with the same group + * and interface to allow receiving datagrams from other source addresses. The + * method returns a {@link MembershipKey} that represents membership to receive + * datagrams from the given source address. Invoking the key's {@link + * MembershipKey#drop drop} method drops membership so that datagrams from the + * source address can no longer be received. + * + *
Platform dependencies
+ * + * The multicast implementation is intended to map directly to the native + * multicasting facility. Consequently, the following items should be considered + * when developing an application that receives IP multicast datagrams: + * + *+ * + *
+ * + *- + * + *
The creation of the channel should specify the {@link ProtocolFamily} + * that corresponds to the address type of the multicast groups that the channel + * will join. There is no guarantee that a channel to a socket in one protocol + * family can join and receive multicast datagrams when the address of the + * multicast group corresponds to another protocol family. For example, it is + * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6} + * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive + * multicast datagrams sent to the group.
- + * + *
The channel's socket should be bound to the {@link + * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to + * a specific address, rather than the wildcard address then it is implementation + * specific if multicast datagrams are received by the socket.
- + * + *
The {@link StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} option should be + * enabled prior to {@link NetworkChannel#bind binding} the socket. This is + * required to allow multiple members of the group to bind to the same + * address.
Usage Example: + *
+ * // join multicast group on this interface, and also use this + * // interface for outgoing multicast datagrams + * NetworkInterface ni = NetworkInterface.getByName("hme0"); + * + * DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET) + * .setOption(StandardSocketOption.SO_REUSEADDR, true) + * .bind(new InetSocketAddress(5000)) + * .setOption(StandardSocketOption.IP_MULTICAST_IF, ni); + * + * InetAddress group = InetAddress.getByName("225.4.5.6"); + * + * MembershipKey key = dc.join(group, ni); + *+ * + * @since 1.7 + */ + +public interface MulticastChannel + extends NetworkChannel +{ + /** + * Joins a multicast group to begin receiving all datagrams sent to the group, + * returning a membership key. + * + *If this channel is currently a member of the group on the given + * interface to receive all datagrams then the membership key, representing + * that membership, is returned. Otherwise this channel joins the group and + * the resulting new membership key is returned. The resulting membership key + * is not {@link MembershipKey#getSourceAddress source-specific}. + * + *
A multicast channel may join several multicast groups, including + * the same group on more than one interface. An implementation may impose a + * limit on the number of groups that may be joined at the same time. + * + * @param group + * The multicast address to join + * @param interf + * The network interface on which to join the group + * + * @return The membership key + * + * @throws IllegalArgumentException + * If the group parameter is not a {@link InetAddress#isMulticastAddress + * multicast} address, or the group parameter is an address type + * that is not supported by this channel + * @throws IllegalStateException + * If the channel already has source-specific membership of the + * group on the interface + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is set, and its + * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast} + * method denies access to the multiast group + */ + MembershipKey join(InetAddress group, NetworkInterface interf) + throws IOException; + + /** + * Joins a multicast group to begin receiving datagrams sent to the group + * from a given source address. + * + *
If this channel is currently a member of the group on the given + * interface to receive datagrams from the given source address then the + * membership key, representing that membership, is returned. Otherwise this + * channel joins the group and the resulting new membership key is returned. + * The resulting membership key is {@link MembershipKey#getSourceAddress + * source-specific}. + * + *
Membership is cumulative and this method may be invoked + * again with the same group and interface to allow receiving datagrams sent + * by other source addresses to the group. + * + * @param group + * The multicast address to join + * @param interf + * The network interface on which to join the group + * @param source + * The source address + * + * @return The membership key + * + * @throws IllegalArgumentException + * If the group parameter is not a {@link + * InetAddress#isMulticastAddress multicast} address, the + * source parameter is not a unicast address, the group + * parameter is an address type that is not supported by this channel, + * or the source parameter is not the same address type as the group + * @throws IllegalStateException + * If the channel is currently a member of the group on the given + * interface to receive all datagrams + * @throws UnsupportedOperationException + * If the underlying operation system does not support source filtering + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If a security manager is set, and its + * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast} + * method denies access to the multiast group + */ + MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) + throws IOException; +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/NetworkChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,158 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.nio.channels; + +import java.net.SocketOption; +import java.net.SocketAddress; +import java.util.Set; +import java.io.IOException; + +/** + * A channel to a network socket. + * + *
A channel that implements this interface is a channel to a network + * socket. The {@link #bind(SocketAddress) bind} method is used to bind the + * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress() + * getLocalAddress} method returns the address that the socket is bound to, and + * the {@link #setOption(SocketOption,Object) setOption} and {@link + * #getOption(SocketOption) getOption} methods are used to set and query socket + * options. An implementation of this interface should specify the socket options + * that it supports. + * + *
The {@link #bind bind} and {@link #setOption setOption} methods that do + * not otherwise have a value to return are specified to return the network + * channel upon which they are invoked. This allows method invocations to be + * chained. Implementations of this interface should specialize the return type + * so that method invocations on the implementation class can be chained. + * + * @since 1.7 + */ + +public interface NetworkChannel + extends Channel +{ + /** + * Binds the channel's socket to a local address. + * + *
This method is used to establish an association between the socket and + * a local address. Once an association is established then the socket remains + * bound until the channel is closed. If the {@code local} parameter has the + * value {@code null} then the socket will be bound to an address that is + * assigned automatically. + * + * @param local + * The address to bind the socket, or {@code null} to bind the socket + * to an automatically assigned socket address + * + * @return This channel + * + * @throws AlreadyBoundException + * If the socket is already bound + * @throws UnsupportedAddressTypeException + * If the type of the given address is not supported + * @throws ClosedChannelException + * If the channel is closed + * @throws IOException + * If some other I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission. An implementation of this interface should specify + * any required permissions. + * + * @see #getLocalAddress + */ + NetworkChannel bind(SocketAddress local) throws IOException; + + /** + * Returns the socket address that this channel's socket is bound to, or + * {@code null} if the socket is not bound. + * + *
Where the channel is {@link #bind bound} to an Internet Protocol + * socket address then the return value from this method is of type {@link + * java.net.InetSocketAddress}. + * + * @return The socket address that the socket is bound to, or {@code null} + * if the channel is not {@link #isOpen open} or the channel's socket + * is not bound + * + * @throws IOException + * If an I/O error occurs + */ + SocketAddress getLocalAddress() throws IOException; + + /** + * Sets the value of a socket option. + * + * @param name + * The socket option + * @param value + * The value of the socket option. A value of {@code null} may be + * a valid value for some socket options. + * + * @return This channel + * + * @throws IllegalArgumentException + * If the socket option is not supported by this channel, or + * the value is not a valid value for this socket option + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If an I/O error occurs + * + * @see java.net.StandardSocketOption + */ +
* + *NetworkChannel setOption(SocketOption name, T value) throws IOException; + + /** + * Returns the value of a socket option. + * + * @param name + * The socket option + * + * @return The value of the socket option. A value of {@code null} may be + * a valid value for some socket options. + * + * @throws IllegalArgumentException + * If the socket option is not supported by this channel + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If an I/O error occurs + * + * @see java.net.StandardSocketOption + */ + T getOption(SocketOption name) throws IOException; + + /** + * Returns a set of the socket options supported by this channel. + * + * This method will continue to return the set of options even after the + * channel has been closed. + * + * @return A set of the socket options supported by this channel + */ + Set
* *> options(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java Wed Jul 05 16:41:30 2017 +0200 @@ -27,33 +27,44 @@ import java.io.IOException; import java.net.ServerSocket; +import java.net.SocketOption; import java.net.SocketAddress; import java.nio.channels.spi.*; - /** * A selectable channel for stream-oriented listening sockets. * - * Server-socket channels are not a complete abstraction of listening - * network sockets. Binding and the manipulation of socket options must be - * done through an associated {@link java.net.ServerSocket} object obtained by - * invoking the {@link #socket() socket} method. It is not possible to create - * a channel for an arbitrary, pre-existing server socket, nor is it possible - * to specify the {@link java.net.SocketImpl} object to be used by a server - * socket associated with a server-socket channel. + *
A server-socket channel is created by invoking the {@link #open() open} + * method of this class. It is not possible to create a channel for an arbitrary, + * pre-existing {@link ServerSocket}. A newly-created server-socket channel is + * open but not yet bound. An attempt to invoke the {@link #accept() accept} + * method of an unbound server-socket channel will cause a {@link NotYetBoundException} + * to be thrown. A server-socket channel can be bound by invoking one of the + * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class. * - *
A server-socket channel is created by invoking the {@link #open() open} - * method of this class. A newly-created server-socket channel is open but not - * yet bound. An attempt to invoke the {@link #accept() accept} method of an - * unbound server-socket channel will cause a {@link NotYetBoundException} to - * be thrown. A server-socket channel can be bound by invoking one of the - * {@link java.net.ServerSocket#bind(java.net.SocketAddress,int) bind} methods - * of an associated server socket. + *
Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Server-socket channels support the following options: + *
+ *+ * Additional (implementation specific) options may also be supported. * *+ *
+ *+ * + *Option Name + *Description + *+ * + *{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} + *The size of the socket receive buffer + *+ * + *{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} + *Re-use address + *Server-socket channels are safe for use by multiple concurrent threads. *
* - * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 @@ -61,6 +72,7 @@ public abstract class ServerSocketChannel extends AbstractSelectableChannel + implements NetworkChannel { /** @@ -110,6 +122,89 @@ // -- ServerSocket-specific operations -- /** + * Binds the channel's socket to a local address and configures the socket + * to listen for connections. + * + *An invocation of this method is equivalent to the following: + *
+ * + * @param local + * The local address to bind the socket, or {@code null} to bind + * to an automatically assigned socket address + * + * @return This channel + * + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies the + * operation + * + * @since 1.7 + */ + public final ServerSocketChannel bind(SocketAddress local) + throws IOException + { + return bind(local, 0); + } + + /** + * Binds the channel's socket to a local address and configures the socket to + * listen for connections. + * + *+ * bind(local, 0); + *This method is used to establish an association between the socket and + * a local address. Once an association is established then the socket remains + * bound until the channel is closed. + * + *
The {@code backlog} parameter is the maximum number of pending + * connections on the socket. Its exact semantics are implementation specific. + * In particular, an implementation may impose a maximum length or may choose + * to ignore the parameter altogther. If the {@code backlog} parameter has + * the value {@code 0}, or a negative value, then an implementation specific + * default is used. + * + * @param local + * The address to bind the socket, or {@code null} to bind to an + * automatically assigned socket address + * @param backlog + * The maximum number of pending connections + * + * @return This channel + * + * @throws AlreadyBoundException + * If the socket is already bound + * @throws UnsupportedAddressTypeException + * If the type of the given address is not supported + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + * @throws SecurityException + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies the + * operation + * + * @since 1.7 + */ + public abstract ServerSocketChannel bind(SocketAddress local, int backlog) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * + * @since 1.7 + */ + public abstract
* - *ServerSocketChannel setOption(SocketOption name, T value) + throws IOException; + + /** * Retrieves a server socket associated with this channel. * * The returned object will not declare any public methods that are not diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/SocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java Wed Jul 05 16:41:30 2017 +0200 @@ -27,24 +27,17 @@ import java.io.IOException; import java.net.Socket; +import java.net.SocketOption; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.spi.*; - /** * A selectable channel for stream-oriented connecting sockets. * - *
Socket channels are not a complete abstraction of connecting network - * sockets. Binding, shutdown, and the manipulation of socket options must be - * done through an associated {@link java.net.Socket} object obtained by - * invoking the {@link #socket() socket} method. It is not possible to create - * a channel for an arbitrary, pre-existing socket, nor is it possible to - * specify the {@link java.net.SocketImpl} object to be used by a socket - * associated with a socket channel. - * *
A socket channel is created by invoking one of the {@link #open open} - * methods of this class. A newly-created socket channel is open but not yet + * methods of this class. It is not possible to create a channel for an arbitrary, + * pre-existing socket. A newly-created socket channel is open but not yet * connected. An attempt to invoke an I/O operation upon an unconnected * channel will cause a {@link NotYetConnectedException} to be thrown. A * socket channel can be connected by invoking its {@link #connect connect} @@ -59,16 +52,6 @@ * Whether or not a connection operation is in progress may be determined by * invoking the {@link #isConnectionPending isConnectionPending} method. * - *
The input and output sides of a socket channel may independently be - * shut down without actually closing the channel. Shutting down the - * input side of a channel by invoking the {@link java.net.Socket#shutdownInput - * shutdownInput} method of an associated socket object will cause further - * reads on the channel to return -1, the end-of-stream indication. - * Shutting down the output side of the channel by invoking the {@link - * java.net.Socket#shutdownOutput shutdownOutput} method of an associated - * socket object will cause further writes on the channel to throw a {@link - * ClosedChannelException}. - * *
Socket channels support asynchronous shutdown, which is similar * to the asynchronous close operation specified in the {@link Channel} class. * If the input side of a socket is shut down by one thread while another @@ -79,6 +62,43 @@ * channel, then the blocked thread will receive an {@link * AsynchronousCloseException}. * + *
Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Socket channels support the following options: + *
+ *+ * Additional (implementation specific) options may also be supported. + * *+ *
+ *+ * + *Option Name + *Description + *+ * + *{@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} + *The size of the socket send buffer + *+ * + *{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} + *The size of the socket receive buffer + *+ * + *{@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE} + *Keep connection alive + *+ * + *{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} + *Re-use address + *+ * + *{@link java.net.StandardSocketOption#SO_LINGER SO_LINGER} + *Linger on close if data is present (when configured in blocking mode + * only) + *+ * + *{@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY} + *Disable the Nagle algorithm + *Socket channels are safe for use by multiple concurrent threads. They * support concurrent reading and writing, though at most one thread may be * reading and at most one thread may be writing at any given time. The {@link @@ -87,7 +107,6 @@ * or write operation while an invocation of one of these methods is in * progress will block until that invocation is complete.
* - * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 @@ -95,7 +114,7 @@ public abstract class SocketChannel extends AbstractSelectableChannel - implements ByteChannel, ScatteringByteChannel, GatheringByteChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel { /** @@ -192,6 +211,73 @@ // -- Socket-specific operations -- /** + * @throws ConnectionPendingException + * If a non-blocking connection operation is already in progress on + * this channel + * @throws AlreadyBoundException {@inheritDoc} + * @throws UnsupportedAddressTypeException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * + * @since 1.7 + */ + @Override + public abstract SocketChannel bind(SocketAddress local) + throws IOException; + + /** + * @throws IllegalArgumentException {@inheritDoc} + * @throws ClosedChannelException {@inheritDoc} + * @throws IOException {@inheritDoc} + * + * @since 1.7 + */ + @Override + public abstractSocketChannel setOption(SocketOption name, T value) + throws IOException; + + /** + * Shutdown the connection for reading without closing the channel. + * + * Once shutdown for reading then further reads on the channel will + * return {@code -1}, the end-of-stream indication. If the input side of the + * connection is already shutdown then invoking this method has no effect. + * + * @return The channel + * + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + * + * @since 1.7 + */ + public abstract SocketChannel shutdownInput() throws IOException; + + /** + * Shutdown the connection for writing without closing the channel. + * + *
Once shutdown for writing then further attempts to write to the + * channel will throw {@link ClosedChannelException}. If the output side of + * the connection is already shutdown then invoking this method has no + * effect. + * + * @return The channel + * + * @throws NotYetConnectedException + * If this channel is not yet connected + * @throws ClosedChannelException + * If this channel is closed + * @throws IOException + * If some other I/O error occurs + * + * @since 1.7 + */ + public abstract SocketChannel shutdownOutput() throws IOException; + + /** * Retrieves a socket associated with this channel. * *
The returned object will not declare any public methods that are not @@ -202,10 +288,10 @@ public abstract Socket socket(); /** - * Tells whether or not this channel's network socket is connected.
+ * Tells whether or not this channel's network socket is connected. * * @return true if, and only if, this channel's network socket - * is connected + * is {@link #isOpen open} and connected */ public abstract boolean isConnected(); @@ -339,6 +425,22 @@ */ public abstract boolean finishConnect() throws IOException; + /** + * Returns the remote address to which this channel's socket is connected. + * + *Where the channel is bound and connected to an Internet Protocol + * socket address then the return value from this method is of type {@link + * java.net.InetSocketAddress}. + * + * @return The remote address; {@code null} if the channel is not {@link + * #isOpen open} or the channel's socket is not connected + * + * @throws IOException + * If an I/O error occurs + * + * @since 1.7 + */ + public abstract SocketAddress getConnectedAddress() throws IOException; // -- ByteChannel operations -- diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/exceptions --- a/jdk/src/share/classes/java/nio/channels/exceptions Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/exceptions Wed Jul 05 16:41:30 2017 +0200 @@ -146,3 +146,14 @@ * virtual machine, or when another thread is already waiting to lock an * overlapping region of the same file." \ 2047812138163068433L + + +SINCE=1.7 + +SUPER=IllegalStateException + +gen AlreadyBoundException " + * Unchecked exception thrown when an attempt is made to bind the socket a + * network oriented channel that is already bound." \ + 6796072983322737592L + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/package-info.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,231 @@ +/* + * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Defines channels, which represent connections to entities that are capable of + * performing I/O operations, such as files and sockets; defines selectors, for + * multiplexed, non-blocking I/O operations. + * + * + * + *
+ * + *+ *
+ * Channels
Description
+ * {@link java.nio.channels.Channel} + *A nexus for I/O operations + * {@link java.nio.channels.ReadableByteChannel} + *Can read into a buffer + * {@link java.nio.channels.ScatteringByteChannel} + *Can read into a sequence of buffers + * {@link java.nio.channels.WritableByteChannel} + *Can write from a buffer + * {@link java.nio.channels.GatheringByteChannel} + *Can write from a sequence of buffers + * {@link java.nio.channels.ByteChannel} + *Can read/write to/from a buffer + * {@link java.nio.channels.SeekableByteChannel} + *A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes + * {@link java.nio.channels.NetworkChannel} + *A channel to a network socket + * {@link java.nio.channels.MulticastChannel} + *Can join Internet Protocol (IP) multicast groups + * {@link java.nio.channels.Channels} + *Utility methods for channel/stream interoperation A channel represents an open connection to an entity such as a + * hardware device, a file, a network socket, or a program component that is + * capable of performing one or more distinct I/O operations, for example reading + * or writing. As specified in the {@link java.nio.channels.Channel} interface, + * channels are either open or closed, and they are both asynchronously + * closeable and interruptible. + * + *
The {@link java.nio.channels.Channel} interface is extended by several + * other interfaces. + * + *
The {@link java.nio.channels.ReadableByteChannel} interface specifies a + * {@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes + * from the channel into a buffer; similarly, the {@link + * java.nio.channels.WritableByteChannel} interface specifies a {@link + * java.nio.channels.WritableByteChannel#write write} method that writes bytes + * from a buffer to the channel. The {@link java.nio.channels.ByteChannel} + * interface unifies these two interfaces for the common case of channels that can + * both read and write bytes. The {@link java.nio.channels.SeekableByteChannel} + * interface extends the {@code ByteChannel} interface with methods to {@link + * java.nio.channels.SeekableByteChannel#position() query} and {@link + * java.nio.channels.SeekableByteChannel#position(long) modify} the channel's + * current position, and its {@link java.nio.channels.SeekableByteChannel#size + * size}. + * + *
The {@link java.nio.channels.ScatteringByteChannel} and {@link + * java.nio.channels.GatheringByteChannel} interfaces extend the {@link + * java.nio.channels.ReadableByteChannel} and {@link + * java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link + * java.nio.channels.ScatteringByteChannel#read read} and {@link + * java.nio.channels.GatheringByteChannel#write write} methods that take a + * sequence of buffers rather than a single buffer. + * + *
The {@link java.nio.channels.NetworkChannel} interface specifies methods + * to {@link java.nio.channels.NetworkChannel#bind bind} the channel's socket, + * obtain the address to which the socket is bound, and methods to {@link + * java.nio.channels.NetworkChannel#getOption get} and {@link + * java.nio.channels.NetworkChannel#setOption set} socket options. The {@link + * java.nio.channels.MulticastChannel} interface specifies methods to join + * Internet Protocol (IP) multicast groups. + * + *
The {@link java.nio.channels.Channels} utility class defines static methods + * that support the interoperation of the stream classes of the {@link + * java.io} package with the channel classes of this package. An appropriate + * channel can be constructed from an {@link java.io.InputStream} or an {@link + * java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an + * {@link java.io.OutputStream} can be constructed from a channel. A {@link + * java.io.Reader} can be constructed that uses a given charset to decode bytes + * from a given readable byte channel, and conversely a {@link java.io.Writer} can + * be constructed that uses a given charset to encode characters into bytes and + * write them to a given writable byte channel. + * + *
+ * + *+ *
+ * File channels
Description
+ * {@link java.nio.channels.FileChannel} + *Reads, writes, maps, and manipulates files + * {@link java.nio.channels.FileLock} + *A lock on a (region of a) file + * {@link java.nio.MappedByteBuffer}/{@link java.nio.MappedBigByteBuffer} + *A direct byte buffer or big byte buffer mapped to a region of a file The {@link java.nio.channels.FileChannel} class supports the usual + * operations of reading bytes from, and writing bytes to, a channel connected to + * a file, as well as those of querying and modifying the current file position + * and truncating the file to a specific size. It defines methods for acquiring + * locks on the whole file or on a specific region of a file; these methods return + * instances of the {@link java.nio.channels.FileLock} class. Finally, it defines + * methods for forcing updates to the file to be written to the storage device that + * contains it, for efficiently transferring bytes between the file and other + * channels, and for mapping a region of the file directly into memory. + * + *
A {@code FileChannel} is created by invoking one of its static {@link + * java.nio.channels.FileChannel#open open} methods, or by invoking the {@code + * getChannel} method of a {@link java.io.FileInputStream}, {@link + * java.io.FileOutputStream}, or {@link java.io.RandomAccessFile} to return a + * file channel connected to the same underlying file as the {@link java.io} + * class. + * + * + *
+ * + *+ *
+ * Multiplexed, non-blocking I/O
Description
+ * {@link java.nio.channels.SelectableChannel} + *A channel that can be multiplexed + * {@link java.nio.channels.DatagramChannel} + *A channel to a datagram-oriented socket + * {@link java.nio.channels.Pipe.SinkChannel} + *The write end of a pipe + * {@link java.nio.channels.Pipe.SourceChannel} + *The read end of a pipe + * {@link java.nio.channels.ServerSocketChannel} + *A channel to a stream-oriented listening socket + * {@link java.nio.channels.SocketChannel} + *A channel for a stream-oriented connecting socket + * {@link java.nio.channels.Selector} + *A multiplexor of selectable channels + * {@link java.nio.channels.SelectionKey} + *A token representing the registration
of a channel + * with a selector+ * {@link java.nio.channels.Pipe} + *Two channels that form a unidirectional pipe Multiplexed, non-blocking I/O, which is much more scalable than + * thread-oriented, blocking I/O, is provided by selectors, selectable + * channels, and selection keys. + * + *
A selector is a multiplexor of selectable channels, which in turn are + * a special type of channel that can be put into non-blocking mode. To perform + * multiplexed I/O operations, one or more selectable channels are first created, + * put into non-blocking mode, and {@link + * java.nio.channels.SelectableChannel#register registered} + * with a selector. Registering a channel specifies the set of I/O operations + * that will be tested for readiness by the selector, and returns a selection key that represents the + * registration. + * + *
Once some channels have been registered with a selector, a selection operation can be performed in + * order to discover which channels, if any, have become ready to perform one or + * more of the operations in which interest was previously declared. If a channel + * is ready then the key returned when it was registered will be added to the + * selector's selected-key set. The key set, and the keys within it, can + * be examined in order to determine the operations for which each channel is + * ready. From each key one can retrieve the corresponding channel in order to + * perform whatever I/O operations are required. + * + *
That a selection key indicates that its channel is ready for some operation + * is a hint, but not a guarantee, that such an operation can be performed by a + * thread without causing the thread to block. It is imperative that code that + * performs multiplexed I/O be written so as to ignore these hints when they prove + * to be incorrect. + * + *
This package defines selectable-channel classes corresponding to the {@link + * java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link + * java.net.Socket} classes defined in the {@link java.net} package. + * Minor changes to these classes have been made in order to support sockets that + * are associated with channels. This package also defines a simple class that + * implements unidirectional pipes. In all cases, a new selectable channel is + * created by invoking the static open method of the corresponding class. + * If a channel needs an associated socket then a socket will be created as a side + * effect of this operation. + * + *
The implementation of selectors, selectable channels, and selection keys + * can be replaced by "plugging in" an alternative definition or instance of the + * {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link + * java.nio.channels.spi} package. It is not expected that many developers + * will actually make use of this facility; it is provided primarily so that + * sophisticated users can take advantage of operating-system-specific + * I/O-multiplexing mechanisms when very high performance is required. + * + *
Much of the bookkeeping and synchronization required to implement the + * multiplexed-I/O abstractions is performed by the {@link + * java.nio.channels.spi.AbstractInterruptibleChannel}, {@link + * java.nio.channels.spi.AbstractSelectableChannel}, {@link + * java.nio.channels.spi.AbstractSelectionKey}, and {@link + * java.nio.channels.spi.AbstractSelector} classes in the {@link + * java.nio.channels.spi} package. When defining a custom selector provider, + * only the {@link java.nio.channels.spi.AbstractSelector} and {@link + * java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed + * directly; custom channel classes should extend the appropriate {@link + * java.nio.channels.SelectableChannel} subclasses defined in this package. + * + *
+ *Unless otherwise noted, passing a null argument to a constructor + * or method in any class or interface in this package will cause a {@link + * java.lang.NullPointerException NullPointerException} to be thrown. + * + * @since 1.4 + * @author Mark Reinhold + * @author JSR-51 Expert Group + */ + +package java.nio.channels; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/package.html --- a/jdk/src/share/classes/java/nio/channels/package.html Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ - - - - -
- -Defines channels, which represent connections to entities that are capable of -performing I/O operations, such as files and sockets; defines selectors, for -multiplexed, non-blocking I/O operations. - - - - -- --
- Channels
Description
- {@link java.nio.channels.Channel} -A nexus for I/O operations - {@link java.nio.channels.ReadableByteChannel} -Can read into a buffer - {@link java.nio.channels.ScatteringByteChannel} -Can read into a sequence of buffers - {@link java.nio.channels.WritableByteChannel} -Can write from a buffer - {@link java.nio.channels.GatheringByteChannel} -Can write from a sequence of buffers - {@link java.nio.channels.ByteChannel} -Can read/write to/from a buffer - {@link java.nio.channels.Channels} -Utility methods for channel/stream interoperation A channel represents an open connection to an entity such as a -hardware device, a file, a network socket, or a program component that is -capable of performing one or more distinct I/O operations, for example reading -or writing. As specified in the {@link java.nio.channels.Channel} interface, -channels are either open or closed, and they are both asynchronously -closeable and interruptible. - -
The {@link java.nio.channels.Channel} interface is extended by several -other interfaces, each of which specifies a new I/O operation. - -
The {@link java.nio.channels.ReadableByteChannel} interface specifies a -{@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes -from the channel into a buffer; similarly, the {@link -java.nio.channels.WritableByteChannel} interface specifies a {@link -java.nio.channels.WritableByteChannel#write write} method that writes bytes -from a buffer to the channel. The {@link java.nio.channels.ByteChannel} -interface unifies these two interfaces for the common case of channels that can -both read and write bytes. - -
The {@link java.nio.channels.ScatteringByteChannel} and {@link -java.nio.channels.GatheringByteChannel} interfaces extend the {@link -java.nio.channels.ReadableByteChannel} and {@link -java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link -java.nio.channels.ScatteringByteChannel#read read} and {@link -java.nio.channels.GatheringByteChannel#write write} methods that take a -sequence of buffers rather than a single buffer. - -
The {@link java.nio.channels.Channels} utility class defines static methods -that support the interoperation of the stream classes of the {@link -java.io} package with the channel classes of this package. An appropriate -channel can be constructed from an {@link java.io.InputStream} or an {@link -java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an -{@link java.io.OutputStream} can be constructed from a channel. A {@link -java.io.Reader} can be constructed that uses a given charset to decode bytes -from a given readable byte channel, and conversely a {@link java.io.Writer} can -be constructed that uses a given charset to encode characters into bytes and -write them to a given writable byte channel. - - -
- --
- File channels
Description
- {@link java.nio.channels.FileChannel} -Reads, writes, maps, and manipulates files - {@link java.nio.channels.FileLock} -A lock on a (region of a) file - {@link java.nio.MappedByteBuffer} -A direct byte buffer mapped to a region of a file The {@link java.nio.channels.FileChannel} class supports the usual -operations of reading bytes from, and writing bytes to, a channel connected to -a file, as well as those of querying and modifying the current file position -and truncating the file to a specific size. It defines methods for acquiring -locks on the whole file or on a specific region of a file; these methods return -instances of the {@link java.nio.channels.FileLock} class. Finally, it defines -methods for forcing updates to the file to be written to the storage device that -contains it, for efficiently transferring bytes between the file and other -channels, and for mapping a region of the file directly into memory. This last -operation creates an instance of the {@link java.nio.MappedByteBuffer} -class, which extends the {@link java.nio.ByteBuffer} class with several -file-related operations. - -
A getChannel method has been added to each of the {@link -java.io.FileInputStream#getChannel FileInputStream}, {@link -java.io.FileOutputStream#getChannel FileOutputStream}, and {@link -java.io.RandomAccessFile#getChannel RandomAccessFile} classes of the {@link -java.io java.io} package. Invoking this method upon an instance of one of -these classes will return a file channel connected to the underlying file. - - - - -
* - *- --
- Multiplexed, non-blocking I/O
Description
- {@link java.nio.channels.SelectableChannel} -A channel that can be multiplexed - {@link java.nio.channels.DatagramChannel} -A channel for a {@link java.net.DatagramSocket java.net.DatagramSocket} - {@link java.nio.channels.Pipe.SinkChannel} -The write end of a pipe - {@link java.nio.channels.Pipe.SourceChannel} -The read end of a pipe - {@link java.nio.channels.ServerSocketChannel} -A channel for a {@link java.net.ServerSocket java.net.ServerSocket} - {@link java.nio.channels.SocketChannel} -A channel for a {@link java.net.Socket java.net.Socket} - {@link java.nio.channels.Selector} -A multiplexor of selectable channels - {@link java.nio.channels.SelectionKey} -A token representing the registration
of a channel - with a selector- {@link java.nio.channels.Pipe} -Two channels that form a unidirectional pipe Multiplexed, non-blocking I/O, which is much more scalable than -thread-oriented, blocking I/O, is provided by selectors, selectable -channels, and selection keys. - -
A selector is a multiplexor of selectable channels, which in turn are -a special type of channel that can be put into non-blocking mode. To perform -multiplexed I/O operations, one or more selectable channels are first created, -put into non-blocking mode, and {@link -java.nio.channels.SelectableChannel#register registered
* * @return The new pipe */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/charset/Charset.java --- a/jdk/src/share/classes/java/nio/charset/Charset.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/charset/Charset.java Wed Jul 05 16:41:30 2017 +0200 @@ -85,6 +85,9 @@ *} -with a selector. Registering a channel specifies the set of I/O operations -that will be tested for readiness by the selector, and returns a selection key that represents the -registration. - -
Once some channels have been registered with a selector, a selection operation can be performed in -order to discover which channels, if any, have become ready to perform one or -more of the operations in which interest was previously declared. If a channel -is ready then the key returned when it was registered will be added to the -selector's selected-key set. The key set, and the keys within it, can -be examined in order to determine the operations for which each channel is -ready. From each key one can retrieve the corresponding channel in order to -perform whatever I/O operations are required. - -
That a selection key indicates that its channel is ready for some operation -is a hint, but not a guarantee, that such an operation can be performed by a -thread without causing the thread to block. It is imperative that code that -performs multiplexed I/O be written so as to ignore these hints when they prove -to be incorrect. - -
This package defines selectable-channel classes corresponding to the {@link -java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link -java.net.Socket} classes defined in the {@link java.net} package. -Minor changes to these classes have been made in order to support sockets that -are associated with channels. This package also defines a simple class that -implements unidirectional pipes. In all cases, a new selectable channel is -created by invoking the static open method of the corresponding class. -If a channel needs an associated socket then a socket will be created as a side -effect of this operation. - -
The implementation of selectors, selectable channels, and selection keys -can be replaced by "plugging in" an alternative definition or instance of the -{@link java.nio.channels.spi.SelectorProvider} class defined in the {@link -java.nio.channels.spi} package. It is not expected that many developers -will actually make use of this facility; it is provided primarily so that -sophisticated users can take advantage of operating-system-specific -I/O-multiplexing mechanisms when very high performance is required. - -
Much of the bookkeeping and synchronization required to implement the -multiplexed-I/O abstractions is performed by the {@link -java.nio.channels.spi.AbstractInterruptibleChannel}, {@link -java.nio.channels.spi.AbstractSelectableChannel}, {@link -java.nio.channels.spi.AbstractSelectionKey}, and {@link -java.nio.channels.spi.AbstractSelector} classes in the {@link -java.nio.channels.spi} package. When defining a custom selector provider, -only the {@link java.nio.channels.spi.AbstractSelector} and {@link -java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed -directly; custom channel classes should extend the appropriate {@link -java.nio.channels.SelectableChannel} subclasses defined in this package. - -
Unless otherwise noted, passing a null argument to a constructor -or method in any class or interface in this package will cause a {@link -java.lang.NullPointerException NullPointerException} to be thrown. - - -@since 1.4 -@author Mark Reinhold -@author JSR-51 Expert Group - - - diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java --- a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,10 +25,8 @@ package java.nio.channels.spi; -import java.io.FileDescriptor; import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; +import java.net.ProtocolFamily; import java.nio.channels.*; import java.security.AccessController; import java.security.PrivilegedAction; @@ -190,7 +188,25 @@ throws IOException; /** - * Opens a pipe.
+ * Opens a datagram channel. + * + * @param family + * The protocol family + * + * @return A new datagram channel + * + * @throws UnsupportedOperationException + * If the specified protocol family is not supported + * @throws IOException + * If an I/O error occurs + * + * @since 1.7 + */ + public abstract DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException; + + /** + * Opens a pipe.The dash character '-' * ('\u002d', HYPHEN-MINUS), * + * The plus character '+' + * ('\u002b', PLUS SIGN), + * * The period character '.' * ('\u002e', FULL STOP), * @@ -307,6 +310,7 @@ if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; if (c == '-' && i != 0) continue; + if (c == '+' && i != 0) continue; if (c == ':' && i != 0) continue; if (c == '_' && i != 0) continue; if (c == '.' && i != 0) continue; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/util/zip/Inflater.java --- a/jdk/src/share/classes/java/util/zip/Inflater.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/util/zip/Inflater.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,11 +73,13 @@ public class Inflater { private long strm; - private byte[] buf = new byte[0]; + private byte[] buf = defaultBuf; private int off, len; private boolean finished; private boolean needDict; + private static final byte[] defaultBuf = new byte[0]; + static { /* Zip library is loaded from System.initializeSystemClass */ initIDs(); @@ -318,6 +320,7 @@ public synchronized void reset() { ensureOpen(); reset(strm); + buf = defaultBuf; finished = false; needDict = false; off = len = 0; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/java/util/zip/ZipFile.java --- a/jdk/src/share/classes/java/util/zip/ZipFile.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,7 +278,6 @@ int size = inflaters.size(); if (size > 0) { Inflater inf = (Inflater)inflaters.remove(size - 1); - inf.reset(); return inf; } else { return new Inflater(true); @@ -291,6 +290,7 @@ */ private void releaseInflater(Inflater inf) { synchronized (inflaters) { + inf.reset(); inflaters.add(inf); } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/InstanceNotFoundException.java --- a/jdk/src/share/classes/javax/management/InstanceNotFoundException.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/InstanceNotFoundException.java Wed Jul 05 16:41:30 2017 +0200 @@ -51,4 +51,16 @@ public InstanceNotFoundException(String message) { super(message); } + + /** + * Constructor for the frequent case where the message is the ObjectName + * of the missing MBean. + * + * @param name the ObjectName of the missing MBean. + * + * @since 1.7 + */ + public InstanceNotFoundException(ObjectName name) { + this(name.toString()); + } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MBeanPermission.java --- a/jdk/src/share/classes/javax/management/MBeanPermission.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanPermission.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,6 +25,7 @@ package javax.management; +import com.sun.jmx.mbeanserver.Util; import java.io.IOException; import java.io.ObjectInputStream; import java.security.Permission; @@ -42,10 +43,10 @@ * permission that you need. When a sensitive operation is * being checked for permission, an MBeanPermission is constructed * representing the permission you need. The operation is only - * allowed if the permissions you have {@link #implies imply} the + * allowed if the permissions you have {@linkplain #implies imply} the * permission you need. An MBeanPermission contains four items of information:
+ *An MBeanPermission contains five items of information:
* ** @@ -57,6 +58,23 @@ * *
* *The action is returned by {@link #getActions()}.
* + *The MBean Server name.
+ * + *For a permission you need, this is the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} + * containing the MBean for which the MBean + * permission is checked.
+ * + *For a permission you have, this is either the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} in which the MBean + * you have this permission for must be registered, + * or a pattern against which that MBean Server name will be matched.
+ * *
+ * An {@code mbeanServerName} pattern can also be empty or the single + * character {@code "*"}, both of which will match any {@code MBeanServer} name. + *The class name.
* *For a permission you need, this is the class name of an MBean @@ -88,7 +106,7 @@ * or operation you can access, or it is empty or the single character * "
* - **
", both of which grant access to any member.The object name.
+ *The object name.
* *For a permission you need, this is the {@link ObjectName} of the * MBean you are accessing. For operations that do not reference a @@ -103,15 +121,15 @@ *
If you have an MBeanPermission, it allows operations only if all - * four of the items match.
+ * five of the items match.The class name, member, and object name can be written together - * as a single string, which is the name of this permission. + *
The MBean Server name, class name, member, and object name can be written + * together as a single string, which is the name of this permission. * The name of the permission is the string returned by {@link * Permission#getName() getName()}. The format of the string is:
* *- ** *className#member[objectName]
+ *mbeanServerName::className#member[objectName]
*The object name is written using the usual syntax for {@link @@ -119,15 +137,18 @@ *
* - *]
. It is terminated by a]
character * that is the last character in the string.One or more of the
className
,member
, - * orobjectName
may be omitted. If the - *member
is omitted, the#
may be too (but + *One or more of the
* - *mbeanServerName
,className
, + *member
, orobjectName
may be omitted. If the + *mbeanServerName
is omitted, the::
may be too (but + * does not have to be). + * If themember
is omitted, the#
may be too (but * does not have to be). If theobjectName
is omitted, * the[]
may be too (but does not have to be). It is - * not legal to omit all three items, that is to have a name + * not legal to omit all four items, that is to have a name * that is the empty string.One or more of the
className
,member
, + *One or more of the
mbeanServerName
,className
, + *member
, * orobjectName
may be the character "-
", * which is equivalent to a null value. A null value is implied by * any value (including another null value) but does not imply any @@ -247,6 +268,13 @@ private transient ObjectName objectName; /** + * The name of the MBeanServer in which this permission is checked, or + * granted. If null, is implied by any MBean Server name + * but does not imply any non-null MBean Server name. + */ + private transient String mbeanServerName; + + /** * Parseactions
parameter. */ private void parseActions() { @@ -283,6 +311,13 @@ throw new IllegalArgumentException("MBeanPermission name " + "cannot be empty"); + final int sepIndex = name.indexOf("::"); + if (sepIndex < 0) { + setMBeanServerName("*"); + } else { + setMBeanServerName(name.substring(0,sepIndex)); + } + /* The name looks like "class#member[objectname]". We subtract elements from the right as we parse, so after parsing the objectname we have "class#member" and after parsing the @@ -290,11 +325,14 @@ // Parse ObjectName - int openingBracket = name.indexOf("["); + + final int start = (sepIndex<0)?0:sepIndex+2; + int openingBracket = name.indexOf("[",start); if (openingBracket == -1) { // If "[on]" missing then ObjectName("*:*") // objectName = ObjectName.WILDCARD; + name = name.substring(start); } else { if (!name.endsWith("]")) { throw new IllegalArgumentException("MBeanPermission: " + @@ -305,11 +343,11 @@ } else { // Create ObjectName // + String on = name.substring(openingBracket + 1, + name.length() - 1); try { // If "[]" then ObjectName("*:*") // - String on = name.substring(openingBracket + 1, - name.length() - 1); if (on.equals("")) objectName = ObjectName.WILDCARD; else if (on.equals("-")) @@ -320,11 +358,11 @@ throw new IllegalArgumentException("MBeanPermission: " + "The target name does " + "not specify a valid " + - "ObjectName"); + "ObjectName", e); } } - name = name.substring(0, openingBracket); + name = name.substring(start, openingBracket); } // Parse member @@ -348,8 +386,9 @@ * Assign fields based on className, member, and objectName * parameters. */ - private void initName(String className, String member, - ObjectName objectName) { + private void initName(String mbeanServerName, String className, + String member, ObjectName objectName) { + setMBeanServerName(mbeanServerName); setClassName(className); setMember(member); this.objectName = objectName; @@ -381,19 +420,30 @@ this.member = member; } + private void setMBeanServerName(String mbeanServerName) { + if (mbeanServerName == null || mbeanServerName.equals("-")) { + this.mbeanServerName = null; + } else if (mbeanServerName.equals("")) { + this.mbeanServerName = "*"; + } else { + this.mbeanServerName = mbeanServerName; + } + } + + /** *Create a new MBeanPermission object with the specified target name * and actions.
* *The target name is of the form - * "
+ * "className#member[objectName]
" where each part is - * optional. It must not be empty or null.mbeanServerName::className#member[objectName]
" where + * each part is optional. It must not be empty or null.The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.
* - * @param name the triplet "className#member[objectName]". + * @param name the quadruplet "mbeanServerName::className#member[objectName]". * @param actions the action string. * * @exception IllegalArgumentException if thename
or @@ -418,6 +468,12 @@ * optional. This will be the result of {@link #getName()} on the * resultant MBeanPermission.This corresponds to a permission granted for all + * MBean servers present in the JVM and is equivalent to + * {@link #MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission("*",className,member,objectName,actions)}. + *
+ * *The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.
@@ -439,17 +495,67 @@ String member, ObjectName objectName, String actions) { + this("*",className,member,objectName,actions); + } - super(makeName(className, member, objectName)); - initName(className, member, objectName); + /** + *Create a new MBeanPermission object with the specified target name + * (MBean Server name, class name, member, object name) and actions.
+ * + *The MBean Server name, class name, member and object name + * parameters define a target name of the form + * "
+ * + *mbeanServerName::className#member[objectName]
" where each + * part is optional. This will be the result of {@link #getName()} on the + * resultant MBeanPermission. + * If thembeanServerName
is empty or exactly {@code "*"}, then + * "{@code mbeanServerName::}" is omitted in that result. + *The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name + * that is implied by any MBeanServer name but does not imply any other + * MBeanServer name. + * @param className the class name to which this permission applies. + * May be null or"-"
, which represents a class name + * that is implied by any class name but does not imply any other + * class name. + * @param member the member to which this permission applies. May + * be null or"-"
, which represents a member that is + * implied by any member but does not imply any other member. + * @param objectName the object name to which this permission + * applies. May be null, which represents an object name that is + * implied by any object name but does not imply any other object + * name. + * @param actions the action string. + * + * @since 1.7 + */ + public MBeanPermission(String mbeanServerName, + String className, + String member, + ObjectName objectName, + String actions) { + + super(makeName(mbeanServerName,className, member, objectName)); + initName(mbeanServerName,className, member, objectName); this.actions = actions; parseActions(); } - private static String makeName(String className, String member, + private static String makeName(String mbeanServerName, String className, + String member, ObjectName objectName) { final StringBuilder name = new StringBuilder(); + if (mbeanServerName == null) + mbeanServerName = "-"; + if (!mbeanServerName.equals("") && !mbeanServerName.equals("*")) + name.append(mbeanServerName).append("::"); if (className == null) className = "-"; name.append(className); @@ -991,6 +1097,9 @@ * *p is an instance of MBeanPermission; and * + *p has a null mbeanServerName or p's mbeanServerName + * matches this object's mbeanServerName; and + * *p has a null className or p's className * matches this object's className; and * @@ -1004,6 +1113,13 @@ * * * + *If this object's mbeanServerName is a pattern, then p's + * mbeanServerName is matched against that pattern. An empty + * mbeanServerName is equivalent to "{@code *}". A null + * mbeanServerName is equivalent to "{@code -}".
+ *If this object's mbeanServerName is "
+ * **
" or is + * empty, p's mbeanServerName always matches it.If this object's className is "
@@ -1050,6 +1166,12 @@ // Target name // + // The 'mbeanServerName' check is true iff: + // 1) the mbeanServerName in 'this' permission is omitted or "*", or + // 2) the mbeanServerName in 'that' permission is omitted or "*", or + // 3) the mbeanServerName in 'this' permission does pattern + // matching with the mbeanServerName in 'that' permission. + // // The 'className' check is true iff: // 1) the className in 'this' permission is omitted or "*", or // 2) the className in 'that' permission is omitted or "*", or @@ -1076,6 +1198,17 @@ expect that "that" contains a wildcard, since it is a needed permission. So we assume that.classNameExactMatch. */ + if (that.mbeanServerName == null) { + // bottom is implied + } else if (this.mbeanServerName == null) { + // bottom implies nothing but itself + return false; + } else if (that.mbeanServerName.equals(this.mbeanServerName)) { + // exact match + } else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) { + return false; // no match + } + if (that.classNamePrefix == null) { // bottom is implied } else if (this.classNamePrefix == null) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MBeanServer.java --- a/jdk/src/share/classes/javax/management/MBeanServer.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServer.java Wed Jul 05 16:41:30 2017 +0200 @@ -42,7 +42,7 @@ * **
", p's * className always matches it. If it is "a.*
", p's * className matches it if it begins with "a.
".User code does not usually implement this interface. Instead, * an object that implements this interface is obtained with one of - * the methods in the {@link MBeanServerFactory} class.
+ * the methods in the {@link javax.management.MBeanServerFactory} class.Every MBean which is added to the MBean server becomes * manageable: its attributes and operations become remotely @@ -62,8 +62,12 @@ *
* *JMImplementation:type=MBeanServerDelegate
.An object obtained from the {@link - * MBeanServerFactory#createMBeanServer(String) createMBeanServer} or - * {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer} + * MBeanServerFactory#createMBeanServer(String) createMBeanServer}, {@link + * MBeanServerFactory#createNamedMBeanServer(String,String) createNamedMBeanServer}, + * {@link + * MBeanServerFactory#newMBeanServer(String) newMBeanServer}, or + * {@link + * MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer} * methods of the {@link MBeanServerFactory} class applies security * checks to its methods, as follows.
* @@ -73,9 +77,26 @@ * *Assuming that there is a security manager, or that the * implementation chooses to make checks anyway, the checks are made - * as detailed below. In what follows,
+ *className
is the + * as detailed below. + * In what follows, and unless otherwise specified: + *
className
is the * string returned by {@link MBeanInfo#getClassName()} for the target - * MBean.{@code mbeanServerName} is the + * {@linkplain MBeanServerFactory#getMBeanServerName name of the + * MBean Server} in which the target MBean is registered. This is the + * value returned by {@link MBeanServerFactory#getMBeanServerName + * MBeanServerFactory.getMBeanServerName(MBeanServer)}, and + * is usually the {@code mbeanServerName} parameter that was supplied + * to the {@link + * MBeanServerFactory#createNamedMBeanServer(String,String) + * createNamedMBeanServer} or {@link + * MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer} + * methods of the {@link MBeanServerFactory} when the MBeanServer was created, + * or {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if + * no name was supplied. + * * *If a security check fails, the method throws {@link * SecurityException}.
@@ -89,78 +110,86 @@ * *For the {@link #invoke invoke} method, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, operationName, name, "invoke")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, operationName, name, "invoke")}. + *For the {@link #getAttribute getAttribute} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, attribute, name, "getAttribute")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, attribute, name, + * "getAttribute")}.For the {@link #getAttributes getAttributes} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getAttribute")}. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName,className, null, name, "getAttribute")}. * Additionally, for each attribute a in the {@link * AttributeList}, if the caller's permissions do not imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, a, name, "getAttribute")}, the + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, a, name, + * "getAttribute")}, the * MBean server will behave as if that attribute had not been in the * supplied list.
* *For the {@link #setAttribute setAttribute} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, attrName, name, "setAttribute")}, where + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, attrName, name, + * "setAttribute")}, where *
* *attrName
is {@link Attribute#getName() * attribute.getName()}.For the {@link #setAttributes setAttributes} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "setAttribute")}. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "setAttribute")}. * Additionally, for each attribute a in the {@link * AttributeList}, if the caller's permissions do not imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, a, name, "setAttribute")}, the + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, a, name, + * "setAttribute")}, the * MBean server will behave as if that attribute had not been in the * supplied list.
* *For the
* *addNotificationListener
methods, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, * "addNotificationListener")}.For the
* *removeNotificationListener
methods, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, * "removeNotificationListener")}.For the {@link #getMBeanInfo getMBeanInfo} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getMBeanInfo")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "getMBeanInfo")}. + *For the {@link #getObjectInstance getObjectInstance} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getObjectInstance")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, + * "getObjectInstance")}.For the {@link #isInstanceOf isInstanceOf} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "isInstanceOf")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "isInstanceOf")}. + *For the {@link #queryMBeans queryMBeans} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(null, null, name, "queryMBeans")}. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, "queryMBeans")}. * Additionally, for each MBean that matches
* *name
, * if the caller's permissions do not imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "queryMBeans")}, the + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "queryMBeans")}, the * MBean server will behave as if that MBean did not exist.Certain query elements perform operations on the MBean server. @@ -179,10 +208,10 @@ * *
For the {@link #getDomains getDomains} method, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(null, null, name, "getDomains")}. Additionally, - * for each domain d in the returned array, if the caller's - * permissions do not imply {@link + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, "getDomains")}. + * Additionally, for each domain d in the returned array, if the + * caller's permissions do not imply {@link * MBeanPermission#MBeanPermission(String,String,ObjectName,String) * MBeanPermission(null, null, new ObjectName("d:x=x"), * "getDomains")}, the domain is eliminated from the array. Here, @@ -191,21 +220,22 @@ * *
For the {@link #getClassLoader getClassLoader} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, loaderName, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, loaderName, * "getClassLoader")}.
* *For the {@link #getClassLoaderFor getClassLoaderFor} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, mbeanName, + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, mbeanName, * "getClassLoaderFor")}.
* *For the {@link #getClassLoaderRepository * getClassLoaderRepository} method, the caller's permissions must * imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(null, null, null, "getClassLoaderRepository")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, + * "getClassLoaderRepository")}.For the deprecated
deserialize
methods, the * required permissions are the same as for the methods that replace @@ -213,15 +243,15 @@ * *For the
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, null, "instantiate")}, + * where {@code className} is the name of the class which is to + * be instantiated.instantiate
methods, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, null, "instantiate")}.For the {@link #registerMBean registerMBean} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "registerMBean")}. Here - *
className
is the string returned by {@link - * MBeanInfo#getClassName()} for an object of this class. + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "registerMBean")}. * *If the
MBeanPermission
check succeeds, the MBean's * class is validated by checking that its {@link @@ -241,8 +271,9 @@ * *For the {@link #unregisterMBean unregisterMBean} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "unregisterMBean")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "unregisterMBean")}. + *postRegister
* (MBeanRegistration
interface) method of the MBean throws a - *RuntimeException
, thecreateMBean
method will + *
RuntimeException
, thecreateMBean
method will * throw aRuntimeMBeanException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. * @exception RuntimeErrorException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws an - *Error
, thecreateMBean
method will + *
Error
, thecreateMBean
method will * throw aRuntimeErrorException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeErrorException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. @@ -150,19 +150,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws a - *RuntimeException
, thecreateMBean
method will + *
RuntimeException
, thecreateMBean
method will * throw aRuntimeMBeanException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. * @exception RuntimeErrorException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws an - *Error
, thecreateMBean
method will + *
Error
, thecreateMBean
method will * throw aRuntimeErrorException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeErrorException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. @@ -225,19 +225,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws a - *RuntimeException
, thecreateMBean
method will + *
RuntimeException
, thecreateMBean
method will * throw aRuntimeMBeanException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. * @exception RuntimeErrorException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws an - *Error
, thecreateMBean
method will + *
Error
, thecreateMBean
method will * throw aRuntimeErrorException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeErrorException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. @@ -297,19 +297,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If thepostRegister
* (MBeanRegistration
interface) method of the MBean throws a - *RuntimeException
, thecreateMBean
method will + *
RuntimeException
, thecreateMBean
method will * throw aRuntimeMBeanException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. * @exception RuntimeErrorException If thepostRegister
method * (MBeanRegistration
interface) method of the MBean throws an - *Error
, thecreateMBean
method will + *
Error
, thecreateMBean
method will * throw aRuntimeErrorException
, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though thecreateMBean
method + * registered even though the
createMBean
method * threw an exception. Note thatRuntimeErrorException
can * also be thrown bypreRegister
, in which case the MBean * will not be registered. @@ -351,19 +351,19 @@ * has thrown an exception. * @exception RuntimeMBeanException If thepostDeregister
* (MBeanRegistration
interface) method of the MBean throws a - *RuntimeException
, theunregisterMBean
method + *
RuntimeException
, theunregisterMBean
method * will throw aRuntimeMBeanException
, although the MBean * unregistration succeeded. In such a case, the MBean will be actually - * unregistered even though theunregisterMBean
method + * unregistered even though the
unregisterMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreDeregister
, in which case the MBean * will remain registered. * @exception RuntimeErrorException If thepostDeregister
* (MBeanRegistration
interface) method of the MBean throws an - *Error
, theunregisterMBean
method will + *
Error
, theunregisterMBean
method will * throw aRuntimeErrorException
, although the MBean * unregistration succeeded. In such a case, the MBean will be actually - * unregistered even though theunregisterMBean
method + * unregistered even though the
unregisterMBean
method * threw an exception. Note thatRuntimeMBeanException
can * also be thrown bypreDeregister
, in which case the MBean * will remain registered. diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MBeanServerDelegate.java --- a/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,7 +25,9 @@ package javax.management; +import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.ServiceName; +import com.sun.jmx.mbeanserver.Util; /** * Represents the MBean server from the management point of view. @@ -39,6 +41,7 @@ /** The MBean server agent identification.*/ private String mbeanServerId ; + private String mbeanServerName; /** The NotificationBroadcasterSupport object that sends the notifications */ @@ -68,6 +71,7 @@ public MBeanServerDelegate () { stamp = getStamp(); broadcaster = new NotificationBroadcasterSupport() ; + mbeanServerName=null; } @@ -82,14 +86,103 @@ try { localHost = java.net.InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException e) { + JmxProperties.MISC_LOGGER.finest("Can't get local host name, " + + "using \"localhost\" instead. Cause is: "+e); localHost = "localhost"; } - mbeanServerId = localHost + "_" + stamp; + mbeanServerId = + Util.insertMBeanServerName(localHost + "_" + stamp, + mbeanServerName); } return mbeanServerId; } /** + * The name of the MBeanServer. + * @return The name of the MBeanServer, or {@value + * javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if no + * name was specified. + * + * @since 1.7 + * @see #setMBeanServerName + */ + public synchronized String getMBeanServerName() { + if (Util.isMBeanServerNameUndefined(mbeanServerName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return mbeanServerName; + } + + /** + * Sets the name of the MBeanServer. The name will be embedded into the + * {@link #getMBeanServerId MBeanServerId} using the following format:
+ * {@code mbeanServerId:;mbeanServerName= } + * The characters {@code ':'} (colon), {@code ';'} (semicolon ), + * {@code '*'} (star) and {@code '?'} (question mark) are not legal in an + * MBean Server name.
+ *For instance, if the {@code mbeanServerName} provided is + * {@code "com.mycompany.myapp.server1"}, and the original + * {@code MBeanServerId} was {@code "myhost_1213353064145"}, + * then {@code mbeanServerName} will be + * embedded in the {@code MBeanServerId} - and the new value of the + * {@code MBeanServerId} will be: + *
+ *+ * "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1" + *+ *Note: The {@code mbeanServerName} is usually set by the + * {@code MBeanServerFactory}. It is set only once, before the + * MBean Server is returned by the factory. Once the MBean Server name is + * set, it is not possible to change it. + *
+ * @param mbeanServerName The MBeanServer name. + * @throws IllegalArgumentException if the MBeanServerName is already set + * to a different value, or if the provided name contains + * illegal characters, or if the provided name is {@code ""} + * (the empty string) or "-" (dash). + * @throws UnsupportedOperationException if this object is of a legacy + * subclass of MBeanServerDelegate which overrides {@link + * #getMBeanServerId()} + * in a way that doesn't support setting an MBeanServer name. + * @see MBeanServerFactory#getMBeanServerName + * @since 1.7 + */ + public synchronized void setMBeanServerName(String mbeanServerName) { + // Sets the name on the delegate. For complex backward + // compatibility reasons it is not possible to give the + // name to the MBeanServerDelegate constructor. + // + // The method setMBeanServerName() will call getMBeanServerId() + // to check that the name is accurately set in the MBeanServerId. + // If not (which could happen if a custom MBeanServerDelegate + // implementation overrides getMBeanServerId() and was not updated + // with respect to JMX 2.0 spec), this method will throw an + // IllegalStateException... + + // will fail if mbeanServerName is illegal + final String name = Util.checkServerName(mbeanServerName); + + // can only set mbeanServerDelegate once. + if (this.mbeanServerName != null && !this.mbeanServerName.equals(name)) + throw new IllegalArgumentException( + "MBeanServerName already set to a different value"); + + this.mbeanServerName = name; + + // will fail if mbeanServerId already has a different mbeanServerName + mbeanServerId = + Util.insertMBeanServerName(getMBeanServerId(),name); + + // check that we don't have a subclass which overrides + // getMBeanServerId() without setting mbeanServerName + if (!name.equals( + Util.extractMBeanServerName(getMBeanServerId()))) + throw new UnsupportedOperationException( + "Can't set MBeanServerName in MBeanServerId - " + + "unsupported by "+this.getClass().getName()+"?"); + // OK: at this point we know that we have correctly set mbeanServerName. + } + + /** * Returns the full name of the JMX specification implemented * by this product. * @@ -210,15 +303,8 @@ * * @since 1.6 */ - public static final ObjectName DELEGATE_NAME; - static { - try { - DELEGATE_NAME = - new ObjectName("JMImplementation:type=MBeanServerDelegate"); - } catch (MalformedObjectNameException e) { - throw new Error("Can't initialize delegate name", e); - } - } + public static final ObjectName DELEGATE_NAME = + Util.newObjectName("JMImplementation:type=MBeanServerDelegate"); /* Return a timestamp that is monotonically increasing even if System.currentTimeMillis() isn't (for example, if you call this diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MBeanServerFactory.java --- a/jdk/src/share/classes/javax/management/MBeanServerFactory.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServerFactory.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,16 +25,19 @@ package javax.management; +import com.sun.jmx.defaults.JmxProperties; import static com.sun.jmx.defaults.JmxProperties.JMX_INITIAL_BUILDER; import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; -import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor; import com.sun.jmx.mbeanserver.GetPropertyAction; +import com.sun.jmx.mbeanserver.Util; import java.security.AccessController; import java.security.Permission; import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import javax.management.loading.ClassLoaderRepository; + /** *Provides MBean server references. There are no instances of * this class.
@@ -80,10 +83,53 @@ * returned by the default MBeanServerBuilder implementation, for the purpose * of e.g. adding an additional security layer. * + *Since version 2.0 of the JMX API, when creating + * an MBeanServer, + * it is possible to specify an {@linkplain #getMBeanServerName + * MBean Server name}. + * To create an MBean Server with a name, the MBeanServerFactory provides two + * new methods:
+ *+ *
- {@link #createNamedMBeanServer + * createNamedMBeanServer(mbeanServerName, defaultDomain)}: creates a named + * MBeanServer and keeps an internal reference to the created object. The + * MBeanServer can be later retrieved using {@link #findMBeanServer + * findMBeanServer(mbeanServerId)} or + * {@link #findMBeanServerByName findMBeanServerByName(mbeanServerName)}, and + * can be released through {@link + * #releaseMBeanServer releaseMBeanServer(mbeanServer)}.
+ *- {@link #newNamedMBeanServer + * newNamedMBeanServer(mbeanServerName, defaultDomain)}: + * creates a named MBeanServer without keeping any internal reference to the + * named server.
+ *The name of the MBeanServer is stored in the + * {@linkplain MBeanServerDelegate MBean Server delegate MBean} + * and is embedded in its {@link MBeanServerDelegate#getMBeanServerId + * MBeanServerId} attribute.
+ *The name of the MBeanServer is particularly useful when + * MBean permissions are checked: + * it makes it + * possible to distinguish between an MBean named "X" in MBeanServer named + * "M1", and another MBean of the same name "X" in another MBeanServer named + * "M2".
+ *When naming MBean servers it is recommended to use a name that starts + * with a Java package name. It is also recommended that the default domain and + * the MBeanServer name be the same.
+ * * @since 1.5 */ public class MBeanServerFactory { + /** + * The MBean Server name that will be + * checked by a permission you need + * when checking access to an MBean registered in an MBeanServer for + * which no MBeanServer name was specified. + * + * @since 1.7 + */ + public final static String DEFAULT_MBEANSERVER_NAME = "default"; + /* * There are no instances of this class so don't generate the * default public constructor. @@ -222,13 +268,78 @@ *javax.management.builder.initial
exists and can be * instantiated but is not assignment compatible with {@link * MBeanServerBuilder}. + * + * @see #createNamedMBeanServer */ public static MBeanServer createMBeanServer(String domain) { - checkPermission("createMBeanServer"); + return createMBeanServer(null,domain); + } - final MBeanServer mBeanServer = newMBeanServer(domain); - addMBeanServer(mBeanServer); - return mBeanServer; + /** + *Return a new object implementing the {@link MBeanServer} + * interface with the specified + * MBean Server name + * and default domain name. The given MBean server name + * is used in security checks, and + * can also be used to {@linkplain #findMBeanServerByName(java.lang.String) + * find an MBeanServer by name}. The given + * domain name is used as the domain part in the ObjectName of + * MBeans when the domain is specified by the user is null.
+ * + *The MBeanServer reference is internally kept. This will + * allow
+ * + * @param mbeanServerName the name for the created + * MBeanServer. This is the name that will be included in the + * {@linkplain MBeanPermission permission you need} when checking + * MBean Permissions for accessing + * an MBean registered in the returned MBeanServer. The characters + * {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star) + * and {@code '?'} are not legal. + * It is recommended that the {@code mbeanServerName} + * be unique in the context of a JVM, and in the form of a java package + * identifier. If {@code mbeanServerName} is {@code null} then the created + * MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used. + * Calling {@code createNamedMBeanServer(null,domain)} is equivalent + * to calling {@link #createMBeanServer(String) createMBeanServer(domain)}. + * + * @param domain the default domain name for the created + * MBeanServer. This is the value that will be returned by {@link + * MBeanServer#getDefaultDomain}. If a non null mbeanServerName is given, + * it is recommended to pass the same value as default domain. + * + * @return the newly created MBeanServer. + * + * @exception SecurityException if there is a SecurityManager and + * the caller's permissions do not include or implyfindMBeanServer
to return a reference to + * this MBeanServer object.{@link + * MBeanServerPermission}("createMBeanServer")
. + * + * @exception JMRuntimeException if the property + *javax.management.builder.initial
exists but the + * class it names cannot be instantiated through a public + * no-argument constructor; or if the instantiated builder returns + * null from its {@link MBeanServerBuilder#newMBeanServerDelegate + * newMBeanServerDelegate} or {@link + * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. + * + * @exception ClassCastException if the property + *javax.management.builder.initial
exists and can be + * instantiated but is not assignment compatible with {@link + * MBeanServerBuilder}. + * + * @exception IllegalArgumentException if the specified + * {@code mbeanServerName} is empty, or is {@code "-"}, or contains a + * character which is not legal. + * + * @exception UnsupportedOperationException if the specified + * {@code mbeanServerName} cannot be set. + * + * @since 1.7 + */ + public static MBeanServer createNamedMBeanServer(String mbeanServerName, + String domain) { + return createMBeanServer(mbeanServerName, domain); } /** @@ -307,6 +418,88 @@ * MBeanServerBuilder}. */ public static MBeanServer newMBeanServer(String domain) { + return newMBeanServer(null,domain); + } + + /** + *Return a new object implementing the MBeanServer interface + * with the specified MBean server name + * and default domain name, without keeping an + * internal reference to this new object. The given MBean server name + * is used in security checks. + * The given domain name + * is used as the domain part in the ObjectName of MBeans when the + * domain is specified by the user is null.
+ * + *No reference is kept.
+ * + * @param mbeanServerName the name for the created + * MBeanServer. This is the name that will be included in the + * {@linkplain MBeanPermission permission you need} when checking + * MBean Permissions for accessing + * an MBean registered in the returned MBeanServer. The characters + * {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star) + * and {@code '?'} are not legal. + * It is recommended that the mbeanServerName + * be unique in the context of a JVM, and in the form of a java package + * identifier. If {@code mbeanServerName} is {@code null} then the created + * MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used. + * Calling {@code newNamedMBeanServer(null,domain)} is equivalent + * to calling {@link #newMBeanServer(String) newMBeanServer(domain)}. + * + * @param domain the default domain name for the created + * MBeanServer. This is the value that will be returned by {@link + * MBeanServer#getDefaultDomain}. + * + * @return the newly created MBeanServer. + * + * @exception SecurityException if there is a SecurityManager and the + * caller's permissions do not include or implyfindMBeanServer
and + *findMBeanServerByName
will not + * be able to return a reference to this MBeanServer object, but + * the garbage collector will be able to remove the MBeanServer + * object when it is no longer referenced.{@link + * MBeanServerPermission}("newMBeanServer")
. + * + * @exception JMRuntimeException if the property + *javax.management.builder.initial
exists but the + * class it names cannot be instantiated through a public + * no-argument constructor; or if the instantiated builder returns + * null from its {@link MBeanServerBuilder#newMBeanServerDelegate + * newMBeanServerDelegate} or {@link + * MBeanServerBuilder#newMBeanServer newMBeanServer} methods. + * + * @exception ClassCastException if the property + *javax.management.builder.initial
exists and can be + * instantiated but is not assignment compatible with {@link + * MBeanServerBuilder}. + * + * @exception IllegalArgumentException if the specified + * {@code mbeanServerName} is empty, or is {@code "-"}, + * or contains a character which is not legal. + * + * @exception UnsupportedOperationException if the specified + * {@code mbeanServerName} cannot be set. + * + * @since 1.7 + */ + public static MBeanServer newNamedMBeanServer(String mbeanServerName, + String domain) { + return newMBeanServer(mbeanServerName, domain); + } + + private static MBeanServer createMBeanServer(String mbeanServerName, + String domain) { + checkPermission("createMBeanServer"); + + final MBeanServer mBeanServer = + newMBeanServer(mbeanServerName,domain); + addMBeanServer(mBeanServer); + return mBeanServer; + } + + private static MBeanServer newMBeanServer(String mbeanServerName, + String domain) { checkPermission("newMBeanServer"); // Get the builder. Creates a new one if necessary. @@ -316,20 +509,50 @@ synchronized(mbsBuilder) { final MBeanServerDelegate delegate = - mbsBuilder.newMBeanServerDelegate(); + mbsBuilder.newMBeanServerDelegate(); if (delegate == null) { final String msg = - "MBeanServerBuilder.newMBeanServerDelegate() " + - "returned null"; + "MBeanServerBuilder.newMBeanServerDelegate() " + + "returned null"; throw new JMRuntimeException(msg); } + + // Sets the name on the delegate. For complex backward + // compatibility reasons it is not possible to give the + // name to the MBeanServerDelegate constructor. + // + // The method setMBeanServerName() will call getMBeanServerId() + // to check that the name is accurately set in the MBeanServerId. + // If not (which could happen if a custom MBeanServerDelegate + // implementation overrides getMBeanServerId() and was not updated + // with respect to JMX 2.0 spec, this method will throw an + // IllegalStateException... + // + if (!Util.isMBeanServerNameUndefined(mbeanServerName)) { + delegate.setMBeanServerName(mbeanServerName); + } + final MBeanServer mbeanServer = - mbsBuilder.newMBeanServer(domain,null,delegate); + mbsBuilder.newMBeanServer(domain,null,delegate); if (mbeanServer == null) { final String msg = - "MBeanServerBuilder.newMBeanServer() returned null"; + "MBeanServerBuilder.newMBeanServer() returned null"; throw new JMRuntimeException(msg); } + + // double check that the MBeanServer name is correctly set. + // "*" might mean that the caller doesn't have the permission + // to see the MBeanServer name. + // + final String mbsName = Util.getMBeanServerSecurityName(mbeanServer); + if (!mbsName.equals(Util.checkServerName(mbeanServerName)) + && !mbsName.equals("*")) { + throw new UnsupportedOperationException( + "can't create MBeanServer with name \""+ + mbeanServerName+"\" using "+ + builder.getClass().getName()); + } + return mbeanServer; } } @@ -363,7 +586,7 @@ ArrayListresult = new ArrayList (); for (MBeanServer mbs : mBeanServerList) { - String name = mBeanServerName(mbs); + String name = mBeanServerId(mbs); if (agentId.equals(name)) result.add(mbs); } @@ -371,8 +594,99 @@ } /** + * Returns a list of registered MBeanServer objects with the given name. A + * registered MBeanServer object is one that was created by one of + * the
+ *createMBeanServer
orcreateNamedMBeanServer
+ * methods and not subsequently released withreleaseMBeanServer
.See the section about MBean Server names + * above.
+ * + * @param mbeanServerName The name of the MBeanServer to + * retrieve. If this parameter is null, all registered MBeanServers + * in this JVM are returned. + * Otherwise, only those MBeanServers that have a name + * matchingmbeanServerName
are returned: this + * parameter can be a pattern, where {@code '*'} matches any + * sequence of characters and {@code '?'} matches any character.
+ * The name of an MBeanServer, if specified, is embedded in the + *MBeanServerId
attribute of its delegate MBean: + * this method will parse theMBeanServerId
to get the + * MBeanServer name. If this parameter is equal to {@code "*"} then + * all registered MBeanServers in this JVM are returned, whether they have + * a name or not: {@code findMBeanServerByName(null)}, + * {@code findMBeanServerByName("*")} and {@code findMBeanServer(null)}, + * are equivalent. It is also possible to get all MBeanServers for which + * no name was specified by callingfindMBeanServerByName({@value + * #DEFAULT_MBEANSERVER_NAME})
. + * + * @return A list of MBeanServer objects. + * + * @exception SecurityException if there is a SecurityManager and the + * caller's permissions do not include or imply{@link + * MBeanServerPermission}("findMBeanServer")
. + * + * @see #getMBeanServerName(MBeanServer) + * @since 1.7 + */ + public synchronized static + ListfindMBeanServerByName(String mbeanServerName) { + + checkPermission("findMBeanServer"); + + if (mbeanServerName==null || "*".equals(mbeanServerName)) + return new ArrayList (mBeanServerList); + + // noname=true iff we are looking for MBeanServers for which no name + // were specified. + ArrayList result = new ArrayList (); + for (MBeanServer mbs : mBeanServerList) { + final String name = Util.getMBeanServerSecurityName(mbs); + if (Util.wildmatch(name, mbeanServerName)) result.add(mbs); + } + return result; + } + + /** + * Returns the name of the MBeanServer embedded in the MBeanServerId of + * the given {@code server}. If the given MBeanServerId doesn't contain + * any name, {@value #DEFAULT_MBEANSERVER_NAME} is returned. + * The MBeanServerId is expected to be of the form: + * {@code *[;mbeanServerName= [;*]]} + *
where {@code *} denotes any sequence of characters, and {@code [ ]} + * indicate optional parts. + * + *For instance, if an MBeanServer is created using {@link + * #createNamedMBeanServer(java.lang.String, java.lang.String) + * server = + * MBeanServerFactory.createNamedMBeanServer("com.mycompany.myapp.server1", + * null)} then {@code MBeanServerFactory.getMBeanServerName(server)} + * will return {@code "com.mycompany.myapp.server1"} and + *
+ *server.getAttribute({@link + * javax.management.MBeanServerDelegate#DELEGATE_NAME + * MBeanServerDelegate.DELEGATE_NAME}, "MBeanServerId")
will return + * something like + * {@code "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"}. + *See the section about MBean Server names + * above.
+ * @param server A named (or unnamed) MBeanServer. + * @return the name of the MBeanServer if found, or + * {@value #DEFAULT_MBEANSERVER_NAME} if no name is + * present in its MBeanServerId, or "*" if its + * MBeanServerId couldn't be obtained. Returning "*" means that + * only {@link MBeanPermission}s that allow all MBean Server names + * will apply to this MBean Server. + * @see MBeanServerDelegate + * @since 1.7 + */ + public static String getMBeanServerName(MBeanServer server) { + return Util.getMBeanServerSecurityName(server); + } + + /** * Return the ClassLoaderRepository used by the given MBeanServer. - * This method is equivalent to {@link MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}. + * This method is equivalent to {@link + * MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}. * @param server The MBeanServer under examination. Since JMX 1.2, * ifserver
isnull
, the result is a * {@link NullPointerException}. This behavior differs from what @@ -387,21 +701,23 @@ * **/ public static ClassLoaderRepository getClassLoaderRepository( - MBeanServer server) { + MBeanServer server) { return server.getClassLoaderRepository(); } - private static String mBeanServerName(MBeanServer mbs) { + private static String mBeanServerId(MBeanServer mbs) { try { return (String) mbs.getAttribute(MBeanServerDelegate.DELEGATE_NAME, - "MBeanServerId"); + "MBeanServerId"); } catch (JMException e) { + JmxProperties.MISC_LOGGER.finest( + "Ignoring exception while getting MBeanServerId: "+e); return null; } } private static void checkPermission(String action) - throws SecurityException { + throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { Permission perm = new MBeanServerPermission(action); @@ -425,16 +741,16 @@ } private static final ArrayListmBeanServerList = - new ArrayList (); + new ArrayList (); /** * Load the builder class through the context class loader. * @param builderClassName The name of the builder class. **/ private static Class loadBuilderClass(String builderClassName) - throws ClassNotFoundException { + throws ClassNotFoundException { final ClassLoader loader = - Thread.currentThread().getContextClassLoader(); + Thread.currentThread().getContextClassLoader(); if (loader != null) { // Try with context class loader @@ -453,14 +769,14 @@ **/ private static MBeanServerBuilder newBuilder(Class builderClass) { try { - final Object builder = builderClass.newInstance(); - return (MBeanServerBuilder)builder; + final Object abuilder = builderClass.newInstance(); + return (MBeanServerBuilder)abuilder; } catch (RuntimeException x) { throw x; } catch (Exception x) { final String msg = - "Failed to instantiate a MBeanServerBuilder from " + - builderClass + ": " + x; + "Failed to instantiate a MBeanServerBuilder from " + + builderClass + ": " + x; throw new JMRuntimeException(msg, x); } } @@ -472,7 +788,7 @@ private static synchronized void checkMBeanServerBuilder() { try { GetPropertyAction act = - new GetPropertyAction(JMX_INITIAL_BUILDER); + new GetPropertyAction(JMX_INITIAL_BUILDER); String builderClassName = AccessController.doPrivileged(act); try { @@ -493,8 +809,8 @@ builder = newBuilder(newBuilderClass); } catch (ClassNotFoundException x) { final String msg = - "Failed to load MBeanServerBuilder class " + - builderClassName + ": " + x; + "Failed to load MBeanServerBuilder class " + + builderClassName + ": " + x; throw new JMRuntimeException(msg, x); } } catch (RuntimeException x) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/MXBean.java --- a/jdk/src/share/classes/javax/management/MXBean.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MXBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -469,8 +469,8 @@ J, then J cannot be the type of a method parameter or return value in an MXBean interface. - If there is a way to convert opendata(J) back to - J then we say that J is +
If there is a way to convert + opendata(J) back to J then we say that J is reconstructible. All method parameters in an MXBean interface must be reconstructible, because when the MXBean framework is invoking a method it will need to convert those diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/ObjectName.java --- a/jdk/src/share/classes/javax/management/ObjectName.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/ObjectName.java Wed Jul 05 16:41:30 2017 +0200 @@ -27,6 +27,8 @@ import com.sun.jmx.mbeanserver.GetPropertyAction; import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.namespace.serial.JMXNamespaceContext; + import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; @@ -223,6 +225,17 @@ public class ObjectName implements Comparable
+ * + *, QueryExp { /** + * The sequence of characters used to separate name spaces in a name space + * path. + * + * @see javax.management.namespace + * @since 1.7 + **/ + public static final String NAMESPACE_SEPARATOR = "//"; + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + /** * A structure recording property structure and * proposing minimal services */ @@ -251,16 +264,17 @@ /** * Returns a key string for receiver key */ - String getKeyString(String name) { - return name.substring(_key_index, _key_index + _key_length); + String getKeyString(String name, int offset) { + final int start = _key_index+offset; + return name.substring(start, start + _key_length); } /** * Returns a value string for receiver key */ - String getValueString(String name) { - int in_begin = _key_index + _key_length + 1; - int out_end = in_begin + _value_length; + String getValueString(String name, int offset) { + final int in_begin = _key_index + offset + _key_length + 1; + final int out_end = in_begin + _value_length; return name.substring(in_begin, out_end); } } @@ -393,6 +407,45 @@ */ private transient boolean _property_value_pattern = false; + private ObjectName(String newDomain, ObjectName aname) + throws MalformedObjectNameException{ + copyToOtherDomain(newDomain,aname); + } + + private void copyToOtherDomain(String domain, ObjectName aname) + throws MalformedObjectNameException, NullPointerException { + + // The domain cannot be null + if (domain == null) + throw new NullPointerException("domain cannot be null"); + + // The key property list cannot be null + if (aname == null) + throw new MalformedObjectNameException( + "key property list cannot be empty"); + + // checks domain validity. A side effect of this method is also to + // set the _domain_pattern flag. + if (!isDomain(domain)) + throw new MalformedObjectNameException("Invalid domain: " + domain); + + // init canonicalname + _domain_length = domain.length(); + + _canonicalName = (domain + + aname._canonicalName.substring(aname._domain_length)).intern(); + _kp_array = aname._kp_array; + _ca_array = aname._ca_array; + _propertyList = aname._propertyList; + _property_list_pattern = aname._property_list_pattern; + _property_value_pattern = aname._property_value_pattern; + // TODO remove this hack + // if (toString().endsWith("//javax.management.service:type1=event_client_delegeate_mbean,type2=default")) { + // Thread.currentThread().dumpStack(); + // throw new Error("************************ Gotcha!"); + //} + } + // Instance private fields <======================================= // Private fields <======================================== @@ -435,10 +488,10 @@ } // initialize parsing of the string - char[] name_chars = name.toCharArray(); - int len = name_chars.length; - char[] canonical_chars = new char[len]; // canonical form will be same - // length at most + final char[] name_chars = name.toCharArray(); + final int len = name_chars.length; + final char[] canonical_chars = new char[len]; // canonical form will + // be same length at most int cname_index = 0; int index = 0; char c, c1; @@ -637,10 +690,12 @@ // we got the key and value part, prepare a property for this if (!value_pattern) { - prop = new Property(key_index, key_length, value_length); + prop = new Property(key_index-_domain_length, + key_length, value_length); } else { _property_value_pattern = true; - prop = new PatternProperty(key_index, key_length, value_length); + prop = new PatternProperty(key_index-_domain_length, + key_length, value_length); } key_name = name.substring(key_index, key_index + key_length); @@ -725,12 +780,12 @@ boolean value_pattern = checkValue(value); sb.append(value); if (!value_pattern) { - prop = new Property(key_index, + prop = new Property(key_index-_domain_length, key.length(), value.length()); } else { _property_value_pattern = true; - prop = new PatternProperty(key_index, + prop = new PatternProperty(key_index-_domain_length, key.length(), value.length()); } @@ -810,9 +865,9 @@ prop = _ca_array[i]; // length of prop including '=' char prop_len = prop._key_length + prop._value_length + 1; - System.arraycopy(specified_chars, prop._key_index, + System.arraycopy(specified_chars, prop._key_index+_domain_length, canonical_chars, prop_index, prop_len); - prop.setKeyIndex(prop_index); + prop.setKeyIndex(prop_index-_domain_length); prop_index += prop_len; if (i != last_index) { canonical_chars[prop_index] = ','; @@ -1031,33 +1086,6 @@ k[endKey] + "'"); } - /* - * Tests whether string s is matched by pattern p. - * Supports "?", "*" each of which may be escaped with "\"; - * Not yet supported: internationalization; "\" inside brackets. - * Wildcard matching routine by Karl Heuer. Public Domain.
- */ - private static boolean wildmatch(char[] s, char[] p, int si, int pi) { - char c; - final int slen = s.length; - final int plen = p.length; - - while (pi < plen) { // While still string - c = p[pi++]; - if (c == '?') { - if (++si > slen) return false; - } else if (c == '*') { // Wildcard - if (pi >= plen) return true; - do { - if (wildmatch(s,p,si,pi)) return true; - } while (++si < slen); - return false; - } else { - if (si >= slen || c != s[si++]) return false; - } - } - return (si == slen); - } // Category : Internal utilities <============================== @@ -1177,15 +1205,43 @@ cn = (String)in.readObject(); } + final JMXNamespaceContext ctxt = + JMXNamespaceContext.getDeserializationContext(); try { - construct(cn); + construct(changeContext(ctxt,cn)); } catch (NullPointerException e) { throw new InvalidObjectException(e.toString()); + } catch (IllegalArgumentException e) { + throw new InvalidObjectException(e.toString()); } catch (MalformedObjectNameException e) { throw new InvalidObjectException(e.toString()); } } + private String changeContext(JMXNamespaceContext context, String nameString) { + final String old = context.prefixToRemove; + final String nw = context.prefixToAdd; + final int ol = old.length(); + if (nameString.startsWith(NAMESPACE_SEPARATOR)) return nameString; + if (ol>0) { + if (!nameString.startsWith(old) || + !nameString.startsWith(NAMESPACE_SEPARATOR,ol)) + throw new IllegalArgumentException( + "Serialized ObjectName does not start with " + old + + ": " + nameString); + nameString = nameString.substring(ol+NAMESPACE_SEPARATOR_LENGTH); + } + if (!nw.equals("")) { + nameString = nw + NAMESPACE_SEPARATOR + nameString; + } + // TODO remove this hack + // if (nameString.endsWith("//javax.management.service:type1=event_client_delegeate_mbean,type2=default")) { + // System.err.println("old="+old+", nw="+nw); + // Thread.currentThread().dumpStack(); + // throw new Error("************************ Gotcha!"); + // } + return nameString; + } /** * Serializes an {@link ObjectName} to an {@link ObjectOutputStream}. @@ -1248,15 +1304,22 @@ private void writeObject(ObjectOutputStream out) throws IOException { + final JMXNamespaceContext ctxt = + JMXNamespaceContext.getSerializationContext(); + if (compat) { // Serializes this instance in the old serial form // Read CR 6441274 before making any changes to this code ObjectOutputStream.PutField fields = out.putFields(); - fields.put("domain", _canonicalName.substring(0, _domain_length)); + final String domain = + changeContext(ctxt,_canonicalName.substring(0, _domain_length)); + final String cn = + changeContext(ctxt,_canonicalName); + fields.put("domain", domain); fields.put("propertyList", getKeyPropertyList()); fields.put("propertyListString", getKeyPropertyListString()); - fields.put("canonicalName", _canonicalName); + fields.put("canonicalName", cn); fields.put("pattern", (_domain_pattern || _property_list_pattern)); fields.put("propertyPattern", _property_list_pattern); out.writeFields(); @@ -1266,7 +1329,8 @@ // Serializes this instance in the new serial form // out.defaultWriteObject(); - out.writeObject(getSerializedNameString()); + + out.writeObject(changeContext(ctxt,getSerializedNameString())); } } @@ -1397,6 +1461,27 @@ } /** + * Returns an {@code ObjectName} that is the same as this one but + * with the specified domain. + * This method preserves the original key order in the new instance. + * If the provided name has a key property pattern, it will also be + * preserved in the returned instance. + * + * @param newDomain The new domain for the returned instance; + * must not be null. + * @return A new {@code ObjectName} that is the same as {@code this} + * except the domain is {@code newDomain}. + * @throws NullPointerException if {@code newDomain} is null. + * @throws MalformedObjectNameException if the new domain is syntactically + * illegal. + * @since 1.7 + **/ + public final ObjectName withDomain(String newDomain) + throws NullPointerException, MalformedObjectNameException { + return new ObjectName(newDomain, this); + } + + /** * Construct an object name from the given string. * * @param name A string representation of the object name. @@ -1550,7 +1635,7 @@ throw new NullPointerException("key property can't be null"); for (int i = 0; i < _ca_array.length; i++) { Property prop = _ca_array[i]; - String key = prop.getKeyString(_canonicalName); + String key = prop.getKeyString(_canonicalName,_domain_length); if (key.equals(property)) return (prop instanceof PatternProperty); } @@ -1630,8 +1715,10 @@ Property prop; for (int i = len - 1; i >= 0; i--) { prop = _ca_array[i]; - _propertyList.put(prop.getKeyString(_canonicalName), - prop.getValueString(_canonicalName)); + _propertyList.put(prop.getKeyString(_canonicalName, + _domain_length), + prop.getValueString(_canonicalName, + _domain_length)); } } } @@ -1716,7 +1803,8 @@ } } - return new String(dest_chars); + final String name = new String(dest_chars); + return name; } /** @@ -1734,7 +1822,7 @@ if (_kp_array.length == 0) return offset; final char[] dest_chars = data; - final char[] value = _canonicalName.toCharArray(); + final char[] value = canonicalChars; int index = offset; final int len = _kp_array.length; @@ -1742,7 +1830,7 @@ for (int i = 0; i < len; i++) { final Property prop = _kp_array[i]; final int prop_len = prop._key_length + prop._value_length + 1; - System.arraycopy(value, prop._key_index, dest_chars, index, + System.arraycopy(value, prop._key_index+_domain_length, dest_chars, index, prop_len); index += prop_len; if (i < last ) dest_chars[index++] = ','; @@ -1816,7 +1904,7 @@ // (because usage of intern()) ObjectName on = (ObjectName) object; String on_string = on._canonicalName; - if (_canonicalName == on_string) return true; + if (_canonicalName == on_string) return true; // ES: OK // Because we are sharing canonical form between object names, // we have finished the comparison at this stage ==> unequal @@ -1997,9 +2085,9 @@ private final boolean matchDomains(ObjectName name) { if (_domain_pattern) { // wildmatch domains - final char[] dom_pattern = getDomain().toCharArray(); - final char[] dom_string = name.getDomain().toCharArray(); - return wildmatch(dom_string,dom_pattern,0,0); + // This ObjectName is the pattern + // The other ObjectName is the string. + return Util.wildpathmatch(name.getDomain(),getDomain()); } return getDomain().equals(name.getDomain()); } @@ -2025,7 +2113,7 @@ // index in receiver // final Property p = props[i]; - final String k = p.getKeyString(cn); + final String k = p.getKeyString(cn,_domain_length); final String v = nameProps.get(k); // Did we find a value for this key ? // @@ -2034,15 +2122,13 @@ // if (_property_value_pattern && (p instanceof PatternProperty)) { // wildmatch key property values - final char[] val_pattern = - p.getValueString(cn).toCharArray(); - final char[] val_string = v.toCharArray(); - if (wildmatch(val_string,val_pattern,0,0)) + // p is the property pattern, v is the string + if (Util.wildmatch(v,p.getValueString(cn,_domain_length))) continue; else return false; } - if (v.equals(p.getValueString(cn))) continue; + if (v.equals(p.getValueString(cn,_domain_length))) continue; return false; } return true; @@ -2109,6 +2195,10 @@ * @since 1.6 */ public int compareTo(ObjectName name) { + // Quick optimization: + // + if (name == this) return 0; + // (1) Compare domains // int domainValue = this.getDomain().compareTo(name.getDomain()); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/event/EventClient.java --- a/jdk/src/share/classes/javax/management/event/EventClient.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/event/EventClient.java Wed Jul 05 16:41:30 2017 +0200 @@ -29,6 +29,7 @@ import com.sun.jmx.event.LeaseRenewer; import com.sun.jmx.event.ReceiverBuffer; import com.sun.jmx.event.RepeatedSingletonJob; +import com.sun.jmx.namespace.JMXNamespaceUtils; import com.sun.jmx.mbeanserver.PerThreadGroupPool; import com.sun.jmx.remote.util.ClassLogger; @@ -1063,6 +1064,24 @@ return clientId; } + /** + * Returns a JMX Connector that will use an {@link EventClient} + * to subscribe for notifications. If the server doesn't have + * an {@link EventClientDelegateMBean}, then the connector will + * use the legacy notification mechanism instead. + * + * @param wrapped The underlying JMX Connector wrapped by the returned + * connector. + * + * @return A JMX Connector that will uses an {@link EventClient}, if + * available. + * + * @see EventClient#getEventClientConnection(MBeanServerConnection) + */ + public static JMXConnector withEventClient(final JMXConnector wrapped) { + return JMXNamespaceUtils.withEventClient(wrapped); + } + private static final PerThreadGroupPool
+ *leaseRenewerThreadPool = PerThreadGroupPool.make(); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/event/EventClientDelegate.java --- a/jdk/src/share/classes/javax/management/event/EventClientDelegate.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/event/EventClientDelegate.java Wed Jul 05 16:41:30 2017 +0200 @@ -721,7 +721,10 @@ SecurityManager sm = System.getSecurityManager(); if (sm != null) { try { - ObjectInstance oi = (ObjectInstance) AccessController.doPrivileged( + final String serverName = getMBeanServerName(); + + ObjectInstance oi = (ObjectInstance) + AccessController.doPrivileged( new PrivilegedExceptionAction + * Note: A JMXNamespace MBean cannot be registered + * simultaneously in two different + * MBean servers, or indeed in the same MBean Server with two + * different names. It is however possible to give the same MBeanServer + * instance to two different JMXNamespace MBeans, and thus create a graph + * rather than a tree. + *
+ * + *To view the content of a namespace, you will usually use an + * instance of {@link JMXNamespaceView}. For instance, given the + * namespace {@code "foo"} created above, you would do: + *
+ *+ * final JMXNamespaceView view = new JMXNamespaceView(server); + * System.out.println("List of namespaces: "+Arrays.toString({@link JMXNamespaceView#list() view.list()})); + * + * final JMXNamespaceView foo = {@link JMXNamespaceView#down view.down("foo")}; + * System.out.println({@link JMXNamespaceView#where() foo.where()}+" contains: " + + * {@link JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null)); + *+ * + *JMX Namespace Permission Checks
+ * + *A special {@link JMXNamespacePermission} is defined to check access + * to MBean within namespaces.
+ *When a JMXNamespace MBean is registered in an + * MBean server created through the default {@link + * javax.management.MBeanServerBuilder}, and if a {@link + * SecurityManager SecurityManager} is + * {@linkplain System#getSecurityManager() present}, the MBeanServer will + * check a {@link JMXNamespacePermission} before invoking + * any method on the {@linkplain #getSourceServer source MBeanServer} of the + * JMXNamespace. + * {@linkplain JMXNamespacePermission JMX Namespace Permissions} are similar to + * {@linkplain javax.management.MBeanPermission MBean Permissions}, except + * that you usually cannot specify an MBean class name. You can however + * specify object name patterns - which will allow you for example to only grant + * permissions for MBeans having a specific {@code type=
+ *} key + * in their object name. + * + * Another difference is that {@link JMXNamespacePermission + * JMXNamespacePermission} also specifies from which namespace and which + * MBean server the permission is granted. + *
+ *In the rest of this document, the following terms are used:
+ *+ *
+ * + *{@code server name} is the + * name of the + * MBeanServer in which the permission is granted. + * The name of an {@code MBeanServer} can be obtained by calling {@link + * javax.management.MBeanServerFactory#getMBeanServerName + * MBeanServerFactory.getMBeanServerName(mbeanServer)} + *
+ *{@code namespace} is the name of the namespace + * in the named MBean server for which the + * permission is granted. It doesn't contain any + * {@link JMXNamespaces#NAMESPACE_SEPARATOR namespace separator}. + *
+ *{@code mbean} is the name + * of the MBean in that {@code namespace}. This is the name of the MBean + * in the namespace's {@link JMXNamespace#getSourceServer() source mbean server}. + * It might contain no, one, or several {@link + * JMXNamespaces#NAMESPACE_SEPARATOR namespace separators}. + *
+ *For instance let's assume that some piece of code calls:
+ *+ * final MBeanServer mbeanServer = ...; + * final ObjectName name = new ObjectName("a//b//c//D:k=v"); + * mbeanServer.getAttribute(name,"Foo"); + *+ *+ * Assuming that there is a security manager, or that the + * implementation chooses to make checks anyway, the checks that will + * be made in that case are: + *
+ *+ *
+ *- + *
+ *JMXNamespacePermission(mbeanServerName, "Foo", "a//b//c//D:k=v", + * "getAttribute")
+ * (where {@code mbeanServerName=MBeanServerFactory.getMBeanServerName(mbeanServer)}, + *namespace="a"
, and {@code mbean="b//c//D:k=v"}) + *- and in addition if namespace {@code "a"} is local, + *
+ *JMXNamespacePermission(aSourceServerName,"Foo","b//c//D:k=v", + * "getAttribute")}
+ * (where + * {@code aSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(a))}, + *namespace="b"
, and {@code mbean="c//D:k=v"}), + *- and in addition if namespace {@code "b"} is also local, + *
+ *JMXNamespacePermission(bSourceServerName,"Foo","c//D:k=v", + * "getAttribute")}
+ * (where + * {@code bSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(b))}, + *namespace="c"
, and {@code mbean="D:k=v"}), + *- and in addition if the source mbean server of namespace + * {@code "c"} is a also a local MBeanServer in this JVM, + * {@code MBeanPermission(cSourceServerName,
+ *,"Foo","D:k=v","getAttrinute")}, + * (where + * {@code cSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(c))}). + * For any of these MBean servers, if no name was supplied when + * creating that MBeanServer the {@link JMXNamespacePermission} is + * created with an {@code mbeanServerName} equal to + * {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}. + *
+ *If the namespace {@code a} is in fact a remote {@code MBeanServer}, + * for instance because namespace {@code a} is implemented by a {@link + * JMXRemoteNamespace} pointing to a distant MBeanServer located in + * another JMX agent, then checks 2, + * 3, and 4 will not + * be performed in the local JVM. They might or might not be performed in + * the remote agent, depending on how access control and permission + * checking are configured in the remote agent, and how authentication + * is configured in the connector used by the {@link + * JMXRemoteNamespace}. + *
+ *In all cases, {@linkplain JMXNamespacePermission JMX Namespace Permissions} + * are checked as follows:
+ *First, if there is no security manager ({@link + * System#getSecurityManager()} is null), then an implementation of + * of MBeanServer that supports JMX namespaces is free not to make any + * checks.
+ * + *Assuming that there is a security manager, or that the + * implementation chooses to make checks anyway, the checks are made + * as detailed below.
+ * + *If a security check fails, the method throws {@link + * SecurityException}.
+ * + *+ * + *
+ *For the {@link MBeanServer#invoke invoke} method, the caller's + * permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <operation name>, <namespace>//<mbean>, "invoke")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *
+ * + *For the {@link MBeanServer#getAttribute getAttribute} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <attribute>, <namespace>//<mbean>, "getAttribute")}. + *
+ * + *For the {@link MBeanServer#getAttributes getAttributes} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <null>, <namespace>//<mbean>, "getAttribute")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + * Additionally, for each attribute att in the {@link + * javax.management.AttributeList}, if the caller's permissions do not + * imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, att, + * <namespace>//<mbean>, "getAttribute")}, the + * MBean server will behave as if that attribute had not been in the + * supplied list.
+ * + *For the {@link MBeanServer#setAttribute setAttribute} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <attrName>, <namespace>//<mbean>, "setAttribute")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace, and + *
+ * + *attrName
is {@link javax.management.Attribute#getName() + * attribute.getName()}.For the {@link MBeanServer#setAttributes setAttributes} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, "setAttribute")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + * Additionally, for each attribute att in the {@link + * javax.management.AttributeList}, if the caller's permissions do not + * imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, att, <namespace>//<mbean>, "setAttribute")}, + * the MBean server will behave as if that attribute had not been in the + * supplied list.
+ * + *For the
+ * + *addNotificationListener
methods, + * the caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "addNotificationListener")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *For the
+ * + *removeNotificationListener
methods, + * the caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "removeNotificationListener")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *For the {@link MBeanServer#getMBeanInfo getMBeanInfo} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "getMBeanInfo")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *
+ * + *For the {@link MBeanServer#getObjectInstance getObjectInstance} method, + * the caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "getObjectInstance")}, + * where mbean server name/a> is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *
+ * + *For the {@link MBeanServer#isInstanceOf isInstanceOf} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "isInstanceOf")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *
+ * + *For the {@link MBeanServer#queryMBeans queryMBeans} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, null, + * "queryMBeans")}. + * Additionally, for each MBean {@code mbean} that matches {@code pattern}, + * if the caller's permissions do not imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "queryMBeans")}, the + * MBean server will behave as if that MBean did not exist.
+ * + *Certain query elements perform operations on the MBean server. + * However these operations are usually performed by the MBeanServer at the + * bottom of the namespace path, and therefore, do not involve any + * {@link JMXNamespacePermission} permission check. They might involve + * {@link javax.management.MBeanPermission} checks depending on how security + * in the JVM in which the bottom MBeanServer resides is implemented. + * See {@link javax.management.MBeanServer} for more details. + *
+ * + *For the {@link MBeanServer#queryNames queryNames} method, the checks + * are the same as for
+ * + *queryMBeans
except that + *"queryNames"
is used instead of + *"queryMBeans"
in theJMXNamespacePermission
+ * objects. Note that a"queryMBeans"
permission implies + * the corresponding"queryNames"
permission.For the {@link MBeanServer#getClassLoader getClassLoader} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<loaderName>, + * "getClassLoader")}, + * where mbean server name/a> is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * loaderName is the name of the ClassLoader MBean + * which is accessed, in that namespace. + *
+ * + *For the {@link MBeanServer#getClassLoaderFor getClassLoaderFor} method, + * the caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "getClassLoaderFor")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which the action + * is performed, in that namespace. + *
+ * + *For the {@link MBeanServer#registerMBean registerMBean} method, the + * caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>, + * "registerMBean")}. Here + *
class name
is the string returned by {@code + * obj.getClass().getName()} where {@code obj} is the mbean reference, + * is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean which is being + * registered, relative to that namespace. + * + *For the
createMBean
methods, the caller's + * permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>, + * "instantiate")} and + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>, + * "registerMBean")}, where + *class name
is the string passed as first argument to the {@code + * createMBean} method, + * mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean which is being + * created, relative to that namespace. + * + *For the {@link MBeanServer#unregisterMBean unregisterMBean} method, + * the caller's permissions must imply {@link + * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String) + * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, + * "unregisterMBean")}, + * where mbean server name is the name of the + * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of + * namespace is registered, and + * mbean is the name of the MBean on which is + * being unregistered, relative to that namespace. + *
+ *It must be noted that if all namespaces are local, and all + * local namespaces are implemented by regular MBean servers, that is, there + * are no {@linkplain MBeanServerSupport Virtual Namespaces}, then + * simple {@linkplain javax.management.MBeanPermission MBean Permission} + * checks might be enough to secure an application. + * In that case, it is possible to specify the following {@link + * JMXNamespacePermission} permission in the policy file, which implies all + * other JMX namespace permissions: + *
+ *+ * permission javax.management.namespace.JMXNamespacePermission "*::*[]", "*"; + *+ * + * @since 1.7 + */ +public class JMXNamespace + implements JMXNamespaceMBean, MBeanRegistration { + + /** + * The standard value of the {@code type} + * property key that must be used to construct valid {@link + * JMXNamespaceMBean} ObjectNames.
+ * This is {@value #TYPE}. + **/ + public static final String TYPE = "JMXNamespace"; + + /** + * The {@link ObjectName#getKeyPropertyListString keyPropertyListString} + * that must be used to construct valid {@link JMXNamespaceMBean} + * ObjectNames.
+ * This is + *{@value #TYPE_ASSIGNMENT}
. + **/ + public static final String TYPE_ASSIGNMENT = "type="+TYPE; + + private volatile MBeanServer mbeanServer; // the mbean server in which + // this MBean is registered. + private volatile ObjectName objectName; // the ObjectName of this MBean. + private final MBeanServer sourceServer; // the MBeanServer within = the + // name space (or the MBean server + // that contains it). + private final String uuid; + + /** + * Creates a new JMXNamespace implemented by means of an MBean Server. + * A namespace is equivalent to an MBeanServer within an MBean Server. + * The {@code sourceServer} provided to this constructor is the MBean Server + * within. + * @param sourceServer the MBean server that implemented by this namespace. + * @see #getSourceServer + */ + public JMXNamespace(MBeanServer sourceServer) { + this.sourceServer = sourceServer; + this.uuid = UUID.randomUUID().toString(); + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a handle to the MBean server in which it is + * registered. It also check the validity of its own ObjectName. + *+ * This method is called by the MBean server. + * Application classes should never call this method directly. + *
+ * If this method is overridden, the overriding method should call + * {@code super.preRegister(server,name)}. + * @see MBeanRegistration#preRegister MBeanRegistration + * @see JMXNamespaces#getNamespaceObjectName getNamespaceObjectName + * @param name The object name of the MBean. name must be a + * syntactically valid JMXNamespace name, as returned by + * {@link JMXNamespaces#getNamespaceObjectName(java.lang.String) + * getNamespaceObjectName(namespace)}. + * @return The name under which the MBean is to be registered. + * @throws IllegalArgumentException if the name supplied is not valid. + * @throws Exception can be thrown by subclasses. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (objectName != null && ! objectName.equals(name)) + throw new IllegalStateException( + "Already registered under another name: " + objectName); + objectName = validateHandlerName(name); + mbeanServer = server; + return name; + } + + /** + * Validate the ObjectName supplied to preRegister. + * This method is introduced to allow standard subclasses to use + * an alternate naming scheme. For instance - if we want to + * reuse JMXNamespace in order to implement sessions... + * It is however only available for subclasses in this package. + **/ + ObjectName validateHandlerName(ObjectName supliedName) { + if (supliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(supliedName.getDomain()); + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dirName); + if (!supliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + supliedName); + return supliedName; + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a handle to the MBean server in which it is + * registered. + *
+ * This method is called by the MBean server. Application classes should + * not call this method directly. Subclasses are free to override this + * method with their own specific behavior - but the overriding method + * shoud still call {@code super.postRegister(registrationDone)}. + * @see MBeanRegistration#postRegister MBeanRegistration + */ + public void postRegister(Boolean registrationDone) { + // nothing to do + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a handle to the MBean server in which it is + * registered. + *
+ * This method is called by the MBean server. Application classes should + * not call this method directly. Subclasses are free to override this + * method with their own specific behavior - but the overriding method + * shoud still call {@code super.preDeregister()}. + * @see MBeanRegistration#preDeregister MBeanRegistration + */ + public void preDeregister() throws Exception { + // nothing to do + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * It allows the {@code JMXNamespace} MBean to perform any operations + * needed after having been unregistered in the MBean server. + *
+ * This method is called by the MBean server. Application classes should + * not call this method directly. If a subclass overrides this + * method, the overriding method shoud call {@code super.postDeregister()}. + * @see MBeanRegistration#postDeregister MBeanRegistration + */ + public void postDeregister() { + mbeanServer = null; + objectName = null; + } + + + /** + * Returns the MBeanServer in which this MBean is registered, + * or null. Chiefly of interest for subclasses. + * @return the MBeanServer supplied to {@link #preRegister}. + **/ + public final MBeanServer getMBeanServer() { + return mbeanServer; + } + + /** + * Returns the MBeanServer that contains or emulates the source + * namespace. When a JMXNamespace MBean is registered in an + * MBean server created through the default {@link + * javax.management.MBeanServerBuilder}, the MBeanServer will + * check {@link JMXNamespacePermission} before invoking + * any method on the source MBeanServer of the JMXNamespace. + * See JMX Namespace Permission Checks + * above. + * @return an MBeanServer view of the source namespace + **/ + public MBeanServer getSourceServer() { + return sourceServer; + } + + /** + * Returns the ObjectName with which this MBean was registered, + * or null. Chiefly of interest for subclasses. + * @return the ObjectName supplied to {@link #preRegister}. + **/ + public final ObjectName getObjectName() { + return objectName; + } + + /** + * HandlerName used in traces. + **/ + String getHandlerName() { + final ObjectName name = getObjectName(); + if (name != null) return name.toString(); + return this.toString(); + } + + /** + * In this class, this method returns {@link #getSourceServer + * getSourceServer()}.{@link javax.management.MBeanServer#getMBeanCount + * getMBeanCount()}. + *
This default behaviour may be redefined in subclasses. + * @throws java.io.IOException can be thrown by subclasses. + */ + public Integer getMBeanCount() throws IOException { + return getSourceServer().getMBeanCount(); + } + + /** + * In this class, this method returns {@link #getSourceServer + * getSourceServer()}.{@link javax.management.MBeanServer#getDomains + * getDomains()}. + *
This default behaviour may be redefined in subclasses. + * @throws java.io.IOException can be thrown by subclasses. + */ + public String[] getDomains() throws IOException { + return getSourceServer().getDomains(); + } + + /** + * In this class, this method returns {@link #getSourceServer + * getSourceServer()}.{@link javax.management.MBeanServer#getDefaultDomain + * getDefaultDomain()}. + *
This default behaviour may be redefined in subclasses. + * @throws java.io.IOException can be thrown by subclasses. + */ + public String getDefaultDomain() throws IOException { + return getSourceServer().getDefaultDomain(); + } + + public final String getUUID() { + return uuid; + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import java.io.IOException; +import java.util.UUID; + +/** + * A {@link JMXNamespace} is an MBean that handles a name space in the + * MBeanServer hierarchical name space. + * @see JMXNamespace + * @since 1.7 + */ +public interface JMXNamespaceMBean { + + // Note: since getDomains(), getDefaultDomain(), and getMBeanCount() + // don't take any ObjectName parameters, the only efficient way + // to get these data is to call the corresponding method on the + // JMXNamespaceMBean that handles the name space. + // + // We need these methods to implement 'cd' (JMXNamespaces.narrowToNamespace) + // correctly. + // + + /** + * Returns the list of domains currently implemented in the name space + * handled by this {@link JMXNamespace}. + * @throws IOException if the domain list cannot be obtained due to + * I/O problems (communication failures etc...). + * @return the list of domains currently implemented in the name space + * handled by this {@link JMXNamespace}. + * @see javax.management.MBeanServerConnection#getDomains + * MBeanServerConnection.getDomains + **/ + public String[] getDomains() throws IOException; + + /** + * Returns the default domain for the name space handled by + * this {@link JMXNamespace}. + * @throws IOException if the default domain cannot be obtained due to + * I/O problems (communication failures etc...). + * @return the default domain for the name space handled by + * this {@link JMXNamespace}. + * @see javax.management.MBeanServerConnection#getDefaultDomain + * MBeanServerConnection.getDefaultDomain + **/ + public String getDefaultDomain() throws IOException; + + /** + * Returns the number of MBeans registered in the name space handled by + * this {@link JMXNamespace}. + * + * @return the number of MBeans registered in the name space handled by + * this {@link JMXNamespace}. + * + * @throws IOException if the MBean count cannot be obtained due to + * I/O problems (communication failures etc...). + * @see javax.management.MBeanServerConnection#getMBeanCount + * MBeanServerConnection.getMBeanCount + */ + public Integer getMBeanCount() throws IOException; + + /** + * Returns a {@link java.util.UUID UUID string} which uniquely identifies + * this {@linkplain JMXNamespace} MBean. + * This information can be used to detect loops in the JMX name space graph. + * @return A unique ID identifying this MBean. + * @throws IOException if the MBean UUID cannot be obtained due to + * I/O problems (communication failures etc...). + */ + public String getUUID() throws IOException; + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,1474 @@ +/* + * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import javax.management.*; +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.security.Permission; + +/** + *A permission controlling access to MBeans located in namespaces. + * If a security manager has been set using {@link + * System#setSecurityManager}, most operations on an MBean mounted in a + * namespace require that the caller's permissions imply a + * JMXNamespacePermission appropriate for the operation. + * This is described in detail in the + * documentation for the + * JMXNamespace + * class.
+ * + *As with other {@link Permission} objects, + * a JMXNamespacePermission can represent either a permission that + * you have or a permission that you need. + * When a sensitive operation is being checked for permission, + * a JMXNamespacePermission is constructed + * representing the permission you need. The operation is only + * allowed if the permissions you have {@linkplain #implies imply} the + * permission you need.
+ * + *A JMXNamespacePermission contains four items of information:
+ * + *+ * + *
+ * + *The action.
+ *For a permission you need, + * this is one of the actions in the list below. For a permission you have, this is + * a comma-separated list of those actions, or
+ * + **
, + * representing all actions.The action is returned by {@link #getActions()}.
+ * + *The MBean Server name.
+ * + *For a permission you need, this is the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} + * from which the MBean is accessed.
+ * + *For a permission you have, this is either the {@linkplain + * javax.management.MBeanServerFactory#getMBeanServerName + * name of the MBeanServer} from which the MBean + * for which you have this permission is accessed, + * or a pattern against which that MBean Server name will be matched.
+ * + *
+ * An {@code mbeanServername} pattern can also be empty, or the single + * character {@code "*"}, both of which match any {@code MBeanServer} name. + * The string {@code "-"} doesn't match any MBeanServer name. + *Example:
+ *+ * // grant permission to invoke the operation "stop" on any MBean + * // whose name matches "a//**//*:type=JMXConnectorServer" when + * // accessed from any MBeanServer whose name matches myapp.*" + * permission javax.management.namespace.JMXNamespacePermission "myapp.*::stop[a//**//*:type=JMXConnectorServer]", "invoke"; + *+ * + *The member.
+ * + *For a permission you need, this is the name of the attribute or + * operation you are accessing. For operations that do not reference + * an attribute or operation, the member is null.
+ * + *For a permission you have, this is either the name of an attribute + * or operation you can access, or it is empty or the single character + * "
+ * + **
", both of which grant access to any member.There is a special case for actions {@code registerMBean} and + * {@code instantiate}, where for a permission you need, {@code member} + * indicates the name of the class for which you are trying + * to create, instantiate, or register an MBean instance. For a + * permission you have, it is a pattern that will be matched against + * the full class name of the MBean being created, instantiated, or + * registered. + *
+ * + * + *The object name.
+ * + *For a permission you need, this is the {@link ObjectName} of the + * MBean you are accessing. It is of the form {@code
+ * + *// } + * where {@code } is the name of the name space for which the + * permission is checked, and {@code } is the name of the MBean + * within that namespace. + *
+ * For operations that do not reference a + * single MBean, the object name is null. It is never an object + * name pattern. + *For a permission you have, this is the {@link ObjectName} of the + * MBean or MBeans you can access. It is of the form + * {@code
+ * + * + *// } + * where {@code } is the name of the name space for which the + * permission is checked, and + * {@code } is the name of the MBean + * within that namespace. Both {@code } and {@code } + * can be patterns. The object name + * may also be empty, which grants access to all MBeans whatever their + * name and namespace. + * When included in a namespace path the special path element + * **
matches any number of sub namespaces + * recursively, but only if used as a complete namespace path element, + * as in**//b//c//D:k=v
ora//**//c//D:k=v
+ * - see below. + *If you have a JMXNamespacePermission, it allows operations only + * if all four of the items match.
+ * + *The MBeanServer name, + * member, and object name + * can be written together + * as a single string, which is the name of this permission. + * The name of the permission is the string returned by {@link + * java.security.Permission#getName() getName()}. + * The format of the string is:
+ * + *+ * {@code+ * + *:: [ // ]} + * + * The {@code
+ *} is optional. If omitted, {@code "*"} is + * assumed, and these three permission names + * are thus equivalent: + * + * {@code *::+ *[ // ]}
+ * {@code ::[ // ]}
+ * {@code[ // ]}
+ *+ * The {@code
+ *// } string can be in the form + * of a traditional ObjectName + * pattern - meaning that ?
will match any single + * character, and*
will match any sequence of characters, + * except {@value + * javax.management.namespace.JMXNamespaces#NAMESPACE_SEPARATOR} + * In addition, when included in a namespace path the special + * path element**
matches any number of sub namespaces + * recursively. + * A {@code// } string of the form + * **//*:*
thus means that the permission is + * granted for all MBeans in all namespaces, recursively (see + * below for more details. + *Namespace permission checking may be tricky to configure, depending + * on whether the namespaces crossed to reach the MBean are local or + * remote.
+ *
+ * For instance, leta//b//D:k=v
be an MBean exposing an + * attributeFoo
. + * If namespacea
is a plain JMXNamespace pointing to + * a local MBeanServer in the same JVM, then the permissions you need + * to get the attributeFoo
will be: + *+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v + * // from MBeanServer named 'srv1' + * // This permission will be checked by the MBeanServer that contains 'a'. + * srv1::Foo[a//b//D:k=v] + * + * // Since a is local, you also need the following additional permission, + * // which will be checked by the MBeanServer 'srv2' that contains 'b': + * // + * // granting permission to access attribute 'Foo' of MBean b//D:k=v from + * // 'srv2' + * srv2::Foo[b//D:k=v] + *+ *On the other hand, if namespace
+ *a
is a JMXRemoteNamespace + * pointing to an MBeanServer in a remote JVM, then the only permission you + * need to get the attributeFoo
will be: + *+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v + * // from 'srv1' + * srv1::Foo[a//b//D:k=v] + *+ *The namespace
+ * + *b
resides in the remote JVM, and + * therefore the permissions concerning access to MBeans from + * namespace 'b' will only be checked in the remote JVM, if that JVM is + * configured to do so. + *The {@code
+ *} is written using the usual syntax for {@link + * ObjectName}. It may contain any legal characters, including + * ]
. It is terminated by a]
character + * that is the last character in the string. + *Below are some examples of permission names:
+ *+ * // allows access to Foo in 'a//b//*:*' from any MBeanServer in the JVM. + * Foo[a//b//*:*] + * + * // allows access to Foo in all subnamespaces of 'a//b', but only for + * // MBeanServers whose name matches 'myapp.*' + * myapp.*::Foo[a//b//**//*:*] + * + * // allows access to Foo from all namespaces in the MBeanServer named + * // 'myapp.srv1' - but not recursively. + * myapp.srv1::Foo[*//*:*] + *+ *For instance, the first two permissions listed above + * will let through {@code getAttribute("a//b//D:k=v","Foo");} in + * all MBeanServers, but will block access to + * {@code getAttribute("a//b//c//D:k=v","Foo");} in MBeanServers whose + * name do not start with {@code "myapp."}. + *
+ * + *+ * // allows access to Foo in all namespaces, recursively. + * // + * *::Foo[**//*:*] + * + * // This permission name is the equivalent to the permission names above: + * // Foo[**//*:*] and Foo[] are equivalent. + * // + * Foo[] + * + * // This permission name is the equivalent to the two permission names + * // above: + * // Foo[**//*:*], Foo[], Foo are equivalent. + * // + * Foo + * + * // allows access to Foo from all namespaces - but not recursively. + * // This wildcard permission complements the previous one: it allows + * // access to 'Foo' from an MBean directly registered in any local namespace. + * // + * Foo[*//*:*] + * + *+ *Note on wildcards: In an object name pattern, a path element + * of exactly
+ ***
corresponds to a meta + * wildcard that will match any number of sub namespaces. Hence:+ *
+ * + *+ *
+ *pattern matches doesn't match + * + *+ * + * **//D:k=v
+ * a//D:k=v
+ *a//b//D:k=v
+ *a//b//c//D:k=v
D:k=v
+ * + * a//**//D:k=v
+ * a//b//D:k=v
+ *a//b//c//D:k=v
b//b//c//D:k=v
+ *a//D:k=v
+ *D:k=v
+ * + * a//**//e//D:k=v
+ * a//b//e//D:k=v
+ *a//b//c//e//D:k=v
a//b//c//c//D:k=v
+ *b//b//c//e//D:k=v
+ *a//e//D:k=v
+ *e//D:k=v
+ * + * + * a//b**//e//D:k=v
+ * a//b//e//D:k=v
a//b//c//e//D:k=v
+ * because in that caseb**
+ * is not a meta-wildcard - andb**
+ * is thus equivalent tob*
.If {@code
+ *::} is omitted, then one of + * member
orobject name
may be omitted. + * If theobject name
is omitted, + * the[]
may be too (but does not have to be). It is + * not legal to omit all items, that is to have a name + * which is the empty string.If {@code
+ * + *} is present, it must be followed by + * the {@code "::"} separator - otherwise it will be interpreted as + * a {@code member name}. + * + * One or more of the MBean Server name, + * member + * or object name may be the character "
+ * + *-
", + * which is equivalent to a null value. A null value is implied by + * any value (including another null value) but does not imply any + * other value. + *The possible actions are these:
+ * + *+ *
+ * + *- addNotificationListener
+ *- getAttribute
+ *- getClassLoader
+ *- getClassLoaderFor
+ *- getClassLoaderRepository
+ *- getMBeanInfo
+ *- getObjectInstance
+ *- instantiate
+ *- invoke
+ *- isInstanceOf
+ *- queryMBeans
+ *- queryNames
+ *- registerMBean
+ *- removeNotificationListener
+ *- setAttribute
+ *- unregisterMBean
+ *In a comma-separated list of actions, spaces are allowed before + * and after each action.
+ * + * @since 1.7 + */ +public class JMXNamespacePermission extends Permission { + + private static final long serialVersionUID = -2416928705275160661L; + + private static final String WILDPATH = "**" + + JMXNamespaces.NAMESPACE_SEPARATOR + "*"; + + /** + * Actions list. + */ + private static final int AddNotificationListener = 0x00001; + private static final int GetAttribute = 0x00002; + private static final int GetClassLoader = 0x00004; + private static final int GetClassLoaderFor = 0x00008; + private static final int GetClassLoaderRepository = 0x00010; + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + // private static final int GetDomains = 0x00020; + private static final int GetMBeanInfo = 0x00040; + private static final int GetObjectInstance = 0x00080; + private static final int Instantiate = 0x00100; + private static final int Invoke = 0x00200; + private static final int IsInstanceOf = 0x00400; + private static final int QueryMBeans = 0x00800; + private static final int QueryNames = 0x01000; + private static final int RegisterMBean = 0x02000; + private static final int RemoveNotificationListener = 0x04000; + private static final int SetAttribute = 0x08000; + private static final int UnregisterMBean = 0x10000; + + /** + * No actions. + */ + private static final int NONE = 0x00000; + + /** + * All actions. + */ + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + // + private static final int ALL = + AddNotificationListener | + GetAttribute | + GetClassLoader | + GetClassLoaderFor | + GetClassLoaderRepository | + GetMBeanInfo | + GetObjectInstance | + Instantiate | + Invoke | + IsInstanceOf | + QueryMBeans | + QueryNames | + RegisterMBean | + RemoveNotificationListener | + SetAttribute | + UnregisterMBean; + + /** + * The actions string. + */ + private String actions; + + /** + * The actions mask. + */ + private transient int mask; + + /** + * The name of the MBeanServer in which this permission is checked, or + * granted. If null, is implied by any MBean server name + * but does not imply any non-null MBean server name. + */ + private transient String mbeanServerName; + + /** + * The member that must match. If null, is implied by any member + * but does not imply any non-null member. + */ + private transient String member; + + /** + * The objectName that must match. If null, is implied by any + * objectName but does not imply any non-null objectName. + */ + private transient ObjectName objectName; + + /** + * If objectName is missing from name, then allnames will be + * set to true. + */ + private transient boolean allnames = false; + + /** + * Parseactions
parameter. + */ + private void parseActions() { + + int amask; + + if (actions == null) + throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + + "actions can't be null"); + if (actions.equals("")) + throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + + "actions can't be empty"); + + amask = getMask(actions); + + if ((amask & ALL) != amask) + throw new IllegalArgumentException("Invalid actions mask"); + if (amask == NONE) + throw new IllegalArgumentException("Invalid actions mask"); + this.mask = amask; + } + + /** + * Parsename
parameter. + */ + private void parseName() { + String name = getName(); + + if (name == null) + throw new IllegalArgumentException("JMXNamespaceAccessPermission name " + + "cannot be null"); + + if (name.equals("")) + throw new IllegalArgumentException("JMXNamespaceAccessPermission name " + + "cannot be empty"); + final int sepIndex = name.indexOf("::"); + if (sepIndex < 0) { + setMBeanServerName("*"); + } else { + setMBeanServerName(name.substring(0,sepIndex)); + } + + /* The name looks like "mbeanServerName::member[objectname]". + We subtract elements from the right as we parse, so after + parsing the objectname we have "class#member" and after parsing the + member we have "class". Each element is optional. */ + + // Parse ObjectName + + final int start = (sepIndex<0)?0:sepIndex+2; + int openingBracket = name.indexOf("[",start); + if (openingBracket == -1) { + // If "[on]" missing then ObjectName("*:*") + // + objectName = null; + allnames = true; + openingBracket=name.length(); + } else { + if (!name.endsWith("]")) { + throw new IllegalArgumentException("JMXNamespaceAccessPermission: " + + "The ObjectName in the " + + "target name must be " + + "included in square " + + "brackets"); + } else { + // Create ObjectName + // + String on = name.substring(openingBracket + 1, + name.length() - 1); + try { + // If "[]" then allnames are implied + // + final ObjectName target; + final boolean all; + if (on.equals("")) { + target = null; + all = true; + } else if (on.equals("-")) { + target = null; + all = false; + } else { + target = new ObjectName(on); + all = false; + } + setObjectName(target,all); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException( + "JMXNamespaceAccessPermission: " + + "The target name does " + + "not specify a valid " + + "ObjectName", e); + } + } + } + + final String memberName = name.substring(start,openingBracket); + setMember(memberName); + } + + private void setObjectName(ObjectName target, boolean all) { + if (target != null && + !Util.wildpathmatch(target.getDomain(), WILDPATH)) { + throw new IllegalArgumentException( + "The target name does not contain " + + "any namespace: "+String.valueOf(target)); + } else if (target != null) { + final String domain = target.getDomain(); + final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length(); + final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); + if (sepc < 0 || (sepc+seplen)==domain.length()) { + throw new IllegalArgumentException(String.valueOf(target)+ + ": no namespace in domain"); + } + } + objectName = target; + allnames = all; + } + + /** + * Assign fields based on className, member, and objectName + * parameters. + */ +// private void initName(String namespaceName, String member, +// ObjectName objectName, boolean allnames) { +// setNamespace(namespaceName); + private void initName(String mbeanServerName, String member, + ObjectName mbeanName, boolean all) { + setMBeanServerName(mbeanServerName); + setMember(member); + setObjectName(mbeanName, all); + } + + private void setMBeanServerName(String mbeanServerName) { + if (mbeanServerName == null || mbeanServerName.equals("-")) { + this.mbeanServerName = null; + } else if (mbeanServerName.equals("")) { + this.mbeanServerName = "*"; + } else { + this.mbeanServerName = mbeanServerName; + } + } + + private void setMember(String member) { + if (member == null || member.equals("-")) + this.member = null; + else if (member.equals("")) + this.member = "*"; + else + this.member = member; + } + + /** + *Create a new JMXNamespacePermission object with the + * specified target name and actions.
+ * + *The target name is of the form + * "
+ *mbeanServerName::member[objectName]
" where each part is + * optional. This target name must not be empty or null. + * IfobjectName
is present, it is of + * the formnamespace//MBeanName
. + *+ * For a permission you need, {@code mbeanServerName} is the + * name of the MBeanServer from + * which {@code objectName} is being accessed. + *
+ *+ * For a permission you have, {@code mbeanServerName} is the + * name of the MBeanServer from + * which access to {@code objectName} is granted. + * It can also be a pattern, and if omitted, {@code "*"} is assumed, + * meaning that access to {@code objectName} is granted in all + * MBean servers in the JVM. + *
+ * + *The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param name the triplet "mbeanServerName::member[objectName]". + * IfobjectName
is present, it is of + * the formnamespace//MBeanName
. + * @param actions the action string. + * + * @exception IllegalArgumentException if thename
or + *actions
is invalid. + */ + public JMXNamespacePermission(String name, String actions) { + super(name); + + parseName(); + + this.actions = actions; + parseActions(); + } + + /** + *Create a new JMXNamespacePermission object with the specified + * target name (namespace name, member, object name) and actions.
+ * + *The {@code MBeanServer} name, member and object name + * parameters define a target name of the form + * "
+ * + *mbeanServerName::member[objectName]
" where each + * part is optional. This will be the result of {@link #getName()} on the + * resultant JMXNamespacePermission. + * If thembeanServerName
is empty or exactly {@code "*"}, then + * "{@code mbeanServerName::}" is omitted in that result. + *The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name + * that is implied by any MBeanServer name but does not imply any other + * MBeanServer name. + * @param member the member to which this permission applies. May + * be null or"-"
, which represents a member that is + * implied by any member but does not imply any other member. + * @param objectName the object name to which this permission + * applies. + * May be null, which represents an object name that is + * implied by any object name but does not imply any other object + * name. If not null, the {@code objectName} must be of the + * form {@code// } - where {@code } + * can be a domain pattern, and {@code } can be an ObjectName + * pattern. + * For a permission you need, {@code } is the name of the + * name space for which the permission is checked, and {@code } + * is the name of the MBean in that namespace. + * The composed name {@code // } thus represents the + * name of the MBean as seen by the {@code mbeanServerName} containing + * {@code }. + * + * @param actions the action string. + */ + public JMXNamespacePermission( + String mbeanServerName, + String member, + ObjectName objectName, + String actions) { + this(mbeanServerName, member, objectName, false, actions); +// this(member, objectName, false, actions); + } + + /** + * Create a new JMXNamespacePermission object with the specified + * MBean Server name, member, and actions.
+ * + *The {@code MBeanServer} name and member + * parameters define a target name of the form + * "
+ * + *mbeanServerName::member[]
" where each + * part is optional. This will be the result of {@link #getName()} on the + * resultant JMXNamespacePermission. + * If thembeanServerName
is empty or exactly {@code "*"}, then + * "{@code mbeanServerName::}" is omitted in that result. + *The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name + * that is implied by any MBeanServer name but does not imply any other + * MBeanServer name. + * @param member the member to which this permission applies. May + * be null or"-"
, which represents a member that is + * implied by any member but does not imply any other member. + * @param actions the action string. + */ + public JMXNamespacePermission(String mbeanServerName, + String member, + String actions) { + this(mbeanServerName,member,null,true,actions); + // this(member,null,allnames,actions); + } + + /** + *Create a new JMXNamespacePermission object with the specified + * target name (namespace name, member, object name) and actions.
+ * + *The MBean Server name, member and object name parameters define a + * target name of the form + * "
+ * + *mbeanServerName::member[objectName]
" where each part is + * optional. This will be the result of {@link + * java.security.Permission#getName() getName()} on the + * resultant JMXNamespacePermission.The actions parameter contains a comma-separated list of the + * desired actions granted on the target name. It must not be + * empty or null.
+ * + * @param mbeanServerName the name of the {@code MBeanServer} to which this + * permission applies. + * May be null or"-"
, which represents an MBeanServer name + * that is implied by any MBeanServer name but does not imply any other + * MBeanServer name. + * @param member the member to which this permission applies. May + * be null or"-"
, which represents a member that is + * implied by any member but does not imply any other member. + * @param objectName the object name to which this permission + * applies. If null, and allnames is false, represents an object + * name that is implied by any object name but does not imply any + * other object name. Otherwise, if allnames is true, it represents + * a meta wildcard that matches all object names. It is equivalent to + * a missing objectName ("[]") in the {@link + * java.security.Permission#getName() name} property. + * @param allnames represent a meta wildcard indicating that the + * objectName was not specified. This implies all objectnames + * that match "*:*" and all object names that match + * "**//*:*" + * @param actions the action string. + */ + private JMXNamespacePermission(String mbeanServerName, + String member, + ObjectName objectName, + boolean allnames, + String actions) { + + super(makeName(mbeanServerName, + member, objectName, allnames)); + initName(mbeanServerName, + member, objectName, allnames); + + this.actions = actions; + parseActions(); + } + + private static String makeName(String mbeanServerName, + String memberName, ObjectName objName, boolean allMBeans) { + final StringBuilder name = new StringBuilder(); + if (mbeanServerName == null) + mbeanServerName = "-"; + if (!mbeanServerName.equals("") && !mbeanServerName.equals("*")) + name.append(mbeanServerName).append("::"); + if (memberName == null) + memberName = "-"; + name.append(memberName); + if (objName == null) { + if (allMBeans) + name.append("[]"); + else + name.append("[-]"); + } else { + final String domain = objName.getDomain(); + final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length(); + final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); + if (sepc < 0 || (sepc+seplen)==domain.length()) { + throw new IllegalArgumentException(String.valueOf(objName)+ + ": no namespace in domain"); + } + final String can = objName.getCanonicalName(); + name.append("[").append(can).append("]"); + } + return name.toString(); + } + + /** + * Returns the "canonical string representation" of the actions. That is, + * this method always returns actions in alphabetical order. + * + * @return the canonical string representation of the actions. + */ + public String getActions() { + + if (actions == null) + actions = getActions(this.mask); + + return actions; + } + + /** + * Returns the "canonical string representation" + * of the actions from the mask. + */ + private static String getActions(int mask) { + final StringBuilder sb = new StringBuilder(); + boolean comma = false; + + if ((mask & AddNotificationListener) == AddNotificationListener) { + comma = true; + sb.append("addNotificationListener"); + } + + if ((mask & GetAttribute) == GetAttribute) { + if (comma) sb.append(','); + else comma = true; + sb.append("getAttribute"); + } + + if ((mask & GetClassLoader) == GetClassLoader) { + if (comma) sb.append(','); + else comma = true; + sb.append("getClassLoader"); + } + + if ((mask & GetClassLoaderFor) == GetClassLoaderFor) { + if (comma) sb.append(','); + else comma = true; + sb.append("getClassLoaderFor"); + } + + if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) { + if (comma) sb.append(','); + else comma = true; + sb.append("getClassLoaderRepository"); + } + + if ((mask & GetMBeanInfo) == GetMBeanInfo) { + if (comma) sb.append(','); + else comma = true; + sb.append("getMBeanInfo"); + } + + if ((mask & GetObjectInstance) == GetObjectInstance) { + if (comma) sb.append(','); + else comma = true; + sb.append("getObjectInstance"); + } + + if ((mask & Instantiate) == Instantiate) { + if (comma) sb.append(','); + else comma = true; + sb.append("instantiate"); + } + + if ((mask & Invoke) == Invoke) { + if (comma) sb.append(','); + else comma = true; + sb.append("invoke"); + } + + if ((mask & IsInstanceOf) == IsInstanceOf) { + if (comma) sb.append(','); + else comma = true; + sb.append("isInstanceOf"); + } + + if ((mask & QueryMBeans) == QueryMBeans) { + if (comma) sb.append(','); + else comma = true; + sb.append("queryMBeans"); + } + + if ((mask & QueryNames) == QueryNames) { + if (comma) sb.append(','); + else comma = true; + sb.append("queryNames"); + } + + if ((mask & RegisterMBean) == RegisterMBean) { + if (comma) sb.append(','); + else comma = true; + sb.append("registerMBean"); + } + + if ((mask & RemoveNotificationListener) == RemoveNotificationListener) { + if (comma) sb.append(','); + else comma = true; + sb.append("removeNotificationListener"); + } + + if ((mask & SetAttribute) == SetAttribute) { + if (comma) sb.append(','); + else comma = true; + sb.append("setAttribute"); + } + + if ((mask & UnregisterMBean) == UnregisterMBean) { + if (comma) sb.append(','); + else comma = true; + sb.append("unregisterMBean"); + } + + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + + return sb.toString(); + } + + @Override + public int hashCode() { + return this.getName().hashCode() + this.getActions().hashCode(); + } + + /** + * Converts an action String to an integer action mask. + * + * @param action the action string. + * @return the action mask. + */ + private static int getMask(String action) { + + /* + * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM. + * + * The 'string length' test must be performed for the lengthiest + * strings first. + * + * In this permission if the "unregisterMBean" string length test is + * performed after the "registerMBean" string length test the algorithm + * considers the 'unregisterMBean' action as being the 'registerMBean' + * action and a parsing error is returned. + */ + + int mask = NONE; + + if (action == null) { + return mask; + } + + if (action.equals("*")) { + return ALL; + } + + char[] a = action.toCharArray(); + + int i = a.length - 1; + if (i < 0) + return mask; + + while (i != -1) { + char c; + + // skip whitespace + while ((i!=-1) && ((c = a[i]) == ' ' || + c == '\r' || + c == '\n' || + c == '\f' || + c == '\t')) + i--; + + // check for the known strings + int matchlen; + + // No GetDomains because it is not possible to route a call to + // getDomains() on a NamespaceInterceptor - getDomains() doesn't + // have any ObjectName. + + if (i >= 25 && /* removeNotificationListener */ + (a[i-25] == 'r') && + (a[i-24] == 'e') && + (a[i-23] == 'm') && + (a[i-22] == 'o') && + (a[i-21] == 'v') && + (a[i-20] == 'e') && + (a[i-19] == 'N') && + (a[i-18] == 'o') && + (a[i-17] == 't') && + (a[i-16] == 'i') && + (a[i-15] == 'f') && + (a[i-14] == 'i') && + (a[i-13] == 'c') && + (a[i-12] == 'a') && + (a[i-11] == 't') && + (a[i-10] == 'i') && + (a[i-9] == 'o') && + (a[i-8] == 'n') && + (a[i-7] == 'L') && + (a[i-6] == 'i') && + (a[i-5] == 's') && + (a[i-4] == 't') && + (a[i-3] == 'e') && + (a[i-2] == 'n') && + (a[i-1] == 'e') && + (a[i] == 'r')) { + matchlen = 26; + mask |= RemoveNotificationListener; + } else if (i >= 23 && /* getClassLoaderRepository */ + (a[i-23] == 'g') && + (a[i-22] == 'e') && + (a[i-21] == 't') && + (a[i-20] == 'C') && + (a[i-19] == 'l') && + (a[i-18] == 'a') && + (a[i-17] == 's') && + (a[i-16] == 's') && + (a[i-15] == 'L') && + (a[i-14] == 'o') && + (a[i-13] == 'a') && + (a[i-12] == 'd') && + (a[i-11] == 'e') && + (a[i-10] == 'r') && + (a[i-9] == 'R') && + (a[i-8] == 'e') && + (a[i-7] == 'p') && + (a[i-6] == 'o') && + (a[i-5] == 's') && + (a[i-4] == 'i') && + (a[i-3] == 't') && + (a[i-2] == 'o') && + (a[i-1] == 'r') && + (a[i] == 'y')) { + matchlen = 24; + mask |= GetClassLoaderRepository; + } else if (i >= 22 && /* addNotificationListener */ + (a[i-22] == 'a') && + (a[i-21] == 'd') && + (a[i-20] == 'd') && + (a[i-19] == 'N') && + (a[i-18] == 'o') && + (a[i-17] == 't') && + (a[i-16] == 'i') && + (a[i-15] == 'f') && + (a[i-14] == 'i') && + (a[i-13] == 'c') && + (a[i-12] == 'a') && + (a[i-11] == 't') && + (a[i-10] == 'i') && + (a[i-9] == 'o') && + (a[i-8] == 'n') && + (a[i-7] == 'L') && + (a[i-6] == 'i') && + (a[i-5] == 's') && + (a[i-4] == 't') && + (a[i-3] == 'e') && + (a[i-2] == 'n') && + (a[i-1] == 'e') && + (a[i] == 'r')) { + matchlen = 23; + mask |= AddNotificationListener; + } else if (i >= 16 && /* getClassLoaderFor */ + (a[i-16] == 'g') && + (a[i-15] == 'e') && + (a[i-14] == 't') && + (a[i-13] == 'C') && + (a[i-12] == 'l') && + (a[i-11] == 'a') && + (a[i-10] == 's') && + (a[i-9] == 's') && + (a[i-8] == 'L') && + (a[i-7] == 'o') && + (a[i-6] == 'a') && + (a[i-5] == 'd') && + (a[i-4] == 'e') && + (a[i-3] == 'r') && + (a[i-2] == 'F') && + (a[i-1] == 'o') && + (a[i] == 'r')) { + matchlen = 17; + mask |= GetClassLoaderFor; + } else if (i >= 16 && /* getObjectInstance */ + (a[i-16] == 'g') && + (a[i-15] == 'e') && + (a[i-14] == 't') && + (a[i-13] == 'O') && + (a[i-12] == 'b') && + (a[i-11] == 'j') && + (a[i-10] == 'e') && + (a[i-9] == 'c') && + (a[i-8] == 't') && + (a[i-7] == 'I') && + (a[i-6] == 'n') && + (a[i-5] == 's') && + (a[i-4] == 't') && + (a[i-3] == 'a') && + (a[i-2] == 'n') && + (a[i-1] == 'c') && + (a[i] == 'e')) { + matchlen = 17; + mask |= GetObjectInstance; + } else if (i >= 14 && /* unregisterMBean */ + (a[i-14] == 'u') && + (a[i-13] == 'n') && + (a[i-12] == 'r') && + (a[i-11] == 'e') && + (a[i-10] == 'g') && + (a[i-9] == 'i') && + (a[i-8] == 's') && + (a[i-7] == 't') && + (a[i-6] == 'e') && + (a[i-5] == 'r') && + (a[i-4] == 'M') && + (a[i-3] == 'B') && + (a[i-2] == 'e') && + (a[i-1] == 'a') && + (a[i] == 'n')) { + matchlen = 15; + mask |= UnregisterMBean; + } else if (i >= 13 && /* getClassLoader */ + (a[i-13] == 'g') && + (a[i-12] == 'e') && + (a[i-11] == 't') && + (a[i-10] == 'C') && + (a[i-9] == 'l') && + (a[i-8] == 'a') && + (a[i-7] == 's') && + (a[i-6] == 's') && + (a[i-5] == 'L') && + (a[i-4] == 'o') && + (a[i-3] == 'a') && + (a[i-2] == 'd') && + (a[i-1] == 'e') && + (a[i] == 'r')) { + matchlen = 14; + mask |= GetClassLoader; + } else if (i >= 12 && /* registerMBean */ + (a[i-12] == 'r') && + (a[i-11] == 'e') && + (a[i-10] == 'g') && + (a[i-9] == 'i') && + (a[i-8] == 's') && + (a[i-7] == 't') && + (a[i-6] == 'e') && + (a[i-5] == 'r') && + (a[i-4] == 'M') && + (a[i-3] == 'B') && + (a[i-2] == 'e') && + (a[i-1] == 'a') && + (a[i] == 'n')) { + matchlen = 13; + mask |= RegisterMBean; + } else if (i >= 11 && /* getAttribute */ + (a[i-11] == 'g') && + (a[i-10] == 'e') && + (a[i-9] == 't') && + (a[i-8] == 'A') && + (a[i-7] == 't') && + (a[i-6] == 't') && + (a[i-5] == 'r') && + (a[i-4] == 'i') && + (a[i-3] == 'b') && + (a[i-2] == 'u') && + (a[i-1] == 't') && + (a[i] == 'e')) { + matchlen = 12; + mask |= GetAttribute; + } else if (i >= 11 && /* getMBeanInfo */ + (a[i-11] == 'g') && + (a[i-10] == 'e') && + (a[i-9] == 't') && + (a[i-8] == 'M') && + (a[i-7] == 'B') && + (a[i-6] == 'e') && + (a[i-5] == 'a') && + (a[i-4] == 'n') && + (a[i-3] == 'I') && + (a[i-2] == 'n') && + (a[i-1] == 'f') && + (a[i] == 'o')) { + matchlen = 12; + mask |= GetMBeanInfo; + } else if (i >= 11 && /* isInstanceOf */ + (a[i-11] == 'i') && + (a[i-10] == 's') && + (a[i-9] == 'I') && + (a[i-8] == 'n') && + (a[i-7] == 's') && + (a[i-6] == 't') && + (a[i-5] == 'a') && + (a[i-4] == 'n') && + (a[i-3] == 'c') && + (a[i-2] == 'e') && + (a[i-1] == 'O') && + (a[i] == 'f')) { + matchlen = 12; + mask |= IsInstanceOf; + } else if (i >= 11 && /* setAttribute */ + (a[i-11] == 's') && + (a[i-10] == 'e') && + (a[i-9] == 't') && + (a[i-8] == 'A') && + (a[i-7] == 't') && + (a[i-6] == 't') && + (a[i-5] == 'r') && + (a[i-4] == 'i') && + (a[i-3] == 'b') && + (a[i-2] == 'u') && + (a[i-1] == 't') && + (a[i] == 'e')) { + matchlen = 12; + mask |= SetAttribute; + } else if (i >= 10 && /* instantiate */ + (a[i-10] == 'i') && + (a[i-9] == 'n') && + (a[i-8] == 's') && + (a[i-7] == 't') && + (a[i-6] == 'a') && + (a[i-5] == 'n') && + (a[i-4] == 't') && + (a[i-3] == 'i') && + (a[i-2] == 'a') && + (a[i-1] == 't') && + (a[i] == 'e')) { + matchlen = 11; + mask |= Instantiate; + } else if (i >= 10 && /* queryMBeans */ + (a[i-10] == 'q') && + (a[i-9] == 'u') && + (a[i-8] == 'e') && + (a[i-7] == 'r') && + (a[i-6] == 'y') && + (a[i-5] == 'M') && + (a[i-4] == 'B') && + (a[i-3] == 'e') && + (a[i-2] == 'a') && + (a[i-1] == 'n') && + (a[i] == 's')) { + matchlen = 11; + mask |= QueryMBeans; + } else if (i >= 9 && /* queryNames */ + (a[i-9] == 'q') && + (a[i-8] == 'u') && + (a[i-7] == 'e') && + (a[i-6] == 'r') && + (a[i-5] == 'y') && + (a[i-4] == 'N') && + (a[i-3] == 'a') && + (a[i-2] == 'm') && + (a[i-1] == 'e') && + (a[i] == 's')) { + matchlen = 10; + mask |= QueryNames; + } else if (i >= 5 && /* invoke */ + (a[i-5] == 'i') && + (a[i-4] == 'n') && + (a[i-3] == 'v') && + (a[i-2] == 'o') && + (a[i-1] == 'k') && + (a[i] == 'e')) { + matchlen = 6; + mask |= Invoke; + } else { + // parse error + throw new IllegalArgumentException("Invalid permission: " + + action); + } + + // make sure we didn't just match the tail of a word + // like "ackbarfaccept". Also, skip to the comma. + boolean seencomma = false; + while (i >= matchlen && !seencomma) { + switch(a[i-matchlen]) { + case ',': + seencomma = true; + break; + case ' ': case '\r': case '\n': + case '\f': case '\t': + break; + default: + throw new IllegalArgumentException("Invalid permission: " + + action); + } + i--; + } + + // point i at the location of the comma minus one (or -1). + i -= matchlen; + } + + return mask; + } + + /** + *Checks if this JMXNamespacePermission object "implies" the + * specified permission.
+ * + *More specifically, this method returns true if:
+ * + *+ * + *
+ * + *- p is an instance of JMXNamespacePermission; and
+ * + *- p has a null mbeanServerName or p's mbeanServerName + * matches this object's mbeanServerName; and
+ * + *- p has a null member or p's member matches this + * object's member; and
+ * + *- p has a null object name or p's + * object name matches this object's object name; and
+ * + *- p's actions are a subset of this object's actions
+ * + *If this object's mbeanServerName is a pattern, then p's + * mbeanServerName is matched against that pattern. An empty + * mbeanServerName is equivalent to "{@code *}". A null + * mbeanServerName is equivalent to "{@code -}".
+ *If this object's mbeanServerName is "
+ * + **
" or is + * empty, p's mbeanServerName always matches it.If this object's member is "
+ * + **
", p's + * member always matches it.If this object's objectName n1 is an object name pattern, + * p's objectName n2 matches it if + * {@link ObjectName#equals n1.equals(n2)} or if + * {@link ObjectName#apply n1.apply(n2)}.
+ * + *A permission that includes the
+ * + * @param p the permission to check against. + * @return true if the specified permission is implied by this object, + * false if not. + */ + public boolean implies(Permission p) { + if (!(p instanceof JMXNamespacePermission)) + return false; + + JMXNamespacePermission that = (JMXNamespacePermission) p; + + // Actions + // + // The actions in 'this' permission must be a + // superset of the actions in 'that' permission + // + + /* "queryMBeans" implies "queryNames" */ + if ((this.mask & QueryMBeans) == QueryMBeans) { + if (((this.mask | QueryNames) & that.mask) != that.mask) { + //System.out.println("action [with QueryNames] does not imply"); + return false; + } + } else { + if ((this.mask & that.mask) != that.mask) { + //System.out.println("action does not imply"); + return false; + } + } + + // Target name + // + // The 'mbeanServerName' check is true iff: + // 1) the mbeanServerName in 'this' permission is omitted or "*", or + // 2) the mbeanServerName in 'that' permission is omitted or "*", or + // 3) the mbeanServerName in 'this' permission does pattern + // matching with the mbeanServerName in 'that' permission. + // + // The 'member' check is true iff: + // 1) the member in 'this' member is omitted or "*", or + // 2) the member in 'that' member is omitted or "*", or + // 3) the member in 'this' permission equals the member in + // 'that' permission. + // + // The 'object name' check is true iff: + // 1) the object name in 'this' permission is omitted, or + // 2) the object name in 'that' permission is omitted, or + // 3) the object name in 'this' permission does pattern + // matching with the object name in 'that' permission. + // + + if (that.mbeanServerName == null) { + // bottom is implied + } else if (this.mbeanServerName == null) { + // bottom implies nothing but itself + return false; + } else if (that.mbeanServerName.equals(this.mbeanServerName)) { + // exact match + } else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) { + return false; // no match + } + + /* Check if this.member implies that.member */ + + if (that.member == null) { + // bottom is implied + } else if (this.member == null) { + // bottom implies nothing but itself + return false; + } else if (this.member.equals("*")) { + // wildcard implies everything (including itself) + } else if (this.member.equals(that.member)) { + // exact match + } else if (!Util.wildmatch(that.member,this.member)) { + return false; // no match + } + + /* Check if this.objectName implies that.objectName */ + + if (that.objectName == null) { + // bottom is implied + } else if (this.objectName == null) { + // bottom implies nothing but itself + if (allnames == false) return false; + } else if (!this.objectName.apply(that.objectName)) { + /* ObjectName.apply returns false if that.objectName is a + wildcard so we also allow equals for that case. This + never happens during real permission checks, but means + the implies relation is reflexive. */ + if (!this.objectName.equals(that.objectName)) + return false; + } + + return true; + } + + /** + * Checks two JMXNamespacePermission objects for equality. Checks + * that obj is an JMXNamespacePermission, and has the same + * name and actions as this object. + *queryMBeans
action + * is considered to includequeryNames
as well.+ * @param obj the object we are testing for equality with this object. + * @return true if obj is an JMXNamespacePermission, and has the + * same name and actions as this JMXNamespacePermission object. + */ + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (! (obj instanceof JMXNamespacePermission)) + return false; + + JMXNamespacePermission that = (JMXNamespacePermission) obj; + + return (this.mask == that.mask) && + (this.getName().equals(that.getName())); + } + + /** + * Deserialize this object based on its name and actions. + */ + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + parseName(); + parseActions(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,300 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import java.io.IOException; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +/** + * This class makes it possible to navigate easily within a hierarchical + * namespace view. + * + *
+ * MBeanServerConnnection rootConnection = ...; + * + * // create a view at the local root of the namespace hierarchy. + * // + * JMXNamespaceView view = new JMXNamespaceView(rootConnection); + * + * // list all top level namespaces + * String[] list = view.list(); + * + * // select one namespace from the list + * String whereToGo = ... ; + * + * // go down to the selected namespace: + * view = view.down(whereToGo); + * System.out.println("I am now in: " + view.where()); + * System.out.println("I can see these MBeans:" + + * view.getMBeanServerConnection().queryNames(null,null)); + * + * // list sub namespaces in current view ('whereToGo') + * list = view.list(); + * System.out.println("Here are the sub namespaces of "+view.where()+": "+ + * Arrays.toString(list)); + * + * // go up one level + * view = view.up(); + * System.out.println("I am now back to: " + + * (view.isRoot() ? "root namespace" : view.where())); + *+ * @since 1.7 + */ +public class JMXNamespaceView { + + private static final ObjectName ALL_NAMESPACES; + static { + try { + ALL_NAMESPACES = ObjectName.getInstance("*" + + JMXNamespaces.NAMESPACE_SEPARATOR + ":"+ + JMXNamespace.TYPE_ASSIGNMENT); + } catch (MalformedObjectNameException x) { + throw new ExceptionInInitializerError(x); + } + } + private static final int NAMESPACE_SEPARATOR_LENGTH = + JMXNamespaces.NAMESPACE_SEPARATOR.length(); + + private final JMXNamespaceView parent; + private final MBeanServerConnection here; + private final String where; + + private static MBeanServerConnection checkRoot(MBeanServerConnection root) { + if (root == null) + throw new IllegalArgumentException( + "namespaceRoot: null is not a valid value"); + return root; + } + + /** + * Creates a view at the top of a JMX namespace hierarchy. + * @param namespaceRoot The {@code MBeanServerConnection} at the + * top of the hierarchy. + */ + public JMXNamespaceView(MBeanServerConnection namespaceRoot) { + this(null,checkRoot(namespaceRoot),""); + } + + // This constructor should remain private. A user can only create + // JMXNamespaceView at the top of the hierarchy. + // JMXNamespaceView sub nodes are created by their parent nodes. + private JMXNamespaceView(JMXNamespaceView parent, + MBeanServerConnection here, String where) { + this.parent = parent; + this.here = here; + this.where = where; + } + + /** + * Returns the path leading to the namespace in this view, from + * the top of the hierarchy. + * @return The path to the namespace in this view. + */ + public String where() { + return where; + } + + /** + * Lists all direct sub namespaces in this view. The returned strings + * do not contain the {@code //} separator. + * + * @return A list of direct sub name spaces accessible from this + * namespace. + * @throws IOException if the attempt to list the namespaces fails because + * of a communication problem. + */ + public String[] list() throws IOException { + final Setnames = + here.queryNames(ALL_NAMESPACES,null); + final String[] res = new String[names.size()]; + int i = 0; + for (ObjectName dirName : names) { + final String dir = dirName.getDomain(); + res[i++]=dir.substring(0,dir.length()-NAMESPACE_SEPARATOR_LENGTH); + } + return res; + } + + /** + * Go down into a sub namespace. + * @param namespace the namespace to go down to. It can contain one or + * more {@code //} separators, to traverse intermediate namespaces, but + * it must not begin or end with {@code //} or contain an empty + * intermediate namespace. If it is the empty string, then {@code this} is + * returned. + * @return A view of the named sub namespace. + * @throws IllegalArgumentException if the {@code namespace} begins or + * ends with {@code //}. + */ + public JMXNamespaceView down(String namespace) { + if (namespace.equals("")) return this; + if (namespace.startsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) + throw new IllegalArgumentException(namespace+": can't start with "+ + JMXNamespaces.NAMESPACE_SEPARATOR); + + // This is a convenience to handle paths like xxx//yyy + final String[] elts = + namespace.split(JMXNamespaces.NAMESPACE_SEPARATOR); + + // Go down the path, creating all sub namespaces along the way. + // Usually there will be a single element in the given namespace + // name, but we don't want to forbid things like + // down("xxx//yyy/www"); + // + JMXNamespaceView previous = this; + String cursor = where; + for (String elt : elts) { + // empty path elements are not allowed. It means we + // had something like "xxx////yyy" + if (elt.equals("")) + throw new IllegalArgumentException(namespace+ + ": invalid path element"); + + // compute the "where" for the child. + cursor = JMXNamespaces.concat(cursor, elt); + + // create the child... + final JMXNamespaceView next = + makeJMXNamespaceView(root(), previous, cursor); + + // the current child will be the parent of the next child... + previous = next; + } + + // We return the last child that was created. + return previous; + } + + /** + * Go back up one level. If this view is at the root of the + * hierarchy, returns {@code null}. + * @return A view of the parent namespace, or {@code null} if we're at + * the root of the hierarchy. + */ + public JMXNamespaceView up() { + return parent; + } + + /** + * Tells whether this view is at the root of the hierarchy. + * @return {@code true} if this view is at the root of the hierachy. + */ + public boolean isRoot() { + return parent == null; + } + + /** + * Returns the view at the root of the hierarchy. + * If we are already at the root, this is {@code this}. + * @return the view at the root of the hierarchy. + */ + public JMXNamespaceView root() { + if (parent == null) return this; + return parent.root(); + } + + /** + * A MBeanServerConnection to the namespace shown by this view. + * This is what would have been obtained by doing: + * + * JMX.narrowToNamespace(this.root().getMBeanServerConnection(), + * this.where()); + *+ * @return A MBeanServerConnection to the namespace shown by this view. + */ + public MBeanServerConnection getMBeanServerConnection() { + return here; + } + + /** + *Get the name of the JMXNamespaceMBean handling the namespace shown by + * this view, relative to the root of the hierarchy. If we are at the root + * of the hierarchy, this method returns {@code null}.
+ * + *You can use this method to make a proxy for the JMXNamespaceMBean + * as follows:
+ * + *+ * JMXNamespaceView view = ...; + * ObjectName namespaceMBeanName = view.getJMXNamespaceMBeanName(); + * JMXNamespaceMBean namespaceMBean = JMX.newMBeanProxy( + * view.root().getMBeanServerConnection(), namespaceMBeanName, + * JMXNamespaceMBean.class); + *+ * + * @return The name of the {@code JMXNamespaceMBean} handling the namespace + * shown by this view, or {@code null}. + */ + public ObjectName getJMXNamespaceMBeanName() { + if (parent == null) + return null; + else + return JMXNamespaces.getNamespaceObjectName(where); + } + + @Override + public int hashCode() { + return where.hashCode(); + } + + /** + * Returns true if this object is equal to the given object. The + * two objects are equal if the other object is also a {@code + * JMXNamespaceView} and both objects have the same {@linkplain #root root} + * MBeanServerConnection and the same {@linkplain #where path}. + * @param o the other object to compare to. + * @return true if both objects are equal. + */ + @Override + public boolean equals(Object o) { + if (o==this) return true; + if (! (o instanceof JMXNamespaceView)) return false; + if (!where.equals(((JMXNamespaceView)o).where)) return false; + return root().getMBeanServerConnection().equals( + ((JMXNamespaceView)o).root().getMBeanServerConnection()); + } + + private JMXNamespaceView makeJMXNamespaceView(final JMXNamespaceView root, + final JMXNamespaceView directParent, final String pathFromRoot) { + if (pathFromRoot.equals("")) return root; + + return new JMXNamespaceView(directParent, + narrowToNamespace(root.getMBeanServerConnection(), + pathFromRoot),pathFromRoot); + } + + private MBeanServerConnection narrowToNamespace(MBeanServerConnection root, + String path) { + if (root instanceof MBeanServer) + return JMXNamespaces.narrowToNamespace((MBeanServer)root, path); + return JMXNamespaces.narrowToNamespace(root, path); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,374 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.namespace.JMXNamespaceUtils; +import com.sun.jmx.namespace.ObjectNameRouter; +import com.sun.jmx.namespace.serial.RewritingProcessor; +import com.sun.jmx.namespace.RoutingConnectionProxy; +import com.sun.jmx.namespace.RoutingServerProxy; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; + +/** + * Static constants and utility methods to help work with + * JMX name spaces. There are no instances of this class. + * @since 1.7 + */ +public class JMXNamespaces { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + /** Creates a new instance of JMXNamespaces */ + private JMXNamespaces() { + } + + /** + * The name space separator. This is an alias for {@link + * ObjectName#NAMESPACE_SEPARATOR}. + **/ + public static final String NAMESPACE_SEPARATOR = + ObjectName.NAMESPACE_SEPARATOR; + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + + /** + * Returns a connector connected to a sub name space exposed through + * the parent connector. + * @param parent the parent connector. + * @param namespace the {@linkplain javax.management.namespace name space} + * to which the returned connector is + * connected. + * @return A connector connected to a sub name space exposed through + * the parent connector. + **/ + public static JMXConnector narrowToNamespace(final JMXConnector parent, + final String namespace) + throws IOException { + + return JMXNamespaceUtils.cd(parent,namespace,true); + } + + /** + * Creates a new {@code MBeanServerConnection} proxy on a + * {@linkplain javax.management.namespace sub name space} + * of the given parent. + * + * @param parent The parent {@code MBeanServerConnection} that contains + * the name space. + * @param namespace The {@linkplain javax.management.namespace + * name space} in which to narrow. + * @return A new {@code MBeanServerConnection} proxy that shows the content + * of that name space. + * @throws IllegalArgumentException if the name space does not exist, or + * if a proxy for that name space cannot be created. + */ + public static MBeanServerConnection narrowToNamespace( + MBeanServerConnection parent, + String namespace) { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Making MBeanServerConnection for: " +namespace); + return RoutingConnectionProxy.cd(parent,namespace); + } + + /** + * Creates a new {@code MBeanServer} proxy on a + * {@linkplain javax.management.namespace sub name space} + * of the given parent. + * + * @param parent The parent {@code MBeanServer} that contains + * the name space. + * @param namespace The {@linkplain javax.management.namespace + * name space} in which to narrow. + * @return A new {@code MBeanServer} proxy that shows the content + * of that name space. + * @throws IllegalArgumentException if either argument is null, + * or the name space does not exist, or if a proxy for that name space + * cannot be created. + */ + public static MBeanServer narrowToNamespace(MBeanServer parent, + String namespace) { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Making NamespaceServerProxy for: " +namespace); + return RoutingServerProxy.cd(parent,namespace); + } + + /** + * Returns an object that is the same as the given object except that + * any {@link ObjectName} it might contain has its domain modified. + * The returned object might be identical to the given object if it + * does not contain any {@code ObjectName} values or if none of them + * were modified. + * This method will replace a prefix ({@code toRemove}) from the path of + * the ObjectNames contained in {@code obj} by another prefix + * ({@code toAdd}). + * Therefore, all contained ObjectNames must have a path that start with + * the given {@code toRemove} prefix. If one of them doesn't, an {@link + * IllegalArgumentException} is thrown. + *+ * For instance, if {@code obj} contains the ObjectName + * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and + * {@code toRemove} + * is {@code x//y} this method will return a copy of {@code obj} that + * contains {@code v//w//z//d:k=x}.
+ *
+ * On the other hand, if {@code obj} contains the ObjectName + * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and + * {@code toRemove} is {@code v} this method + * will raise an exception, because {@code x//y//z//d:k=x} doesn't start + * with {@code v} + *Note: the default implementation of this method can use the + * Java serialization framework to clone and replace ObjectNames in the + * provided {@code obj}. It will usually fail if {@code obj} is not + * Java serializable, or contains objects which are not Java + * serializable. + *
+ * @param obj The object to deep-rewrite + * @param toRemove a prefix already present in contained ObjectNames. + * If {@code toRemove} is the empty string {@code ""}, nothing + * will be removed from the contained ObjectNames. + * @param toAdd the prefix that will replace (@code toRemove} in contained + * ObjectNames. + * If {@code toAdd} is the empty string {@code ""}, nothing + * will be added to the contained ObjectNames. + * @return the rewritten object, or possibly {@code obj} if nothing needed + * to be changed. + * @throws IllegalArgumentException if {@code obj} couldn't be rewritten or + * if {@code toRemove} or {@code toAdd} is null. + **/ + public staticT deepReplaceHeadNamespace(T obj, String toRemove, String toAdd) { + final RewritingProcessor processor = + RewritingProcessor.newRewritingProcessor(toAdd,toRemove); + return processor.rewriteOutput(obj); + } + + /** + * Appends {@code namespace} to {@code path}. + * This methods appends {@code namespace} to {@code path} to obtain a + * a full path, and normalizes the result thus obtained: + * + *
+ * @param path a name space path prefix + * @param namespace a name space name to append to the path + * @return a syntactically valid name space path, or "" if both parameters + * are null or empty. + * @throws IllegalArgumentException if either argument is null or ends with + * an odd number of {@code /} characters. + **/ + public static String concat(String path, String namespace) { + if (path == null || namespace == null) + throw new IllegalArgumentException("Null argument"); + checkTrailingSlashes(path); + checkTrailingSlashes(namespace); + final String result; + if (path.equals("")) result=namespace; + else if (namespace.equals("")) result=path; + else result=path+NAMESPACE_SEPARATOR+namespace; + return ObjectNameRouter.normalizeNamespacePath(result,false,true,false); + } + + /** + * Returns a syntactically valid name space path. + * If the provided {@code namespace} ends with {@code "//"}, + * recursively strips trailing {@code "//"}. Each sequence of an + * even number of {@code "/"} characters is also replaced by {@code "//"}, + * for example {@code "foo//bar////baz/////buh"} will become + * {@code "foo//bar//baz///buh"}. + * + * @param namespace A name space path + * @return {@code ""} - if the provided {@code namespace} resolves to + * the empty string; otherwise a syntactically valid name space string + * stripped of trailing and redundant {@code "//"}. + * @throws IllegalArgumentException if {@code namespace} is null or + * is not syntactically valid (e.g. it contains + * invalid characters like ':', or it ends with an odd + * number of '/'). + */ + public static String normalizeNamespaceName(String namespace) { + if (namespace == null) + throw new IllegalArgumentException("Null namespace"); + final String sourcePath = + ObjectNameRouter.normalizeNamespacePath(namespace,false,true,false); + if (sourcePath.equals("")) return sourcePath; + + // Will throw an IllegalArgumentException if the namespace name + // is not syntactically valid... + // + getNamespaceObjectName(sourcePath); + return sourcePath; + } + + + /** + * Return a canonical handler name for the provided {@code namespace}, + * The handler name returned will be + * {@link #normalizeNamespaceName normalizeNamespaceName}{@code (namespace) + + * "//:type=JMXNamespace"}. + * + * @param namespace A name space path + * @return a canonical ObjectName for a name space handler. + * @see #normalizeNamespaceName + * @throws IllegalArgumentException if the provided + * {@code namespace} is null or not valid. + */ + public static ObjectName getNamespaceObjectName(String namespace) { + if (namespace == null || namespace.equals("")) + throw new IllegalArgumentException("Null or empty namespace"); + final String sourcePath = + ObjectNameRouter.normalizeNamespacePath(namespace,false, + true,false); + try { + return ObjectName.getInstance(sourcePath+ + NAMESPACE_SEPARATOR+":"+ + JMXNamespace.TYPE_ASSIGNMENT); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(namespace,x); + } + } + + /** + * Returns an ObjectName pattern that can be used to query for all MBeans + * contained in the given name space. + * For instance, if {@code namespace="foo//bar"}, this method will + * return {@code "foo//bar//*:*"} + * @return an ObjectName pattern that selects all MBeans in the given + * name space. + **/ + public static ObjectName getWildcardFor(String namespace) { + return insertPath(namespace,ObjectName.WILDCARD); + } + + + /** + * Returns an ObjectName that can be used to access an MBean + * contained in the given name space. + * For instance, if {@code path="foo//bar"}, and + * {@code to="domain:type=Thing"} this method will + * return {@code "foo//bar//domain:type=Thing"} + * @return an ObjectName that can be used to invoke an MBean located in a + * sub name space. + * @throws IllegalArgumentException if {@code path} ends with an + * odd number of {@code /} characters. + **/ + public static ObjectName insertPath(String path, ObjectName to) { + if (path == null || to == null) + throw new IllegalArgumentException("Null argument"); + checkTrailingSlashes(path); + try { + String prefix = path; + if (!prefix.equals("")) prefix = + ObjectNameRouter.normalizeNamespacePath( + prefix + NAMESPACE_SEPARATOR,false,false,false); + return to.withDomain( + ObjectNameRouter.normalizeDomain( + prefix+to.getDomain(),false)); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(path+": "+x,x); + } + } + + /** + * Returns the normalized name space path of the name space expected to + * contain {@code ObjectName}. + * For instance, for {@code "foo//domain:type=Thing"} this will be + * {@code "foo"}. For {@code "//foo//bar//domain:type=Thing"} this will be + * {@code "foo//bar"}. For {@code //foo//bar//baz//domain:type=Thing} + * this will be {@code "foo//bar//baz"}. For + * {@code //foo//bar//baz//:type=JMXNamespace} + * this will be {@code "foo//bar"}. + * + * @param name an {@code ObjectName} + * @return the name space path of the name space that could contain such + * a name. If {@code name} has no name space, returns {@code ""}. + * @throws IllegalArgumentException if {@code name} is null. + **/ + public static String getContainingNamespace(ObjectName name) { + return getNormalizedPath(name,true); + } + + + static String getNormalizedPath(ObjectName name, + boolean removeLeadingSep) { + if (name == null) + throw new IllegalArgumentException("Null name"); + String domain = + ObjectNameRouter.normalizeDomain(name.getDomain(),removeLeadingSep); + int end = domain.length(); + + // special case of domain part being a single '/' + // + if (domain.endsWith(NAMESPACE_SEPARATOR+"/")) + return domain.substring(0,end-NAMESPACE_SEPARATOR_LENGTH-1); + + // special case of namespace handler + // + if (domain.endsWith(NAMESPACE_SEPARATOR)) + domain = domain.substring(0,end-NAMESPACE_SEPARATOR_LENGTH); + + int last = domain.lastIndexOf(NAMESPACE_SEPARATOR); + if (last < 0) return ""; + if (last == 0) return domain; + + // special case of domain part starting with '/' + // last=0 is not possible - we took care of this above. + if (domain.charAt(last-1) == '/') last--; + + return domain.substring(0,last); + } + + private static void checkTrailingSlashes(String path) { + int i; + for (i = path.length() - 1; i >= 0 && path.charAt(i) == '/'; i--) + continue; + if (path.length() - i % 2 == 0) + throw new IllegalArgumentException("Path ends with odd number of /"); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,837 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.namespace.JMXNamespaceUtils; +import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe; +import com.sun.jmx.remote.util.EnvHelp; + +import java.io.IOException; +import java.security.AccessControlException; +import java.util.HashMap; +import java.util.Map; +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.MBeanPermission; +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.ObjectName; +import javax.management.event.EventClient; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +/** + * A {@link JMXNamespace} that will connect to a remote MBeanServer + * by creating a {@link javax.management.remote.JMXConnector} from a + * {@link javax.management.remote.JMXServiceURL}. + *- If {@code path} is empty, the full path is + * {@code namespace}.
+ *- Otherwise, if {@code namespace} is empty, + * the full path is {@code path}
+ *- Otherwise, and this is the regular case, the full path is the + * result of the concatenation of + * {@code path}+{@value #NAMESPACE_SEPARATOR}+{@code namespace}
+ *- finally, the full path is normalized: multiple consecutive + * occurrences of {@value #NAMESPACE_SEPARATOR} are replaced by a + * single {@value #NAMESPACE_SEPARATOR} in the result, and trailing + * occurences of {@value #NAMESPACE_SEPARATOR} are removed. + *
+ *+ * You can call {@link #connect() connect()} and {@link #close close()} + * several times. This MBean will emit an {@link AttributeChangeNotification} + * when the value of its {@link #isConnected Connected} attribute changes. + *
+ *+ * The JMX Remote Namespace MBean is not connected until {@link + * #connect() connect()} is explicitly called. The usual sequence of code to + * create a JMX Remote Namespace is thus: + *
+ *+ * final String namespace = "mynamespace"; + * final ObjectName name = {@link JMXNamespaces#getNamespaceObjectName + * JMXNamespaces.getNamespaceObjectName(namespace)}; + * final JMXServiceURL remoteServerURL = .... ; + * final Map+ *optionsMap = .... ; + * final MBeanServer masterMBeanServer = .... ; + * final JMXRemoteNamespace namespaceMBean = {@link #newJMXRemoteNamespace + * JMXRemoteNamespace.newJMXRemoteNamespace(remoteServerURL, optionsMap)}; + * masterMBeanServer.registerMBean(namespaceMBean, name); + * namespaceMBean.connect(); + * // or: masterMBeanServer.invoke(name, {@link #connect() "connect"}, null, null); + * + * The JMX Remote Namespace MBean will register for {@linkplain + * JMXConnectionNotification JMX Connection Notifications} with its underlying + * {@link JMXConnector}. When a JMX Connection Notification indicates that + * the underlying connection has failed, the JMX Remote Namespace MBean + * closes its underlying connector and switches its {@link #isConnected + * Connected} attribute to false, emitting an {@link + * AttributeChangeNotification}. + *
+ *+ * At this point, a managing application (or an administrator connected + * through a management console) can attempt to reconnect the + * JMX Remote Namespace MBean by calling its {@link #connect() connect()} method + * again. + *
+ *Note that when the connection with the remote namespace fails, or when + * {@link #close} is called, then any notification subscription to + * MBeans registered in that namespace will be lost - unless a custom + * {@linkplain javax.management.event event service} supporting connection-less + * mode was used. + *
+ * @since 1.7 + */ +public class JMXRemoteNamespace + extends JMXNamespace + implements JMXRemoteNamespaceMBean, NotificationEmitter { + + /** + * A logger for this class. + */ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final Logger PROBE_LOG = Logger.getLogger( + JmxProperties.NAMESPACE_LOGGER_NAME+".probe"); + + + // This connection listener is used to listen for connection events from + // the underlying JMXConnector. It is used in particular to maintain the + // "connected" state in this MBean. + // + private static class ConnectionListener implements NotificationListener { + private final JMXRemoteNamespace handler; + private ConnectionListener(JMXRemoteNamespace handler) { + this.handler = handler; + } + public void handleNotification(Notification notification, + Object handback) { + if (!(notification instanceof JMXConnectionNotification)) + return; + final JMXConnectionNotification cn = + (JMXConnectionNotification)notification; + handler.checkState(this,cn,(JMXConnector)handback); + } + } + + // When the JMXRemoteNamespace is originally created, it is not connected, + // which means that the source MBeanServer should be one that throws + // exceptions for most methods. When it is subsequently connected, + // the methods should be forwarded to the MBeanServerConnection. + // We handle this using MBeanServerConnectionWrapper. The + // MBeanServerConnection that is supplied to the constructor of + // MBeanServerConnectionWrapper is ignored (and in fact it is null) + // because the one that is actually used is the one supplied by the + // override of getMBeanServerConnection(). + private static class JMXRemoteNamespaceDelegate + extends MBeanServerConnectionWrapper + implements DynamicProbe { + private volatile JMXRemoteNamespace parent=null; + + JMXRemoteNamespaceDelegate() { + super(null,null); + } + @Override + public MBeanServerConnection getMBeanServerConnection() { + return parent.getMBeanServerConnection(); + } + @Override + public ClassLoader getDefaultClassLoader() { + return parent.getDefaultClassLoader(); + } + + // Because this class is instantiated in the super() call from the + // constructor of JMXRemoteNamespace, it cannot be an inner class. + // This method achieves the effect that an inner class would have + // had, of giving the class a reference to the outer "this". + synchronized void initParentOnce(JMXRemoteNamespace parent) { + if (this.parent != null) + throw new UnsupportedOperationException("parent already set"); + this.parent=parent; + + } + + public boolean isProbeRequested() { + return this.parent.isProbeRequested(); + } + } + + private static final MBeanNotificationInfo connectNotification = + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + "Connected", + "Emitted when the Connected state of this object changes"); + + private static long seqNumber=0; + + private final NotificationBroadcasterSupport broadcaster; + private final ConnectionListener listener; + private final JMXServiceURL jmxURL; + private final MapoptionsMap; + + private volatile MBeanServerConnection server = null; + private volatile JMXConnector conn = null; + private volatile ClassLoader defaultClassLoader = null; + private volatile boolean probed; + + /** + * Creates a new instance of {@code JMXRemoteNamespace}. + * + * This constructor is provided for subclasses. + * To create a new instance of {@code JMXRemoteNamespace} call + * {@link #newJMXRemoteNamespace + * JMXRemoteNamespace.newJMXRemoteNamespace(sourceURL, optionsMap)}. + *
+ * @param sourceURL a JMX service URL that can be used to {@linkplain + * #connect() connect} to the + * source MBean Server. The source MBean Server is the remote + * MBean Server which contains the MBeans that will be mirrored + * in this namespace. + * @param optionsMap the options map that will be passed to the + * {@link JMXConnectorFactory} when {@linkplain + * JMXConnectorFactory#newJMXConnector creating} the + * {@link JMXConnector} used to {@linkplain #connect() connect} + * to the remote source MBean Server. Can be null, which is + * equivalent to an empty map. + * @see #newJMXRemoteNamespace JMXRemoteNamespace.newJMXRemoteNamespace + * @see #connect + */ + protected JMXRemoteNamespace(JMXServiceURL sourceURL, + MapoptionsMap) { + super(new JMXRemoteNamespaceDelegate()); + ((JMXRemoteNamespaceDelegate)super.getSourceServer()). + initParentOnce(this); + + // URL must not be null. + this.jmxURL = JMXNamespaceUtils.checkNonNull(sourceURL,"url"); + this.broadcaster = + new NotificationBroadcasterSupport(connectNotification); + + // handles options + this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap); + + // handles (dis)connection events + this.listener = new ConnectionListener(this); + + // XXX TODO: remove the probe, or simplify it. + this.probed = false; + } + + /** + * Returns the {@code JMXServiceURL} that is (or will be) used to + * connect to the remote name space. + * @see #connect + * @return The {@code JMXServiceURL} used to connect to the remote + * name space. + */ + public JMXServiceURL getJMXServiceURL() { + return jmxURL; + } + + /** + * In this class, this method never returns {@code null}, and the + * address returned is the {@link #getJMXServiceURL JMXServiceURL} + * that is used by this object to {@linkplain #connect} to the remote + * name space.
+ * This behaviour might be overriden by subclasses, if needed. + * For instance, a subclass might want to return {@code null} if it + * doesn't want to expose that JMXServiceURL. + */ + public JMXServiceURL getAddress() { + return getJMXServiceURL(); + } + + private Map
+ *getEnvMap() { + return optionsMap; + } + + boolean isProbeRequested() { + return probed==false; + } + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) { + broadcaster.addNotificationListener(listener, filter, handback); + } + + /** + * A subclass that needs to send its own notifications must override + * this method in order to return an {@link MBeanNotificationInfo + * MBeanNotificationInfo[]} array containing both its own notification + * infos and the notification infos of its super class. + * The implementation should probably look like: + *
+ * final MBeanNotificationInfo[] myOwnNotifs = { .... }; + * final MBeanNotificationInfo[] parentNotifs = + * super.getNotificationInfo(); + * final Set+ */ + public MBeanNotificationInfo[] getNotificationInfo() { + return broadcaster.getNotificationInfo(); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener, filter, handback); + } + + private static synchronized long getNextSeqNumber() { + return seqNumber++; + } + + + /** + * Sends a notification to registered listeners. Before the notification + * is sent, the following steps are performed: + *mergedResult = + * new HashSet (); + * mergedResult.addAll(Arrays.asList(myOwnNotifs)); + * mergedResult.addAll(Arrays.asList(parentNotifs)); + * return mergeResult.toArray( + * new MBeanNotificationInfo[mergedResult.size()]); + * + *
- + * If {@code n.getSequenceNumber() <= 0} set it to the next available + * sequence number.
+ *- If {@code n.getSource() == null}, set it to the value returned by {@link + * #getObjectName getObjectName()}. + *
This method can be called by subclasses in order to send their own + * notifications. + * In that case, these subclasses might also need to override + * {@link #getNotificationInfo} in order to declare their own + * {@linkplain MBeanNotificationInfo notification types}. + *
+ * @param n The notification to send to registered listeners. + * @see javax.management.NotificationBroadcasterSupport + * @see #getNotificationInfo + **/ + protected void sendNotification(Notification n) { + if (n.getSequenceNumber()<=0) + n.setSequenceNumber(getNextSeqNumber()); + if (n.getSource()==null) + n.setSource(getObjectName()); + broadcaster.sendNotification(n); + } + + private void checkState(ConnectionListener listener, + JMXConnectionNotification cn, + JMXConnector emittingConnector) { + + // Due to the asynchronous handling of notifications, it is + // possible that this method is called for a JMXConnector + // (or connection) which is already closed and replaced by a newer + // one. + // + // This method attempts to determine the real state of the + // connection - which might be different from what the notification + // says. + // + // This is quite complex logic - because we try not to hold any + // lock while evaluating the true value of the connected state, + // while anyone might also call close() or connect() from a + // different thread. + // + // The method switchConnection() (called from here too) also has the + // same kind of complex logic. + // + // We use the JMXConnector has a handback to the notification listener + // (emittingConnector) in order to be able to determine whether the + // notification concerns the current connector in use, or an older + // one. + // + boolean remove = false; + + // whether the emittingConnector is already 'removed' + synchronized (this) { + if (this.conn != emittingConnector || + JMXConnectionNotification.FAILED.equals(cn.getType())) + remove = true; + } + + // We need to unregister our listener from this 'removed' connector. + // This is the only place where we remove the listener. + // + if (remove) { + try { + // This may fail if the connector is already closed. + // But better unregister anyway... + // + emittingConnector.removeConnectionNotificationListener( + listener,null, + emittingConnector); + } catch (Exception x) { + LOG.log(Level.FINE, + "Failed to unregister connection listener"+x); + LOG.log(Level.FINEST, + "Failed to unregister connection listener",x); + } + try { + // This may fail if the connector is already closed. + // But better call close twice and get an exception than + // leaking... + // + emittingConnector.close(); + } catch (Exception x) { + LOG.log(Level.FINEST, + "Failed to close old connector " + + "(failure was expected): "+x); + } + } + + // Now we checked whether our current connector is still alive. + // + boolean closed = false; + final JMXConnector thisconn = this.conn; + try { + if (thisconn != null) + thisconn.getConnectionId(); + } catch (IOException x) { + LOG.finest("Connector already closed: "+x); + closed = true; + } + + // We got an IOException - the connector is not connected. + // Need to forget it and switch our state to closed. + // + if (closed) { + switchConnection(thisconn,null,null); + try { + // Usually this will fail... Better call close twice + // and get an exception than leaking... + // + if (thisconn != emittingConnector || !remove) + thisconn.close(); + } catch (IOException x) { + LOG.log(Level.FINEST, + "Failed to close connector (failure was expected): " + +x); + } + } + } + + private final void switchConnection(JMXConnector oldc, + JMXConnector newc, + MBeanServerConnection mbs) { + boolean connect = false; + boolean close = false; + synchronized (this) { + if (oldc != conn) { + if (newc != null) { + try { + newc.close(); + } catch (IOException x) { + LOG.log(Level.FINEST, + "Failed to close connector",x); + } + } + return; + } + if (conn == null && newc != null) connect=true; + if (newc == null && conn != null) close = true; + conn = newc; + server = mbs; + } + if (connect || close) { + boolean oldstate = close; + boolean newstate = connect; + final ObjectName myName = getObjectName(); + + // In the uncommon case where the MBean is connected before + // being registered, myName can be null... + // If myName is null - we use 'this' as the source instead... + // + final Object source = (myName==null)?this:myName; + final AttributeChangeNotification acn = + new AttributeChangeNotification(source, + getNextSeqNumber(),System.currentTimeMillis(), + String.valueOf(source)+ + (newstate?" connected":" closed"), + "Connected", + "boolean", + Boolean.valueOf(oldstate), + Boolean.valueOf(newstate)); + sendNotification(acn); + } + } + + private void closeall(JMXConnector... a) { + for (JMXConnector c : a) { + try { + if (c != null) c.close(); + } catch (Exception x) { + // OK: we're gonna throw the original exception later. + LOG.finest("Ignoring exception when closing connector: "+x); + } + } + } + + JMXConnector connect(JMXServiceURL url, Mapenv) + throws IOException { + final JMXConnector c = newJMXConnector(jmxURL, env); + c.connect(env); + return c; + } + + /** + * Creates a new JMXConnector with the specified {@code url} and + * {@code env} options map. + * + * This method first calls {@link JMXConnectorFactory#newJMXConnector + * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new + * JMX connector, and returns that. + *
+ *+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation + * that connects to a sub namespace of the remote server by subclassing + * this class in the following way: + *
+ * class JMXRemoteSubNamespace extends JMXRemoteNamespace { + * private final String subnamespace; + * JMXRemoteSubNamespace(JMXServiceURL url, + * Map{@code+ *} env, String subnamespace) { + * super(url,options); + * this.subnamespace = subnamespace; + * } + * protected JMXConnector newJMXConnector(JMXServiceURL url, + * Map env) throws IOException { + * final JMXConnector inner = super.newJMXConnector(url,env); + * return {@link JMXNamespaces#narrowToNamespace(JMXConnector,String) + * JMXNamespaces.narrowToNamespace(inner,subnamespace)}; + * } + * } + * + * Some connectors, like the JMXMP connector server defined by the + * version 1.2 of the JMX API may not have been upgraded to use the + * new {@linkplain javax.management.event Event Service} defined in this + * version of the JMX API. + *
+ * In that case, and if the remote server to which this JMXRemoteNamespace + * connects also contains namespaces, it may be necessary to configure + * explicitly an {@linkplain + * javax.management.event.EventClientDelegate#newForwarder() + * Event Client Forwarder} on the remote server side, and to force the use + * of an {@link EventClient} on this client side. + *
+ *
+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation + * of {@code newJMXConnector} that will force notification subscriptions + * to flow through an {@link EventClient} over a legacy protocol by + * overriding this method in the following way: + *+ * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace { + * JMXRemoteSubNamespaceConnector(JMXServiceURL url, + * Map+ *env) { + * super(url,options); + * } + * protected JMXConnector newJMXConnector(JMXServiceURL url, + * Map env) throws IOException { + * final JMXConnector inner = super.newJMXConnector(url,env); + * return {@link EventClient#withEventClient( + * JMXConnector) EventClient.withEventClient(inner)}; + * } + * } + * + * Note that the remote server also needs to provide an {@link + * javax.management.event.EventClientDelegateMBean}: only configuring + * the client side (this object) is not enough.
+ * @param url The JMXServiceURL of the remote server. + * @param optionsMap An unmodifiable options map that will be passed to the + * {@link JMXConnectorFactory} when {@linkplain + * JMXConnectorFactory#newJMXConnector creating} the + * {@link JMXConnector} that can connect to the remote source + * MBean Server. + * @return An unconnected JMXConnector to use to connect to the remote + * server + * @throws java.io.IOException if the connector could not be created. + * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map) + * @see #JMXRemoteNamespace + */ + protected JMXConnector newJMXConnector(JMXServiceURL url, + Map
+ * In summary, this technique should be used if the remote server + * supports JMX namespaces, but uses a JMX Connector Server whose + * implementation does not transparently use the new Event Service + * (as would be the case with the JMXMPConnectorServer implementation + * from the reference implementation of the JMX Remote API 1.0 + * specification). + *optionsMap) throws IOException { + final JMXConnector c = + JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap); +// TODO: uncomment this when contexts are added +// return ClientContext.withDynamicContext(c); + return c; + } + + public void connect() throws IOException { + if (conn != null) { + try { + // This is much too fragile. It must go away! + PROBE_LOG.finest("Probing again..."); + triggerProbe(getMBeanServerConnection()); + } catch(Exception x) { + close(); + Throwable cause = x; + // if the cause is a security exception - rethrows it... + while (cause != null) { + if (cause instanceof SecurityException) + throw (SecurityException) cause; + cause = cause.getCause(); + } + throw new IOException("connection failed: cycle?",x); + } + } + LOG.fine("connecting..."); + // TODO remove these traces + // System.err.println(getInitParameter()+" connecting"); + final Map env = + new HashMap (getEnvMap()); + try { + // XXX: We should probably document this... + // This allows to specify a loader name - which will be + // retrieved from the paret MBeanServer. + defaultClassLoader = + EnvHelp.resolveServerClassLoader(env,getMBeanServer()); + } catch (InstanceNotFoundException x) { + final IOException io = + new IOException("ClassLoader not found"); + io.initCause(x); + throw io; + } + env.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,defaultClassLoader); + final JMXServiceURL url = getJMXServiceURL(); + final JMXConnector aconn = connect(url,env); + final MBeanServerConnection msc; + try { + msc = aconn.getMBeanServerConnection(); + aconn.addConnectionNotificationListener(listener,null,aconn); + } catch (IOException io) { + closeall(aconn); + throw io; + } catch (RuntimeException x) { + closeall(aconn); + throw x; + } + + + // XXX Revisit here + // Note from the author: This business of switching connection is + // incredibly complex. Isn't there any means to simplify it? + // + switchConnection(conn,aconn,msc); + try { + triggerProbe(msc); + } catch(Exception x) { + close(); + Throwable cause = x; + // if the cause is a security exception - rethrows it... + while (cause != null) { + if (cause instanceof SecurityException) + throw (SecurityException) cause; + cause = cause.getCause(); + } + throw new IOException("connection failed: cycle?",x); + } + LOG.fine("connected."); + } + + // If this is a self-linking namespace, this method should trigger + // the emission of a probe in the wrapping NamespaceInterceptor. + // The first call to source() in the wrapping NamespaceInterceptor + // causes the emission of the probe. + // + // Note: the MBeanServer returned by getSourceServer + // (our private JMXRemoteNamespaceDelegate inner class) + // implements a sun private interface (DynamicProbe) which is + // used by the NamespaceInterceptor to determine whether it should + // send a probe or not. + // We needed this interface here because the NamespaceInterceptor + // has otherwise no means to knows that this object has just + // connected, and that a new probe should be sent. + // + // Probes work this way: the NamespaceInterceptor sets a flag and sends + // a queryNames() request. If a queryNames() request comes in when the flag + // is on, then it deduces that there is a self-linking loop - and instead + // of calling queryNames() on the JMXNamespace (which would cause the + // loop to go on) it breaks the recursion by returning the probe ObjectName. + // If the NamespaceInterceptor receives the probe ObjectName as result of + // its original queryNames() it knows that it has been looping back on + // itslef and throws an Exception - which will be raised through this + // method, thus preventing the connection to be established... + // + // More info in the com.sun.jmx.namespace.NamespaceInterceptor class + // + // XXX: TODO this probe thing is way too complex and fragile. + // This *must* go away or be replaced by something simpler. + // ideas are welcomed. + // + private void triggerProbe(final MBeanServerConnection msc) + throws MalformedObjectNameException, IOException { + // Query Pattern that we will send through the source server in order + // to detect self-linking namespaces. + // + // + final ObjectName pattern; + pattern = ObjectName.getInstance("*" + + JMXNamespaces.NAMESPACE_SEPARATOR + ":" + + JMXNamespace.TYPE_ASSIGNMENT); + probed = false; + try { + msc.queryNames(pattern, null); + probed = true; + } catch (AccessControlException x) { + // if we have an MBeanPermission missing then do nothing... + if (!(x.getPermission() instanceof MBeanPermission)) + throw x; + PROBE_LOG.finer("Can't check for cycles: " + x); + probed = false; // no need to do it again... + } + } + + public void close() throws IOException { + if (conn == null) return; + LOG.fine("closing..."); + // System.err.println(toString()+": closing..."); + conn.close(); + // System.err.println(toString()+": connector closed"); + switchConnection(conn,null,null); + LOG.fine("closed."); + // System.err.println(toString()+": closed"); + } + + MBeanServerConnection getMBeanServerConnection() { + if (conn == null) + throw newRuntimeIOException("getMBeanServerConnection: not connected"); + return server; + } + + // Better than throwing UndeclaredThrowableException ... + private RuntimeException newRuntimeIOException(String msg) { + final IllegalStateException illegal = new IllegalStateException(msg); + return Util.newRuntimeIOException(new IOException(msg,illegal)); + } + + /** + * Returns the default class loader used by the underlying + * {@link JMXConnector}. + * @return the default class loader used when communicating with the + * remote source MBean server. + **/ + ClassLoader getDefaultClassLoader() { + if (conn == null) + throw newRuntimeIOException("getMBeanServerConnection: not connected"); + return defaultClassLoader; + } + + public boolean isConnected() { + // This is a pleonasm + return (conn != null) && (server != null); + } + + + /** + * This name space handler will automatically {@link #close} its + * connection with the remote source in {@code preDeregister}. + **/ + @Override + public void preDeregister() throws Exception { + try { + close(); + } catch (IOException x) { + LOG.fine("Failed to close properly - exception ignored: " + x); + LOG.log(Level.FINEST, + "Failed to close properly - exception ignored",x); + } + super.preDeregister(); + } + + /** + * This method calls {@link + * javax.management.MBeanServerConnection#getMBeanCount + * getMBeanCount()} on the remote namespace. + * @throws java.io.IOException if an {@link IOException} is raised when + * communicating with the remote source namespace. + */ + @Override + public Integer getMBeanCount() throws IOException { + return getMBeanServerConnection().getMBeanCount(); + } + + /** + * This method returns the result of calling {@link + * javax.management.MBeanServerConnection#getDomains + * getDomains()} on the remote namespace. + * @throws java.io.IOException if an {@link IOException} is raised when + * communicating with the remote source namespace. + */ + @Override + public String[] getDomains() throws IOException { + return getMBeanServerConnection().getDomains(); + } + + /** + * This method returns the result of calling {@link + * javax.management.MBeanServerConnection#getDefaultDomain + * getDefaultDomain()} on the remote namespace. + * @throws java.io.IOException if an {@link IOException} is raised when + * communicating with the remote source namespace. + */ + @Override + public String getDefaultDomain() throws IOException { + return getMBeanServerConnection().getDefaultDomain(); + } + + /** + * Creates a new instance of {@code JMXRemoteNamespace}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean Server. The source MBean Server is the remote + * MBean Server which contains the MBeans that will be mirrored + * in this namespace. + * @param optionsMap An options map that will be passed to the + * {@link JMXConnectorFactory} when {@linkplain + * JMXConnectorFactory#newJMXConnector creating} the + * {@link JMXConnector} used to connect to the remote source + * MBean Server. Can be null, which is equivalent to an empty map. + * @see #JMXRemoteNamespace JMXRemoteNamespace(sourceURL,optionsMap) + * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map) + */ + public static JMXRemoteNamespace newJMXRemoteNamespace( + JMXServiceURL sourceURL, + Map optionsMap) { + return new JMXRemoteNamespace(sourceURL, optionsMap); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import java.io.IOException; +import javax.management.remote.JMXServiceURL; + +/** + * A {@link JMXNamespaceMBean} that will connect to a remote MBeanServer + * by creating a {@link javax.management.remote.JMXConnector} from a + * {@link javax.management.remote.JMXServiceURL}. + * You can call {@link #connect connect()} and {@link #close close()} + * several times. + * @since 1.7 + */ +public interface JMXRemoteNamespaceMBean + extends JMXNamespaceMBean { + + /** + * Connects to the underlying remote source name space, if not already + * {@link #isConnected connected}. + * If connected, do nothing. Otherwise, creates a new connector from the + * {@link javax.management.remote.JMXServiceURL JMXServiceURL} provided at + * creation time, and connects to the remote source name space. + * + * The source MBeans will not appear in the target name space until the + * JMXRemoteNamespaceMBean is connected. + *
+ * It is possible to call {@code connect()}, {@link #close close()}, and + * {@code connect()} again. + * However, closing the connection with the remote name space may cause + * notification listeners to be lost, unless the client explicitly uses + * the new {@linkplain javax.management.event JMX event service}. + *
+ * @throws IOException if connection to the remote source name space fails. + * @see #isConnected isConnected + **/ + public void connect() + throws IOException; + + /** + * Closes the connection with the remote source name space. + * If the connection is already closed, do nothing. + * Otherwise, closes the underlying {@link + * javax.management.remote.JMXConnector}. + *
Once closed, it is possible to reopen the connection by + * calling {@link #connect connect}. + *
+ * @throws IOException if the connection to the remote source name space + * can't be closed properly. + * @see #isConnected isConnected + **/ + public void close() + throws IOException; + + /** + * Tells whether the connection to the remote source name space is opened. + * @see #connect connect + * @see #close close + * @return {@code true} if connected. + **/ + public boolean isConnected(); + + /** + * Returns the {@link JMXServiceURL} address that points to the remote name + * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean}, + * if available. + * @return The {@link JMXServiceURL} address that points to the remote name + * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean}, + * or {@code null}. + */ + public JMXServiceURL getAddress(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,703 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.security.AccessController; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.loading.ClassLoaderRepository; + +/** + *An object of this class implements the MBeanServer interface + * and, for each of its methods forwards the request to a wrapped + * {@link MBeanServerConnection} object. + * Some methods of the {@link MBeanServer} interface do not have + * any equivalent in {@link MBeanServerConnection}. In that case, an + * {@link UnsupportedOperationException} will be thrown. + * + *
A typical use of this class is to apply a {@link QueryExp} object locally, + * on an MBean that resides in a remote MBeanServer. Since an + * MBeanServerConnection is not an MBeanServer, it cannot be passed + * to the
+ * + * @since 1.7 + */ +public class MBeanServerConnectionWrapper + implements MBeanServer { + + private final MBeanServerConnection wrapped; + private final ClassLoader defaultCl; + + /** + * Construct a new object that implements {@link MBeanServer} by + * forwarding its methods to the given {@link MBeanServerConnection}. + * This constructor is equivalent to {@link #MBeanServerConnectionWrapper( + * MBeanServerConnection, ClassLoader) MBeanServerConnectionWrapper(wrapped, + * null)}. + * + * @param wrapped the {@link MBeanServerConnection} to which methods + * are to be forwarded. This parameter can be null, in which case the + * {@code MBeanServerConnection} will typically be supplied by overriding + * {@link #getMBeanServerConnection}. + */ + public MBeanServerConnectionWrapper(MBeanServerConnection wrapped) { + this(wrapped, null); + } + + /** + * Construct a new object that implements {@link MBeanServer} by + * forwarding its methods to the given {@link MBeanServerConnection}. + * The {@code defaultCl} parameter specifies the value to be returned + * by {@link #getDefaultClassLoader}. A null value is equivalent to + * {@link Thread#getContextClassLoader()}. + * + * @param wrapped the {@link MBeanServerConnection} to which methods + * are to be forwarded. This parameter can be null, in which case the + * {@code MBeanServerConnection} will typically be supplied by overriding + * {@link #getMBeanServerConnection}. + * @param defaultCl the value to be returned by {@link + * #getDefaultClassLoader}. A null value is equivalent to the current + * thread's {@linkplain Thread#getContextClassLoader()}. + */ + public MBeanServerConnectionWrapper(MBeanServerConnection wrapped, + ClassLoader defaultCl) { + this.wrapped = wrapped; + this.defaultCl = (defaultCl == null) ? + Thread.currentThread().getContextClassLoader() : defaultCl; + } + + /** + * Returns an MBeanServerConnection. This method is called each time + * an operation must be invoked on the underlying MBeanServerConnection. + * The default implementation returns the MBeanServerConnection that + * was supplied to the constructor of this MBeanServerConnectionWrapper. + **/ + protected MBeanServerConnection getMBeanServerConnection() { + return wrapped; + } + + /** + * Returns the default class loader passed to the constructor. If the + * value passed was null, then the returned value will be the + * {@linkplain Thread#getContextClassLoader() context class loader} at the + * time this object was constructed. + * + * @return the ClassLoader that was passed to the constructor. + **/ + public ClassLoader getDefaultClassLoader() { + return defaultCl; + } + + /** + *setMBeanServer()
method of the {@link QueryExp} + * object. However, this object can.This method is called each time an IOException is raised when + * trying to forward an operation to the underlying + * MBeanServerConnection, as a result of calling + * {@link #getMBeanServerConnection()} or as a result of invoking the + * operation on the returned connection. Since the methods in + * {@link MBeanServer} are not declared to throw {@code IOException}, + * this method must return a {@code RuntimeException} to be thrown + * instead. Typically, the original {@code IOException} will be in the + * {@linkplain Throwable#getCause() cause chain} of the {@code + * RuntimeException}.
+ * + *Subclasses may redefine this method if they need to perform any + * specific handling of IOException (logging etc...).
+ * + * @param x The raised IOException. + * @param method The name of the method in which the exception was + * raised. This is one of the methods of the MBeanServer + * interface. + * + * @return A RuntimeException that should be thrown by the caller. + * In this default implementation, this is a + * {@link RuntimeException} wrapping x. + **/ + protected RuntimeException wrapIOException(IOException x, String method) { + return Util.newRuntimeIOException(x); + } + + // Take care of getMBeanServerConnection returning null. + // + private synchronized MBeanServerConnection connection() + throws IOException { + final MBeanServerConnection c = getMBeanServerConnection(); + if (c == null) + throw new IOException("MBeanServerConnection unavailable"); + return c; + } + + //-------------------------------------------- + //-------------------------------------------- + // + // Implementation of the MBeanServer interface + // + //-------------------------------------------- + //-------------------------------------------- + + /** + * Forward this method to the + * wrapped object. + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + connection().addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"addNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + connection().addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"addNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, ObjectName name) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return connection().createMBean(className, name); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return connection().createMBean(className, name, + params, signature); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return connection().createMBean(className, name, loaderName); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + Object params[], + String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return connection().createMBean(className, name, loaderName, + params, signature); + } catch (IOException x) { + throw wrapIOException(x,"createMBean"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(String,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, + byte[] data) + throws + InstanceNotFoundException, + OperationsException, + ReflectionException { + throw new UnsupportedOperationException("deserialize"); + } + + /** + * Forward this method to the + * wrapped object. + */ + public Object getAttribute(ObjectName name, String attribute) + throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException { + try { + return connection().getAttribute(name, attribute); + } catch (IOException x) { + throw wrapIOException(x,"getAttribute"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return connection().getAttributes(name, attributes); + } catch (IOException x) { + throw wrapIOException(x,"getAttributes"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + throw new UnsupportedOperationException("getClassLoader"); + } + + /** + * Returns the {@linkplain #getDefaultClassLoader() default class loader}. + * This behavior can be changed by subclasses. + */ + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return getDefaultClassLoader(); + } + + /** + *Returns a {@link ClassLoaderRepository} based on the class loader + * returned by {@link #getDefaultClassLoader()}.
+ * @return a {@link ClassLoaderRepository} that contains a single + * class loader, returned by {@link #getDefaultClassLoader()}. + **/ + public ClassLoaderRepository getClassLoaderRepository() { + // We return a new ClassLoaderRepository each time this method is + // called. This is by design, because there's no guarantee that + // getDefaultClassLoader() will always return the same class loader. + return Util.getSingleClassLoaderRepository(getDefaultClassLoader()); + } + + /** + * Forward this method to the + * wrapped object. + */ + public String getDefaultDomain() { + try { + return connection().getDefaultDomain(); + } catch (IOException x) { + throw wrapIOException(x,"getDefaultDomain"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public String[] getDomains() { + try { + return connection().getDomains(); + } catch (IOException x) { + throw wrapIOException(x,"getDomains"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public Integer getMBeanCount() { + try { + return connection().getMBeanCount(); + } catch (IOException x) { + throw wrapIOException(x,"getMBeanCount"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws + InstanceNotFoundException, + IntrospectionException, + ReflectionException { + try { + return connection().getMBeanInfo(name); + } catch (IOException x) { + throw wrapIOException(x,"getMBeanInfo"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + return connection().getObjectInstance(name); + } catch (IOException x) { + throw wrapIOException(x,"getObjectInstance"); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, + Object params[], + String signature[]) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public Object instantiate(String className, ObjectName loaderName, + Object params[], String signature[]) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("instantiate"); + } + + /** + * Forward this method to the + * wrapped object. + */ + public Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws + InstanceNotFoundException, + MBeanException, + ReflectionException { + try { + return connection().invoke(name,operationName,params,signature); + } catch (IOException x) { + throw wrapIOException(x,"invoke"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + return connection().isInstanceOf(name, className); + } catch (IOException x) { + throw wrapIOException(x,"isInstanceOf"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public boolean isRegistered(ObjectName name) { + try { + return connection().isRegistered(name); + } catch (IOException x) { + throw wrapIOException(x,"isRegistered"); + } + } + + /** + * Forward this method to the + * wrapped object. + * If an IOException is raised, returns an empty Set. + */ + public SetqueryMBeans(ObjectName name, QueryExp query) { + try { + return connection().queryMBeans(name, query); + } catch (IOException x) { + throw wrapIOException(x,"queryMBeans"); + //return Collections.emptySet(); + } + } + + /** + * Forward this method to the + * wrapped object. + * If an IOException is raised, returns an empty Set. + */ + public Set queryNames(ObjectName name, QueryExp query) { + try { + return connection().queryNames(name, query); + } catch (IOException x) { + throw wrapIOException(x,"queryNames"); + //return Collections.emptySet(); + } + } + + /** + * Throws an {@link UnsupportedOperationException}. This behavior can + * be changed by subclasses. + */ + public ObjectInstance registerMBean(Object object, ObjectName name) + throws + InstanceAlreadyExistsException, + MBeanRegistrationException, + NotCompliantMBeanException { + throw new UnsupportedOperationException("registerMBean"); + } + + /** + * Forward this method to the + * wrapped object. + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + connection().removeNotificationListener(name, listener); + } catch (IOException x) { + throw wrapIOException(x,"removeNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + connection().removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"removeNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + connection().removeNotificationListener(name, listener); + } catch (IOException x) { + throw wrapIOException(x,"removeNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + connection().removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw wrapIOException(x,"removeNotificationListener"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws + InstanceNotFoundException, + AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException { + try { + connection().setAttribute(name, attribute); + } catch (IOException x) { + throw wrapIOException(x,"setAttribute"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return connection().setAttributes(name, attributes); + } catch (IOException x) { + throw wrapIOException(x,"setAttributes"); + } + } + + /** + * Forward this method to the + * wrapped object. + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + connection().unregisterMBean(name); + } catch (IOException x) { + throw wrapIOException(x,"unregisterMBean"); + } + } + + //---------------- + // PRIVATE METHODS + //---------------- + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,1339 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package javax.management.namespace; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.mbeanserver.Util; +import java.io.ObjectInputStream; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.DynamicWrapperMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.JMRuntimeException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryEval; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.loading.ClassLoaderRepository; + +/** + * Base class for custom implementations of the {@link MBeanServer} + * interface. The commonest use of this class is as the {@linkplain + * JMXNamespace#getSourceServer() source server} for a {@link + * JMXNamespace}, although this class can be used anywhere an {@code + * MBeanServer} instance is required. Note that the usual ways to + * obtain an {@code MBeanServer} instance are either to use {@link + * java.lang.management.ManagementFactory#getPlatformMBeanServer() + * ManagementFactory.getPlatformMBeanServer()} or to use the {@code + * newMBeanServer} or {@code createMBeanServer} methods from {@link + * javax.management.MBeanServerFactory MBeanServerFactory}. {@code + * MBeanServerSupport} is for certain cases where those are not + * appropriate.
+ * + *There are two main use cases for this class: special-purpose MBeanServer implementations, + * and namespaces containing Virtual MBeans. The next + * sections explain these use cases.
+ * + *In the simplest case, a subclass needs to implement only two methods:
+ * + *+ *
+ * + *- + * {@link #getNames getNames} which returns the name of + * all MBeans handled by this {@code MBeanServer}. + *
+ *- + * {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a + * {@link DynamicMBean} that can be used to invoke operations and + * obtain meta data (MBeanInfo) on a given MBean. + *
+ *Subclasses can create such {@link DynamicMBean} MBeans on the fly - for + * instance, using the class {@link javax.management.StandardMBean}, just for + * the duration of an MBeanServer method call.
+ * + *Special-purpose MBeanServer implementations
+ * + *In some cases + * the general-purpose {@code MBeanServer} that you get from + * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not + * appropriate. You might need different security checks, or you might + * want a mock {@code MBeanServer} suitable for use in tests, or you might + * want a simplified and optimized {@code MBeanServer} for a special purpose.
+ * + *As an example of a special-purpose {@code MBeanServer}, the class {@link + * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs + * an {@code MBeanServer} instance every time it filters a notification, + * with just one MBean that represents the notification. Although it could + * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code + * MBeanServer} will be quicker to create, use less memory, and have simpler + * methods that execute faster.
+ * + *Here is an example of a special-purpose {@code MBeanServer} + * implementation that contains exactly one MBean, which is specified at the + * time of creation.
+ * + *+ * public class SingletonMBeanServer extends MBeanServerSupport { + * private final ObjectName objectName; + * private final DynamicMBean mbean; + * + * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) { + * this.objectName = objectName; + * this.mbean = mbean; + * } + * + * @Override + * protected {@code Set+ * + *} {@link #getNames getNames}() { + * return Collections.singleton(objectName); + * } + * + * @Override + * public DynamicMBean {@link #getDynamicMBeanFor + * getDynamicMBeanFor}(ObjectName name) + * throws InstanceNotFoundException { + * if (objectName.equals(name)) + * return mbean; + * else + * throw new InstanceNotFoundException(name); + * } + * } + * Using this class, you could make an {@code MBeanServer} that contains + * a {@link javax.management.timer.Timer Timer} MBean like this:
+ * + *+ * Timer timer = new Timer(); + * DynamicMBean mbean = new {@link javax.management.StandardMBean + * StandardMBean}(timer, TimerMBean.class); + * ObjectName name = new ObjectName("com.example:type=Timer"); + * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean); + *+ * + *When {@code getDynamicMBeanFor} always returns the same object for the + * same name, as here, notifications work in the expected way: if the object + * is a {@link NotificationEmitter} then listeners can be added using + * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) MBeanServer.addNotificationListener}. If + * {@code getDynamicMBeanFor} does not always return the same object for the + * same name, more work is needed to make notifications work, as described + * below.
+ * + *Namespaces containing Virtual MBeans
+ * + *Virtual MBeans are MBeans that do not exist as Java objects, + * except transiently while they are being accessed. This is useful when + * there might be very many of them, or when keeping track of their creation + * and deletion might be expensive or hard. For example, you might have one + * MBean per system process. With an ordinary {@code MBeanServer}, you would + * have to list the system processes in order to create an MBean object for + * each one, and you would have to track the arrival and departure of system + * processes in order to create or delete the corresponding MBeans. With + * Virtual MBeans, you only need the MBean for a given process at the exact + * point where it is referenced with a call such as + * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.
+ * + *Here is an example of an {@code MBeanServer} implementation that has + * one MBean for every system property. The system property {@code "java.home"} + * is represented by the MBean called {@code + * com.example:type=Property,name="java.home"}, with an attribute called + * {@code Value} that is the value of the property.
+ * + *+ * public interface PropertyMBean { + * public String getValue(); + * } + * + * public class PropsMBS extends MBeanServerSupport { + * private static ObjectName newObjectName(String name) { + * try { + * return new ObjectName(name); + * } catch (MalformedObjectNameException e) { + * throw new AssertionError(e); + * } + * } + * + * public static class PropertyImpl implements PropertyMBean { + * private final String name; + * + * public PropertyImpl(String name) { + * this.name = name; + * } + * + * public String getValue() { + * return System.getProperty(name); + * } + * } + * + * @Override + * public DynamicMBean {@link #getDynamicMBeanFor + * getDynamicMBeanFor}(ObjectName name) + * throws InstanceNotFoundException { + * + * // Check that the name is a legal one for a Property MBean + * ObjectName namePattern = newObjectName( + * "com.example:type=Property,name=\"*\""); + * if (!namePattern.apply(name)) + * throw new InstanceNotFoundException(name); + * + * // Extract the name of the property that the MBean corresponds to + * String propName = ObjectName.unquote(name.getKeyProperty("name")); + * if (System.getProperty(propName) == null) + * throw new InstanceNotFoundException(name); + * + * // Construct and return a transient MBean object + * PropertyMBean propMBean = new PropertyImpl(propName); + * return new StandardMBean(propMBean, PropertyMBean.class, false); + * } + * + * @Override + * protected {@code Set+ * + *} {@link #getNames getNames}() { + * {@code Set names = new TreeSet ();} + * Properties props = System.getProperties(); + * for (String propName : props.stringPropertyNames()) { + * ObjectName objectName = newObjectName( + * "com.example:type=Property,name=" + + * ObjectName.quote(propName)); + * names.add(objectName); + * } + * return names; + * } + * } + * Because the {@code getDynamicMBeanFor} method + * returns a different object every time it is called, the default handling + * of notifications will not work, as explained below. + * In this case it does not matter, because the object returned by {@code + * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link + * MBeanServer#addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) MBeanServer.addNotificationListener} will + * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean + * for property {@code "foo"} emitted a notification every time that property + * changed, we would need to do it as shown below. (Because there is no API to + * be informed when a property changes, this code assumes that some other code + * calls the {@code propertyChanged} method every time a property changes.)
+ * + *+ * public class PropsMBS { + * ...as above... + * + * private final {@link VirtualEventManager} vem = new VirtualEventManager(); + * + * @Override + * public NotificationEmitter {@link #getNotificationEmitterFor + * getNotificationEmitterFor}( + * ObjectName name) throws InstanceNotFoundException { + * getDynamicMBeanFor(name); // check that the name is valid + * return vem.{@link VirtualEventManager#getNotificationEmitterFor + * getNotificationEmitterFor}(name); + * } + * + * public void propertyChanged(String name, String newValue) { + * ObjectName objectName = newObjectName( + * "com.example:type=Property,name=" + ObjectName.quote(name)); + * Notification n = new Notification( + * "com.example.property.changed", objectName, 0L, + * "Property " + name + " changed"); + * n.setUserData(newValue); + * vem.{@link VirtualEventManager#publish publish}(objectName, n); + * } + * } + *+ * + *MBean creation and deletion
+ * + *MBean creation through {@code MBeanServer.createMBean} is disabled + * by default. Subclasses which need to support MBean creation + * through {@code createMBean} need to implement a single method {@link + * #createMBean(String, ObjectName, ObjectName, Object[], String[], + * boolean)}.
+ * + *Similarly MBean registration and unregistration through {@code + * registerMBean} and {@code unregisterMBean} are disabled by default. + * Subclasses which need to support MBean registration and + * unregistration will need to implement {@link #registerMBean registerMBean} + * and {@link #unregisterMBean unregisterMBean}.
+ * + *Notifications
+ * + *By default {@link MBeanServer#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object) addNotificationListener} + * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor + * getDynamicMBeanFor}
+ * + *(name)
returns an object that is a + * {@link NotificationEmitter}. That is appropriate if + * {@code getDynamicMBeanFor}(name)
always returns the + * same object for the same {@code name}. But with + * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object, + * which is discarded as soon as the MBean request has finished. + * So a listener added to that object would be immediately forgotten.The simplest way for a subclass that defines Virtual MBeans + * to support notifications is to create a private {@link VirtualEventManager} + * and override the method {@link + * #getNotificationEmitterFor getNotificationEmitterFor} as follows:
+ * + *+ * private final VirtualEventManager vem = new VirtualEventManager(); + * + * @Override + * public NotificationEmitter getNotificationEmitterFor( + * ObjectName name) throws InstanceNotFoundException { + * // Check that the name is a valid Virtual MBean. + * // This is the easiest way to do that, but not always the + * // most efficient: + * getDynamicMBeanFor(name); + * + * // Return an object that supports add/removeNotificationListener + * // through the VirtualEventManager. + * return vem.getNotificationEmitterFor(name); + * } + *+ * + *A notification {@code n} can then be sent from the Virtual MBean + * called {@code name} by calling {@link VirtualEventManager#publish + * vem.publish}
+ * + * @since 1.7 + */ +public abstract class MBeanServerSupport implements MBeanServer { + + /** + * A logger for this class. + */ + private static final Logger LOG = + JmxProperties.NAMESPACE_LOGGER; + + /** + *(name, n)
. See the example + * above.Make a new {@code MBeanServerSupport} instance.
+ */ + protected MBeanServerSupport() { + } + + /** + *Returns a dynamically created handle that makes it possible to + * access the named MBean for the duration of a method call.
+ * + *An easy way to create such a {@link DynamicMBean} handle is, for + * instance, to create a temporary MXBean instance and to wrap it in + * an instance of + * {@link javax.management.StandardMBean}. + * This handle should remain valid for the duration of the call + * but can then be discarded.
+ * @param name the name of the MBean for which a request was received. + * @return a {@link DynamicMBean} handle that can be used to invoke + * operations on the named MBean. + * @throws InstanceNotFoundException if no such MBean is supposed + * to exist. + */ + public abstract DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException; + + /** + *Subclasses should implement this method to return + * the names of all MBeans handled by this object instance.
+ * + *The object returned by getNames() should be safely {@linkplain + * Set#iterator iterable} even in the presence of other threads that may + * cause the set of names to change. Typically this means one of the + * following:
+ * + *+ *
+ * + * @return the names of all MBeans handled by this object. + */ + protected abstract Set- the returned set of names is always the same; or + *
- the returned set of names is an object such as a {@link + * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is + * safely iterable even if the set is changed by other threads; or + *
- a new Set is constructed every time this method is called. + *
getNames(); + + /** + * List names matching the given pattern. + * The default implementation of this method calls {@link #getNames()} + * and returns the subset of those names matching {@code pattern}.
+ * + * @param pattern an ObjectName pattern + * @return the list of MBean names that match the given pattern. + */ + protected SetgetMatchingNames(ObjectName pattern) { + return Util.filterMatchingNames(pattern, getNames()); + } + + /** + * Returns a {@link NotificationEmitter} which can be used to + * subscribe or unsubscribe for notifications with the named + * mbean.
+ * + *The default implementation of this method calls {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object + * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification + * handling.
+ * + * @param name The name of the MBean whose notifications are being + * subscribed, or unsuscribed. + * + * @return A {@link NotificationEmitter} that can be used to subscribe or + * unsubscribe for notifications emitted by the named MBean, or {@code + * null} if the MBean does not emit notifications and should not be + * considered as a {@code NotificationEmitter}. + * + * @throws InstanceNotFoundException if {@code name} is not the name of + * an MBean in this {@code MBeanServer}. + */ + public NotificationEmitter getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return (NotificationEmitter) mbean; + else + return null; + } + + private NotificationEmitter getNonNullNotificationEmitterFor( + ObjectName name) + throws InstanceNotFoundException { + NotificationEmitter emitter = getNotificationEmitterFor(name); + if (emitter == null) { + IllegalArgumentException iae = new IllegalArgumentException( + "Not a NotificationEmitter: " + name); + throw new RuntimeOperationsException(iae); + } + return emitter; + } + + /** + *Creates a new MBean in the MBean name space. + * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws an {@link + * UnsupportedOperationException} + * wrapped in a {@link RuntimeOperationsException}.Subclasses may redefine this method to provide an implementation. + * All the various flavors of {@code MBeanServer.createMBean} methods + * will eventually call this method. A subclass that wishes to + * support MBean creation through {@code createMBean} thus only + * needs to provide an implementation for this one method. + * + * @param className The class name of the MBean to be instantiated. + * @param name The object name of the MBean. May be null. + * @param params An array containing the parameters of the + * constructor to be invoked. + * @param signature An array containing the signature of the + * constructor to be invoked. + * @param loaderName The object name of the class loader to be used. + * @param useCLR This parameter is {@code true} when this method + * is called from one of the {@code MBeanServer.createMBean} methods + * whose signature does not include the {@code ObjectName} of an + * MBean class loader to use for loading the MBean class. + * + * @return An
ObjectInstance
, containing the + *ObjectName
and the Java class name of the newly + * instantiated MBean. If the containedObjectName
+ * isn
, the contained Java class name is + *{@link javax.management.MBeanServer#getMBeanInfo + * getMBeanInfo(n)}.getClassName()
. + * + * @exception ReflectionException Wraps a + *java.lang.ClassNotFoundException
or a + *java.lang.Exception
that occurred when trying to + * invoke the MBean's constructor. + * @exception InstanceAlreadyExistsException The MBean is already + * under the control of the MBean server. + * @exception MBeanRegistrationException The + *preRegister
(MBeanRegistration
+ * interface) method of the MBean has thrown an exception. The + * MBean will not be registered. + * @exception MBeanException The constructor of the MBean has + * thrown an exception + * @exception NotCompliantMBeanException This class is not a JMX + * compliant MBean + * @exception InstanceNotFoundException The specified class loader + * is not registered in the MBean server. + * @exception RuntimeOperationsException Wraps either: + *+ *
+ */ + public ObjectInstance createMBean(String className, + ObjectName name, ObjectName loaderName, Object[] params, + String[] signature, boolean useCLR) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + throw newUnsupportedException("createMBean"); + } + + + /** + *- a
+ *java.lang.IllegalArgumentException
: The className + * passed in parameter is null, theObjectName
passed in + * parameter contains a pattern or noObjectName
is specified + * for the MBean; or- an {@code UnsupportedOperationException} if creating MBeans is not + * supported by this {@code MBeanServer} implementation. + *
Attempts to determine whether the named MBean should be + * considered as an instance of a given class. The default implementation + * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} + * to get an MBean object. Then its behaviour is the same as the standard + * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
+ * + * {@inheritDoc} + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + + final DynamicMBean instance = nonNullMBeanFor(name); + + try { + final String mbeanClassName = instance.getMBeanInfo().getClassName(); + + if (mbeanClassName.equals(className)) + return true; + + final Object resource; + final ClassLoader cl; + if (instance instanceof DynamicWrapperMBean) { + DynamicWrapperMBean d = (DynamicWrapperMBean) instance; + resource = d.getWrappedObject(); + cl = d.getWrappedClassLoader(); + } else { + resource = instance; + cl = instance.getClass().getClassLoader(); + } + + final Class> classNameClass = Class.forName(className, false, cl); + + if (classNameClass.isInstance(resource)) + return true; + + if (classNameClass == NotificationBroadcaster.class || + classNameClass == NotificationEmitter.class) { + try { + getNotificationEmitterFor(name); + return true; + } catch (Exception x) { + LOG.finest("MBean " + name + + " is not a notification emitter. Ignoring: "+x); + return false; + } + } + + final Class> resourceClass = Class.forName(mbeanClassName, false, cl); + return classNameClass.isAssignableFrom(resourceClass); + } catch (Exception x) { + /* Could be SecurityException or ClassNotFoundException */ + LOG.logp(Level.FINEST, + MBeanServerSupport.class.getName(), + "isInstanceOf", "Exception calling isInstanceOf", x); + return false; + } + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns the string + * "DefaultDomain".
+ */ + public String getDefaultDomain() { + return "DefaultDomain"; + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns + * {@link #getNames()}.size().
+ */ + public Integer getMBeanCount() { + return getNames().size(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method first calls {@link #getNames + * getNames()} to get a list of all MBean names, + * and from this set of names, derives the set of domains which contain + * MBeans.
+ */ + public String[] getDomains() { + final Setnames = getNames(); + final Set res = new TreeSet (); + for (ObjectName n : names) { + if (n == null) continue; // not allowed but you never know. + res.add(n.getDomain()); + } + return res.toArray(new String[res.size()]); + } + + + /** + * {@inheritDoc} + * + * The default implementation of this method will first + * call {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle + * to the named MBean, + * and then call {@link DynamicMBean#getAttribute getAttribute} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getAttribute(attribute); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} + * to obtain a handle to the named MBean, + * and then call {@link DynamicMBean#setAttribute setAttribute} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + mbean.setAttribute(attribute); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#getAttributes getAttributes} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public AttributeList getAttributes(ObjectName name, + String[] attributes) throws InstanceNotFoundException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getAttributes(attributes); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#setAttributes setAttributes} + * on that {@link DynamicMBean} handle.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.setAttributes(attributes); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#invoke invoke} + * on that {@link DynamicMBean} handle.
+ */ + public Object invoke(ObjectName name, String operationName, + Object[] params, String[] signature) + throws InstanceNotFoundException, MBeanException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.invoke(operationName, params, signature); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a + * handle to the named MBean, + * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} + * on that {@link DynamicMBean} handle.
+ */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + final DynamicMBean mbean = nonNullMBeanFor(name); + return mbean.getMBeanInfo(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will call + * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the + * class name to combine with {@code name} to produce a new + * {@code ObjectInstance}.
+ */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mbean = nonNullMBeanFor(name); + final String className = mbean.getMBeanInfo().getClassName(); + return new ObjectInstance(name, className); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method will first call {@link + * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the + * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code + * isRegistered} will return true. If {@code getDynamicMBeanFor} returns + * null or throws {@link InstanceNotFoundException}, {@code isRegistered} + * will return false.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public boolean isRegistered(ObjectName name) { + try { + final DynamicMBean mbean = getDynamicMBeanFor(name); + return mbean!=null; + } catch (InstanceNotFoundException x) { + if (LOG.isLoggable(Level.FINEST)) + LOG.finest("MBean "+name+" is not registered: "+x); + return false; + } + } + + + /** + * {@inheritDoc} + * + *The default implementation of this method will first + * call {@link #queryNames queryNames} + * to get a list of all matching MBeans, and then, for each returned name, + * call {@link #getObjectInstance getObjectInstance(name)}.
+ */ + public SetqueryMBeans(ObjectName pattern, QueryExp query) { + final Set names = queryNames(pattern, query); + if (names.isEmpty()) return Collections.emptySet(); + final Set mbeans = new HashSet (); + for (ObjectName name : names) { + try { + mbeans.add(getObjectInstance(name)); + } catch (SecurityException x) { // DLS: OK + continue; + } catch (InstanceNotFoundException x) { // DLS: OK + continue; + } + } + return mbeans; + } + + /** + * {@inheritDoc} + * + * The default implementation of this method calls {@link #getMatchingNames + * getMatchingNames(pattern)} to obtain a list of MBeans matching + * the given name pattern. If the {@code query} parameter is null, + * this will be the result. Otherwise, it will evaluate the + * {@code query} parameter for each of the returned names, exactly + * as an {@code MBeanServer} would. This might result in + * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called + * several times for each returned name.
+ */ + public SetqueryNames(ObjectName pattern, QueryExp query) { + try { + final Set res = getMatchingNames(pattern); + return filterListOfObjectNames(res, query); + } catch (Exception x) { + LOG.fine("Unexpected exception raised in queryNames: "+x); + LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x); + } + // We reach here only when an exception was raised. + // + return Collections.emptySet(); + } + + private final static boolean apply(final QueryExp query, + final ObjectName on, + final MBeanServer srv) { + boolean res = false; + MBeanServer oldServer = QueryEval.getMBeanServer(); + query.setMBeanServer(srv); + try { + res = query.apply(on); + } catch (Exception e) { + LOG.finest("QueryExp.apply threw exception, returning false." + + " Cause: "+e); + res = false; + } finally { + /* + * query.setMBeanServer is probably + * QueryEval.setMBeanServer so put back the old + * value. Since that method uses a ThreadLocal + * variable, this code is only needed for the + * unusual case where the user creates a custom + * QueryExp that calls a nested query on another + * MBeanServer. + */ + query.setMBeanServer(oldServer); + } + return res; + } + + /** + * Filters a {@code Set } according to a pattern and a query. + * This might be quite inefficient for virtual name spaces. + */ + Set + filterListOfObjectNames(Set list, + QueryExp query) { + if (list.isEmpty() || query == null) + return list; + + // create a new result set + final Set result = new HashSet (); + + for (ObjectName on : list) { + // if on doesn't match query exclude it. + if (apply(query, on, this)) + result.add(on); + } + return result; + } + + + // Don't use {@inheritDoc}, because we don't want to say that the + // MBeanServer replaces a reference to the MBean by its ObjectName. + /** + * Adds a listener to a registered MBean. A notification emitted by + * the MBean will be forwarded to the listener.
+ * + *This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code addNotificationListener} on the + * {@link NotificationEmitter} it returns. + * + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException { + final NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.addNotificationListener(listener, filter, handback); + } + + /** + * {@inheritDoc} + * + *
This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code removeNotificationListener} on the + * {@link NotificationEmitter} it returns. + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + final NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.removeNotificationListener(listener); + } + + /** + * {@inheritDoc} + * + *
This implementation calls + * {@link #getNotificationEmitterFor getNotificationEmitterFor} + * and invokes {@code removeNotificationListener} on the + * {@link NotificationEmitter} it returns. + * @see #getDynamicMBeanFor getDynamicMBeanFor + * @see #getNotificationEmitterFor getNotificationEmitterFor + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationEmitter emitter = + getNonNullNotificationEmitterFor(name); + emitter.removeNotificationListener(listener); + } + + + /** + *
Adds a listener to a registered MBean.
+ * + *The default implementation of this method first calls + * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. + * If that successfully returns an object, call it {@code + * mbean}, then (a) if {@code mbean} is an instance of {@link + * NotificationListener} then this method calls {@link + * #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) addNotificationListener(name, mbean, filter, + * handback)}, otherwise (b) this method throws an exception as specified + * for this case.
+ * + *This default implementation is not appropriate for Virtual MBeans, + * although that only matters if the object returned by {@code + * getDynamicMBeanFor} can be an instance of + * {@code NotificationListener}.
+ * + * @throws RuntimeOperationsException {@inheritDoc} + */ + public void addNotificationListener(ObjectName name, ObjectName listenerName, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + addNotificationListener(name, listener, filter, handback); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void removeNotificationListener(ObjectName name, + ObjectName listenerName) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + removeNotificationListener(name, listener); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void removeNotificationListener(ObjectName name, + ObjectName listenerName, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener listener = getListenerMBean(listenerName); + removeNotificationListener(name, listener, filter, handback); + } + + private NotificationListener getListenerMBean(ObjectName listenerName) + throws InstanceNotFoundException { + Object mbean = getDynamicMBeanFor(listenerName); + if (mbean instanceof NotificationListener) + return (NotificationListener) mbean; + else { + throw newIllegalArgumentException( + "MBean is not a NotificationListener: " + listenerName); + } + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link InstanceNotFoundException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @return the default implementation of this method never returns. + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final UnsupportedOperationException failed = + new UnsupportedOperationException("getClassLoader"); + final InstanceNotFoundException x = + new InstanceNotFoundException(String.valueOf(loaderName)); + x.initCause(failed); + throw x; + } + + /** + * {@inheritDoc} + * + *The default implementation of this method calls + * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies + * the logic just described to the result.
+ */ + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final DynamicMBean mbean = nonNullMBeanFor(mbeanName); + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); + else + return mbean.getClass().getClassLoader(); + } + + /** + * {@inheritDoc} + * + *The default implementation of this method returns a + * {@link ClassLoaderRepository} containing exactly one loader, + * the {@linkplain Thread#getContextClassLoader() context class loader} + * for the current thread. + * Subclasses can override this method to return a different + * {@code ClassLoaderRepository}.
+ */ + public ClassLoaderRepository getClassLoaderRepository() { + // We return a new ClassLoaderRepository each time this + // method is called. This is by design, because the + // SingletonClassLoaderRepository is a very small object and + // getClassLoaderRepository() will not be called very often + // (the connector server calls it once) - in the context of + // MBeanServerSupport there's a very good chance that this method will + // *never* be called. + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + return Util.getSingleClassLoaderRepository(ccl); + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + throw newUnsupportedException("registerMBean"); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}. + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + throw newUnsupportedException("unregisterMBean"); + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, null, params, signature, true)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return safeCreateMBean(className, name, null, params, signature, true); + } catch (InstanceNotFoundException ex) { + // should not happen! + throw new MBeanException(ex, "Unexpected exception: " + ex); + } + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className,name, loaderName, params, signature, false)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return safeCreateMBean(className, name, loaderName, params, signature, false); + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, null, null, null, true)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return safeCreateMBean(className, name, null, null, null, true); + } catch (InstanceNotFoundException ex) { + // should not happen! + throw new MBeanException(ex, "Unexpected exception: " + ex); + } + } + + /** + * Calls {@link #createMBean(String, ObjectName, + * ObjectName, Object[], String[], boolean) + * createMBean(className, name, loaderName, null, null, false)}; + */ + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return safeCreateMBean(className, name, loaderName, null, null, false); + } + + // make sure all exceptions are correctly wrapped in a JMXException + private ObjectInstance safeCreateMBean(String className, + ObjectName name, ObjectName loaderName, Object[] params, + String[] signature, boolean useRepository) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + return createMBean(className, name, loaderName, params, + signature, useRepository); + } catch (ReflectionException x) { throw x; + } catch (InstanceAlreadyExistsException x) { throw x; + } catch (MBeanRegistrationException x) { throw x; + } catch (MBeanException x) { throw x; + } catch (NotCompliantMBeanException x) { throw x; + } catch (InstanceNotFoundException x) { throw x; + } catch (SecurityException x) { throw x; + } catch (JMRuntimeException x) { throw x; + } catch (RuntimeException x) { + throw new RuntimeOperationsException(x, x.toString()); + } catch (Exception x) { + throw new MBeanException(x, x.toString()); + } + } + + + /** + * {@inheritDoc} + * + *
This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * {@inheritDoc} + * + *This operation is not supported in this base class implementation. + * The default implementation of this method always throws + * {@link RuntimeOperationsException} wrapping + * {@link UnsupportedOperationException}.
+ * + * @throws javax.management.RuntimeOperationsException wrapping + * {@link UnsupportedOperationException} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + + // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException + // if the returned mbean is null. + // The DynamicMBean returned by this method is thus guaranteed to be + // non null. + // + private DynamicMBean nonNullMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (name == null) + throw newIllegalArgumentException("Null ObjectName"); + if (name.getDomain().equals("")) { + String defaultDomain = getDefaultDomain(); + try { + name = name.withDomain(getDefaultDomain()); + } catch (Exception e) { + throw newIllegalArgumentException( + "Illegal default domain: " + defaultDomain); + } + } + final DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean!=null) return mbean; + throw new InstanceNotFoundException(String.valueOf(name)); + } + + static RuntimeException newUnsupportedException(String operation) { + return new RuntimeOperationsException( + new UnsupportedOperationException( + operation+": Not supported in this namespace")); + } + + static RuntimeException newIllegalArgumentException(String msg) { + return new RuntimeOperationsException( + new IllegalArgumentException(msg)); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,378 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management.namespace; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventConsumer; + +/** + *This class maintains a list of subscribers for ObjectName patterns and + * allows a notification to be sent to all subscribers for a given ObjectName. + * It is typically used in conjunction with {@link MBeanServerSupport} + * to implement a namespace with Virtual MBeans that can emit notifications. + * The {@code VirtualEventManager} keeps track of the listeners that have been + * added to each Virtual MBean. When an event occurs that should trigger a + * notification from a Virtual MBean, the {@link #publish publish} method can + * be used to send it to the appropriate listeners.
+ * @since 1.7 + */ +public class VirtualEventManager implements EventConsumer { + /** + *Create a new {@code VirtualEventManager}.
+ */ + public VirtualEventManager() { + } + + public void subscribe( + ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) { + + if (logger.traceOn()) + logger.trace("subscribe", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new IllegalArgumentException("Null listener"); + + Map> map = + name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap; + + final ListenerInfo li = new ListenerInfo(listener, filter, handback); + List list; + + synchronized (map) { + list = map.get(name); + if (list == null) { + list = new ArrayList (); + map.put(name, list); + } + list.add(li); + } + } + + public void unsubscribe( + ObjectName name, NotificationListener listener) + throws ListenerNotFoundException { + + if (logger.traceOn()) + logger.trace("unsubscribe2", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new ListenerNotFoundException(); + + Map > map = + name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap; + + final ListenerInfo li = new ListenerInfo(listener, null, null); + List list; + synchronized (map) { + list = map.get(name); + if (list == null || !list.remove(li)) + throw new ListenerNotFoundException(); + + if (list.isEmpty()) + map.remove(name); + } + } + + /** + * Unsubscribes a listener which is listening to an MBean or a set of + * MBeans represented by an {@code ObjectName} pattern.
+ * + *The listener to be removed must have been added by the {@link + * #subscribe subscribe} method with the given {@code name}, {@code filter}, + * and {@code handback}. If the {@code + * name} is a pattern, then the {@code subscribe} must have used the same + * pattern. If the same listener has been subscribed more than once to the + * {@code name} with the same filter and handback, only one listener is + * removed.
+ * + * @param name The name of the MBean or an {@code ObjectName} pattern + * representing a set of MBeans to which the listener was subscribed. + * @param listener A listener that was previously subscribed to the + * MBean(s). + * + * @throws ListenerNotFoundException The given {@code listener} was not + * subscribed to the given {@code name}. + * + * @see #subscribe + */ + public void unsubscribe( + ObjectName name, NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + + if (logger.traceOn()) + logger.trace("unsubscribe4", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new ListenerNotFoundException(); + + Map> map = + name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap; + + List list; + synchronized (map) { + list = map.get(name); + boolean removed = false; + for (Iterator it = list.iterator(); it.hasNext(); ) { + ListenerInfo li = it.next(); + if (li.equals(listener, filter, handback)) { + it.remove(); + removed = true; + break; + } + } + if (!removed) + throw new ListenerNotFoundException(); + + if (list.isEmpty()) + map.remove(name); + } + } + + /** + * Sends a notification to the subscribers for a given MBean.
+ * + *For each listener subscribed with an {@code ObjectName} that either + * is equal to {@code emitterName} or is a pattern that matches {@code + * emitterName}, if the associated filter accepts the notification then it + * is forwarded to the listener.
+ * + * @param emitterName The name of the MBean emitting the notification. + * @param n The notification being sent by the MBean called + * {@code emitterName}. + * + * @throws IllegalArgumentException If the emitterName of the + * notification is null or is an {@code ObjectName} pattern. + */ + public void publish(ObjectName emitterName, Notification n) { + if (logger.traceOn()) + logger.trace("publish", "" + emitterName); + + if (n == null) + throw new IllegalArgumentException("Null notification"); + + if (emitterName == null) { + throw new IllegalArgumentException( + "Null emitter name"); + } else if (emitterName.isPattern()) { + throw new IllegalArgumentException( + "The emitter must not be an ObjectName pattern"); + } + + final Listlisteners = new ArrayList (); + + // If there are listeners for this exact name, add them. + synchronized (exactSubscriptionMap) { + List exactListeners = + exactSubscriptionMap.get(emitterName); + if (exactListeners != null) + listeners.addAll(exactListeners); + } + + // Loop over subscription patterns, and add all listeners for each + // one that matches the emitterName name. + synchronized (patternSubscriptionMap) { + for (ObjectName on : patternSubscriptionMap.keySet()) { + if (on.apply(emitterName)) + listeners.addAll(patternSubscriptionMap.get(on)); + } + } + + // Send the notification to all the listeners we found. + sendNotif(listeners, n); + } + + /** + * Returns a {@link NotificationEmitter} object which can be used to + * subscribe or unsubscribe for notifications with the named + * mbean. The returned object implements {@link + * NotificationEmitter#addNotificationListener + * addNotificationListener(listener, filter, handback)} as + * {@link #subscribe this.subscribe(name, listener, filter, handback)} + * and the two {@code removeNotificationListener} methods from {@link + * NotificationEmitter} as the corresponding {@code unsubscribe} methods + * from this class.
+ * + * @param name The name of the MBean whose notifications are being + * subscribed, or unsuscribed. + * + * @return A {@link NotificationEmitter} + * that can be used to subscribe or unsubscribe for + * notifications emitted by the named MBean, or {@code null} if + * the MBean does not emit notifications and should not + * be considered as a {@code NotificationBroadcaster}. This class + * never returns null but a subclass is allowed to. + * + * @throws InstanceNotFoundException if {@code name} does not exist. + * This implementation never throws {@code InstanceNotFoundException} but + * a subclass is allowed to override this method to do so. + */ + public NotificationEmitter + getNotificationEmitterFor(final ObjectName name) + throws InstanceNotFoundException { + final NotificationEmitter emitter = new NotificationEmitter() { + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws IllegalArgumentException { + subscribe(name, listener, filter, handback); + } + + public void removeNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + unsubscribe(name, listener); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws ListenerNotFoundException { + unsubscribe(name, listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + // Never called. + return null; + } + }; + return emitter; + } + + // --------------------------------- + // private stuff + // --------------------------------- + + private static class ListenerInfo { + public final NotificationListener listener; + public final NotificationFilter filter; + public final Object handback; + + public ListenerInfo(NotificationListener listener, + NotificationFilter filter, + Object handback) { + + if (listener == null) { + throw new IllegalArgumentException("Null listener."); + } + + this.listener = listener; + this.filter = filter; + this.handback = handback; + } + + /* Two ListenerInfo instances are equal if they have the same + * NotificationListener. This means that we can use List.remove + * to implement the two-argument removeNotificationListener. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof ListenerInfo)) { + return false; + } + + return listener.equals(((ListenerInfo)o).listener); + } + + /* Method that compares all four fields, appropriate for the + * four-argument removeNotificationListener. + */ + boolean equals( + NotificationListener listener, + NotificationFilter filter, + Object handback) { + return (this.listener == listener && same(this.filter, filter) + && same(this.handback, handback)); + } + + private static boolean same(Object x, Object y) { + if (x == y) + return true; + if (x == null) + return false; + return x.equals(y); + } + + @Override + public int hashCode() { + return listener.hashCode(); + } + } + + private static void sendNotif(Listlisteners, Notification n) { + for (ListenerInfo li : listeners) { + if (li.filter == null || + li.filter.isNotificationEnabled(n)) { + try { + li.listener.handleNotification(n, li.handback); + } catch (Exception e) { + logger.trace("sendNotif", "handleNotification", e); + } + } + } + } + + // --------------------------------- + // private variables + // --------------------------------- + + private final Map > exactSubscriptionMap = + new HashMap >(); + private final Map > patternSubscriptionMap = + new HashMap >(); + + // trace issue + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventManager"); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/package-info.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,597 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * The
+ * + *javax.management.namespace
package makes it possible + * to federate MBeanServers into a hierarchical name space.What Is a Name Space?
+ *+ * A name space is like an {@link javax.management.MBeanServer} within + * an {@code MBeanServer}. Just as a file system folder can contain + * another file system folder, an {@code MBeanServer} can contain another + * {@code MBeanServer}. Similarly, just as a remote folder on a remote + * disk can be mounted on a parent folder on a local disk, a remote name + * space in a remote {@code MBeanServer} can be mounted on a name + * space in a local parent {@code MBeanServer}. + *
+ *+ * The
+ *javax.management.namespace
API thus makes it possible to + * create a hierarchy of MBean servers federated in a hierarchical name + * space inside a single {@code MBeanServer}. + *How To Create a Name Space?
+ *+ * To create a name space, you only need to register a + * {@link javax.management.namespace.JMXNamespace} MBean in + * an MBean server. We have seen that a namespace is like + * an {@code MBeanServer} within an {@code MBeanServer}, and + * therefore, it is possible to create a namespace that shows the + * content of another {@code MBeanServer}. The simplest case is + * when that {@code MBeanServer} is another {@code MBeanServer} + * created by the {@link javax.management.MBeanServerFactory} as + * shown in the extract below: + *
+ *+ * final MBeanServer server = ....; + * final String namespace = "foo"; + * final ObjectName namespaceName = {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName + * JMXNamespaces.getNamespaceObjectName(namespace)}; + * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()), + * namespaceName); + *+ *+ * To navigate in namespaces and view their content, the easiest way is + * to use an instance of {@link javax.management.namespace.JMXNamespaceView}. For instance, given + * the {@code server} above, in which we created a namespace {@code "foo"}, + * it is possible to create a {@code JMXNamespaceView} that will make it + * possible to navigate easily in the namespaces and sub-namespaces of that + * server: + *
+ *+ * // create a namespace view for 'server' + * final JMXNamespaceView view = new JMXNamespaceView(server); + * + * // list all top level namespaces in 'server' + * System.out.println("List of namespaces: " + Arrays.toString({@link javax.management.namespace.JMXNamespaceView#list() view.list()})); + * + * // go down into namespace 'foo': provides a namespace view of 'foo' and its + * // sub namespaces... + * final JMXNamespaceView foo = {@link javax.management.namespace.JMXNamespaceView#down view.down("foo")}; + * + * // list all MBeans contained in namespace 'foo' + * System.out.println({@link javax.management.namespace.JMXNamespaceView#where() foo.where()} + " contains: " + + * {@link javax.management.namespace.JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null)); + *+ *+ * It is also possible to create more complex namespaces, such as namespaces + * that point to MBean servers located in remote JVMs. + *
+ *+ * For instance, to mount the MBeanServer accessible + * at
+ *service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi
+ * in a name space {@code "foo"} inside the {@linkplain + * java.lang.management.ManagementFactory#getPlatformMBeanServer platform + * MBeanServer} you would write the following piece of code: + *+ * final JMXServiceURL sourceURL = + * new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi"); + * final MBeanServer platform = ManagementFactory.getPlatformMBeanServer(); + * final Map<String,Object> options = Collections.emptyMap(); + * final JMXRemoteNamespace mbean = {@link + * javax.management.namespace.JMXRemoteNamespace JMXRemoteNamespace}. + * {@link javax.management.namespace.JMXRemoteNamespace#newJMXRemoteNamespace newJMXRemoteNamespace(sourceURL, options)}; + * final ObjectName name = {@link javax.management.namespace.JMXNamespaces JMXNamespaces}.{@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName(String) getNamespaceObjectName("foo")}; + * final ObjectInstance ref = platform.registerMBean(mbean,name); + * platform.invoke(ref.getObjectName(),"connect",null,null); + *+ * + *What Does a Name Space Look Like?
+ * + *+ * We have seen that {@link javax.management.namespace.JMXNamespaceView} class + * provides an easy way to navigate within namespaces. It is however also + * possible to interact with namespaces directly from the top level + * {@code MBeanServer} in which they have been created. + * From the outside, a name space only appears as a special MBean in + * the MBean server. There's nothing much you can do with this MBean + * directly. + *
+ *+ * For instance, let's assume you have registered a {@link + * javax.management.namespace.JMXRemoteNamespaceMBean + * JMXRemoteNamespaceMBean} to manage the name space {@code "foo"}. + *
+ *
If you query for + *platform.queryNames("*//:*",null)
, then you will see + * one MBean named {@code "foo//:type=JMXNamespace"}. + *
This is the {@link javax.management.namespace.JMXNamespace} + * MBean which is in charge of handling the namespace {@code "foo"}. + *+ * In fact, name space handler MBeans are instances of + * the class {@link javax.management.namespace.JMXNamespace} - or + * instances of a subclass of that class. + * They have a special {@link javax.management.ObjectName} defined by + * {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName + * JMXNamespaces.getNamespaceObjectName}.
+ *
+ * {@link javax.management.namespace.JMXNamespace} instances are able + * to return an {@link + * javax.management.namespace.JMXNamespace#getSourceServer MBeanServer} + * which corresponds to the MBeanServer within (= the name space itself). + *+ * So how does it work? How can you see the MBeans contained in the new + * name space? + *
+ *In order to address scalability issues, MBeans registered in + * namespaces (such as our namespace {@code "foo"} above) can not be + * seen with {@code mbeanServer.queryNames("*:*",null)}. To see the MBeans + * contained in a namespace, you can use one of these methods: + *
+ *+ *
+ * + *- + * You can use the {@link javax.management.namespace.JMXNamespaceView} + * class shown above, + *
+ *- + * or you can directly look for MBeans + * whose names match + * {@code "foo//*:*"}, + *
+ *- + * or you can narrow down to the namespace + * and obtain an MBeanServer + * proxy that corresponds to an MBeanServer view of that namespace. + * The JMXNamespaces class provides a static method that + * allows you to narrow down to a name space, by calling + * {@link javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String) + * JMXNamespaces.narrowToNamespace}. + *
+ *Using Name Space Prefixes
+ *+ * As we have explained above, MBeans contained in name + * spaces are not returned by {@code server.queryNames(null,null)} - or + *
server.queryNames({@link javax.management.ObjectName#WILDCARD ObjectName.WILDCARD},null)
. + *
+ * However, these MBeans can still be accessed from the top level + * {@code MBeanServer} interface, without using any API specific to the + * version 2.0 of the JMX API, simply by using object names with + * name space prefixes: + *
To list MBeans contained in a namespace {@code "foo"} you can + * query for MBeans whose names match {@code "foo//*:*"}, as shown + * earlier in this document: + *+ * server.queryNames(new ObjectName("foo//*:*", null); + * // or equivalently: + * server.queryNames(JMXNamespaces.getWildcardFor("foo"), null); + *+ * This will return a list of MBean names whose domain name starts + * with {@code foo//}. + *+ * Using these names, you can invoke any operation on the corresponding + * MBeans. For instance, to get the {@link javax.management.MBeanInfo + * MBeanInfo} of an MBean + * contained in name space {@code "foo"} (assuming + * the name of the MBean within its name space is domain:type=Thing, + * then simply call: + *
+ * server.getMBeanInfo(new ObjectName("foo//domain:type=Thing")); + *+ * An easier way to access MBeans contained in a name space is to + * cd inside the name space, as shown in the following paragraph. + * + * + *Narrowing Down Into a Name Spaces
+ *+ * As we have seen, name spaces are like MBean servers within MBean servers. + * Therefore, it is possible to view a name space just as if it were + * an other MBean server. This is similar to opening a sub + * folder from a parent folder.
+ * This operation is illustrated in the code extract below: + *+ * final MBeanServer foo = + * JMXNamespaces.narrowToNamespace(platform, "foo"); + * final MBeanInfo info = + * foo.getMBeanInfo(new ObjectName("domain:type=Thing")); + *+ * The {@code MBeanServer} returned by {@link + * javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String) + * JMXNamespaces.narrowToNamespace} is an {@code MBeanServer} view that + * narrows down into a given namespace. The MBeans contained inside that + * namespace can now be accessed by their regular local name.
+ * The MBean server obtained by narrowing down + * to name space {@code "foo"} behaves just like a regular MBean server. + * However, it may sometimes throw an {@link + * java.lang.UnsupportedOperationException UnsupportedOperationException} + * wrapped in a JMX exception if you try to call an operation which is not + * supported by the underlying name space handler. + *
For instance, {@link javax.management.MBeanServer#registerMBean + * registerMBean} is not supported for name spaces mounted from remote + * MBean servers. + * + *+ * Note: If you have a deep hierarchy of namespaces, and if you + * are switching from one namespace to another in the course of your + * application, it might be more convenient to use a + * {@link javax.management.namespace.JMXNamespaceView} + * in order to navigate in your namespaces. + *
+ * + *Different Types of Name Spaces
+ *+ * This API lets you create several types of name spaces: + *
+ *
+ * + * + *- + * You can use the {@link + * javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} to create + * remote name spaces, mounted from + * a remote sub {@code MBeanServer} source, as shown + * earlier in this document. + *
+ *- + * You can also use {@link + * javax.management.namespace.JMXNamespace + * JMXNamespace} to create + * local name spaces, + * by providing a direct reference to another {@code MBeanServer} + * instance living in the same JVM. + *
+ *- + * Finally, you can create + * name spaces containing virtual MBeans, + * by subclassing the {@link + * javax.management.namespace.MBeanServerSupport + * MBeanServerSupport}, and passing an instance of + * your own subclass to a {@link + * javax.management.namespace.JMXNamespace JMXNamespace}. + *
+ *- + * If none of these classes suit your needs, you can also provide + * your own subclass of {@link + * javax.management.namespace.JMXNamespace + * JMXNamespace}. This is however discouraged. + *
+ *Name Spaces And Special Operations
+ *+ * MBean Naming considerations aside, Name Spaces are transparent for + * most {@code MBeanServer} operations. There are however a few + * exceptions: + *
+ *+ *
+ * + *- + *
+ *MBeanServer only operations - these are the operations which are + * supported by {@link javax.management.MBeanServer MBeanServer} but + * are not present in {@link + * javax.management.MBeanServerConnection + * MBeanServerConnection}. Since a name space can be a local view of + * a remote {@code MBeanServer}, accessible only through an + * {@code MBeanServerConnection}, these + * kinds of operations are not always supported.
+ *+ *
+ *- + *
+ *registerMBean:
+ *The {@link javax.management.MBeanServer#registerMBean + * registerMBean} + * operation is not supported by most name spaces. A call + * to + *
+ * MBeanServer server = ....; + * ThingMBean mbean = new Thing(...); + * ObjectName name = new ObjectName("foo//domain:type=Thing"); + * server.registerMBean(mbean, name); + *+ * will usually fail, unless the name space + * {@code "foo"} is a local name + * space. In the case where you attempt to cross + * multiple name spaces, then all name spaces in the + * path must support the {@code registerMBean} operation + * in order for it to succeed.
+ * To create an MBean inside a name space, it is + * usually safer to use {@code createMBean} - + * although some special + * considerations can also apply. + * + * + *- + *
+ *getClassLoader:
+ *Similarly to registerMBean, + * and for the same reasons, {@link + * javax.management.MBeanServer#getClassLoader + * getClassLoader} will usually fail, unless the + * class loader is an MBean registered in a + * local name space.
+ *
+ *- + *
+ *getClassLoaderFor:
+ *The implementation of {@link + * javax.management.MBeanServer#getClassLoaderFor + * getClassLoaderFor} also depends on which + * type of name space + * handler is used across the namespace path. + *
+ *+ * A local name space will usually + * be able to implement this method just as a real + * {@code MBeanServer} would. A + * remote name space will usually + * return the default class loader configured on the + * internal {@link javax.management.remote.JMXConnector + * JMXConnector} used to connect to the remote server. + * When a {@link + * javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} is used to connect to a + * remote server that contains MBeans which export + * custom types, the {@link + * javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} must thus be configured with + * an options map such that the underlying connector + * can obtain a default class loader able + * to handle those types. + *
+ *+ * Other types of name spaces + * may implement this method + * as best as they can. + *
+ *- + *
+ *MBean creation
+ *MBean creation through {@link + * javax.management.MBeanServerConnection#createMBean + * createMBean} might not be supported by all + * name spaces: local name spaces and + * remote name spaces will usually + * support it, but virtual name + * spaces and custom name + * spaces might not. + *
+ *+ * In that case, they will throw an {@link + * java.lang.UnsupportedOperationException + * UnsupportedOperationException} usually wrapped into an {@link + * javax.management.MBeanRegistrationException}. + *
+ *- + *
+ *Notifications
+ *Some namespaces might not support JMX Notifications. In that + * case, a call to add or remove notification listener for an + * MBean contained in that name space will raise a + * {@link javax.management.RuntimeOperationsException + * RuntimeOperationsException} wrapping an {@link + * java.lang.UnsupportedOperationException + * UnsupportedOperationException} exception. + *
+ *Crossing Several Name Spaces
+ *+ * Just as folders can contain other folders, name spaces can contain + * other name spaces. For instance, if an {@code MBeanServer} S1 + * containing a name space {@code "bar"} is mounted in another + * {@code MBeanServer} S2 with name space {@code "foo"}, then + * an MBean M1 named {@code "domain:type=Thing"} in namespace + * {@code "bar"} will appear as {@code "foo//bar//domain:type=Thing"} in + * {@code MBeanServer} S2. + *
+ *+ * When accessing the MBean M1 from server S2, the + * method call will traverse in a cascade {@code MBeanServer} S2, + * then the name space handler for name space {@code "foo"}, then + * {@code MBeanServer} S1, before coming to the name space + * handler for name space {@code "bar"}. Any operation invoked + * on the MBean from a "top-level" name space will therefore need to + * traverse all the name spaces along the name space path until + * it eventually reaches the named MBean. This means that an operation + * like registerMBean for instance, + * can only succeed if all the name spaces along the path support it. + *
+ *+ * Narrowing to a nested name space works just the same as narrowing + * to a top level name space: + *
+ * final MBeanServer S2 = .... ; + * final MBeanServer bar = + * JMXNamespaces.narrowToNamespace(S2, "foo//bar"); + * final MBeanInfo info = + * foo.getMBeanInfo(new ObjectName("domain:type=Thing")); + *+ * + * + *Name Spaces And Operation Results
+ *+ * Operation results, as well as attribute values returned by an MBean + * contained in a name space must be interpreted in the context of that + * name space.
+ *
+ * In other words, if an MBean in name space "foo" has an attribute of + * type {@code ObjectName}, then it must be assumed that the + * {@code ObjectName} returned by that MBean is relative to + * name space "foo".
+ * The same rule aplies for MBean names that can be returned by + * operations invoked on such an MBean. If one of the MBean operations + * return, say, a {@code Set} then those MBean names must + * also be assumed to be relative to name space "foo".
+ *+ * In the usual case, a JMX client will first + * narrow to a name space before invoking + * any operation on the MBeans it contains. In that case the names + * returned by the MBean invoked can be directly fed back to the + * narrowed connection. + *
+ * + *
+ * If however, the JMX client directly invoked the MBean from a higher + * name space, without having narrowed to that name space first, then + * the names that might be returned by that MBean will not be directly + * usable - the JMX client will need to either + * narrow to the name space before using the + * returned names, or convert the names to the higher level name space + * context. + *
+ * The {@link javax.management.namespace.JMXNamespaces JMXNamespaces} + * class provides methods that can be used to perform that conversion. + *Name Spaces And Notifications
+ *+ * As already explained, name spaces are very + * similar to {@code MBeanServer}s. It is thus possible to get + * {@link javax.management.MBeanServerNotification MBeanServerNotifications} + * when MBeans are added or removed within a name space, by registering + * with the {@link javax.management.MBeanServerDelegate + * MBeanServerDelegate} MBean of the corresponding name space.
+ * However, it must be noted that the notifications emitted by a + * name space must be interpreted in the context of that name space. + * For instance, if an MBean {@code "domain:type=Thing"} contained in + * namespace "foo//bar" emits a notification, the source of the + * notification will be {@code "domain:type=Thing"}, not + * {@code "foo//bar//domain:type=Thing"}.
+ * It is therefore recommended to keep track of the name space + * information when registering a listener with an MBean contained in + * a name space, especially if the same listener is used to receive + * notifications from different name spaces. An easy solution is to + * use the handback, as illustrated in the code below. + *+ * final MBeanServer server = ...; + * final NotificationListener listener = new NotificationListener() { + * public void handleNotification(Notification n, Object handback) { + * if (!(n instanceof MBeanServerNotification)) { + * System.err.println("Error: expected MBeanServerNotification"); + * return; + * } + * final MBeanServerNotification mbsn = + * (MBeanServerNotification) n; + * + * // We will pass the namespace path in the handback. + * // + * // The received notification must be interpreted in + * // the context of its source - therefore + * // mbsn.getMBeanName() does not include the name space + * // path... + * // + * final String namespace = (String) handback; + * System.out.println("Received " + mbsn.getType() + + * " for MBean " + mbsn.getMBeanName() + + * " from name space " + namespace); + * } + * }; + * server.addNotificationListener(JMXNamespaces.insertPath("foo//bar", + * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar"); + * server.addNotificationListener(JMXNamespaces.insertPath("foo//joe", + * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe"); + *+ * + *+ * JMX Connectors may require some configuration in order to be able + * to forward notifications from MBeans located in name spaces. + * The RMI JMX Connector Server + * in the Java SE 7 platform is configured by default to internally + * use the new {@linkplain javax.management.event event service} on + * the server side. + * When the connector server is configured in this way, JMX clients + * which use the old JMX Notifications mechanism (such as clients + * running on prior versions of the JDK) will be able to + * to receive notifications from MBeans located in sub name spaces. + * This is because the connector server will transparently delegate + * their subscriptions to the underlying {@linkplain + * javax.management.event event service}. In summary: + *
+ *
+ * + *- + * On the server side: When exporting an {@code MBeanServer} + * through a JMX Connector, you will need to make sure that the + * connector server uses the new {@linkplain javax.management.event + * event service} in order to register for notifications. If the + * connector server doesn't use the event service, only clients + * which explicitly use the new {@linkplain javax.management.event + * event service} will be able to register for notifications + * with MBeans located in sub name spaces. + *
+ *- + * On the client side: if the JMX Connector server (on the remote + * server side) was configured to internally use the new + * {@linkplain javax.management.event + * event service}, then clients can continue to use the old + * {@code MBeanServerConnection} add / remove notification + * listener methods transparently. Otherwise, only clients which + * explicitly use the new {@linkplain javax.management.event + * event service} will be able to receive notifications from + * MBeans contained in sub name spaces. + *
+ *+ * These configuration issues apply at each node in the name space path, + * whenever the name space points to a remote server. The + * {@link javax.management.namespace.JMXRemoteNamespace + * JMXRemoteNamespace} can be configured in such a way that it will + * explicitly use an {@link javax.management.event.EventClient EventClient} + * when forwarding subscription to the remote side. Note that this can be + * unnecessary (and a waste of resources) if the underlying JMXConnector + * returned by the JMXConnectorFactory (client side) already uses the + * {@linkplain javax.management.event event service} to register for + * notifications with the server side. + *
+ * + *Name Spaces And Access Control
+ *+ * Access to MBeans exposed through JMX namespaces is controlled by + * {@linkplain javax.management.namespace.JMXNamespacePermission + * jmx namespace permissions}. These permissions are checked by the + * MBeanServer in which the {@link + * javax.management.namespace.JMXNamespace JMXNamespace} MBean is registered. + * This is described in + * details in the {@link + * javax.management.namespace.JMXNamespace JMXNamespace} class. + *
+ *+ * To implement a "firewall-like" access control in a JMX agent you + * can also place an {@link + * javax.management.remote.MBeanServerForwarder} in the JMX Connector + * Server which exposes the top-level MBeanServer of your application. + * This {@code MBeanServerForwarder} will be able to perform + * authorization checks for all MBeans, including those located in + * sub name spaces. + *
+ *+ * For a tighter access control we recommend using a {@link + * java.lang.SecurityManager security manager}. + *
+ * @since 1.7 + * + **/ + +package javax.management.namespace; + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/openmbean/CompositeType.java --- a/jdk/src/share/classes/javax/management/openmbean/CompositeType.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/openmbean/CompositeType.java Wed Jul 05 16:41:30 2017 +0200 @@ -89,7 +89,7 @@ *
* @param itemNames The names of the items contained in the * composite data values described by thisCompositeType
instance; - * cannot be null and should contain at least one element; no element can be a null or empty string. + * cannot be null; no element can be null or an empty string. * Note that the order in which the item names are given is not important to differentiate a *CompositeType
instance from another; * the item names are internally stored sorted in ascending alphanumeric order. @@ -97,7 +97,7 @@ * @param itemDescriptions The descriptions, in the same order as itemNames, of the items contained in the * composite data values described by thisCompositeType
instance; * should be of the same size as itemNames; - * no element can be a null or empty string. + * no element can be null or an empty string. *
* @param itemTypes The open type instances, in the same order as itemNames, describing the items contained * in the composite data values described by thisCompositeType
instance; @@ -125,7 +125,7 @@ // super(CompositeData.class.getName(), typeName, description, false); - // Check the 3 arrays are not null or empty (ie length==0) and that there is no null element or empty string in them + // Check the 3 arrays are not null and that there is no null element or empty string in them // checkForNullElement(itemNames, "itemNames"); checkForNullElement(itemDescriptions, "itemDescriptions"); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java --- a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Wed Jul 05 16:41:30 2017 +0200 @@ -268,6 +268,14 @@ return conn; } + private staticMap newHashMap() { + return new HashMap (); + } + + private static Map newHashMap(Map map) { + return new HashMap (map); + } + /** * Creates a connector client for the connector server at the * given address. The resultant client is not connected until its @@ -300,16 +308,18 @@ public static JMXConnector newJMXConnector(JMXServiceURL serviceURL, Map
environment) throws IOException { - Map envcopy; + + final Map envcopy; if (environment == null) - envcopy = new HashMap (); + envcopy = newHashMap(); else { EnvHelp.checkAttributes(environment); - envcopy = new HashMap (environment); + envcopy = newHashMap(environment); } final ClassLoader loader = resolveClassLoader(envcopy); - final Class targetInterface = JMXConnectorProvider.class; + final Class targetInterface = + JMXConnectorProvider.class; final String protocol = serviceURL.getProtocol(); final String providerClassName = "ClientProvider"; @@ -351,9 +361,10 @@ } } - envcopy = Collections.unmodifiableMap(envcopy); + final Map fixedenv = + Collections.unmodifiableMap(envcopy); - return provider.newJMXConnector(serviceURL, envcopy); + return provider.newJMXConnector(serviceURL, fixedenv); } private static String resolvePkgs(Map env) throws JMXProviderException { @@ -365,8 +376,8 @@ if (pkgsObject == null) pkgsObject = - AccessController.doPrivileged(new PrivilegedAction