# 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 @@ - + +
+ @@ -1087,50 +1148,59 @@ - + - + - + - + + - + + - + + - + + - + + - - + + +
OpenJDKIntroduction
  • Minimum Build Environments
  • Specific Developer Build Environments
  • +
  • Source Directory Structure
  • Build Information
      @@ -182,14 +187,64 @@ we will try to provide what information we have available to us. -

      Fedora

      +

      Fedora 9

      - TBD + After installing + Fedora 9 + you need to make sure you have + the "Software Development" bundle installed, plus the + following packages: +
      +
        +
      • cups devel: Cups Development Package
      • +
      • freetype 2.3+ devel: Freetype 2.3 Development Package
      • +
      • hg: Mercurial, if you need to clone or manage source repositories
      • +
      • ksh: May be needed when using webrev
      • +
      +
      +

      + Always a good idea to do a complete Software Update/Refresh + after you get all the packages installed.

      -

      Debian

      +

      CentOS 5.2

      - TBD + After installing + CentOS 5.2 + you need to make sure you have + the following Development bundles installed: +
      +
        +
      • Development Libraries
      • +
      • Development Tools
      • +
      • Java Development
      • +
      • X Software Development
      • +
      +
      +

      + Plus the following packages: +

      +
        +
      • cups devel: Cups Development Package
      • +
      • alsa devel: Alsa Development Package
      • +
      • ant: Ant Package
      • +
      • Xi devel: libXi.so Development Package
      • +
      +
      +

      + The freetype 2.3 packages don't seem to be available, + but the freetype 2.3 sources can be downloaded, built, + and installed easily enough from + + the freetype site. + Build and install with something like: +

      + ./configure && make && sudo -u root make install +
      +

      + Mercurial packages could not be found easily, but a Google + search should find ones, and they usually include Python if + it's needed.

      Ubuntu

      @@ -664,8 +719,8 @@
    • Install the - Microsoft Visual Studio .NET 2003 Professional or the - Microsoft Platform SDK. + Microsoft Visual Studio .NET 2003 Professional (32bit) or the + Microsoft Platform SDK (64bit).
    • Setup all environment variables for compilers @@ -871,6 +926,11 @@ The Microsoft Visual Studio .NET 2005 (VS2005) compiler will not work at this time due to the new runtime dll and the manifest requirements. +

      + 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 @@
  • Binary NameCategory Package Description
    ar.exe Develbinutils: The GNU assembler, linker and binary + binutilsThe GNU assembler, linker and binary utilities
    make.exe Develmake: The GNU version of the 'make' utility
    +
    makeThe GNU version of the 'make' utility built for CYGWIN.
    NOTE: See the GNU make section
    m4.exe Interpretersm4: GNU implementation of the traditional Unix macro + m4GNU implementation of the traditional Unix macro processor
    cpio.exe Utilscpio: A program to manage archives of filescpioA program to manage archives of files
    gawk.exe Utilsawk: Pattern-directed scanning and processing languageawkPattern-directed scanning and processing language
    file.exe Utilsfile: Determines file type using 'magic' numbersfileDetermines file type using 'magic' numbers
    zip.exe Archivezip: Package and compress (archive) fileszipPackage and compress (archive) files
    unzip.exe Archiveunzip: Extract compressed files in a ZIP archiveunzipExtract compressed files in a ZIP archive
    free.exeProcpsfree: Display amount of free and used memory in the systemSystemprocpsDisplay amount of free and used memory in the system
    @@ -1144,6 +1214,13 @@ section on BLODA (applications that interfere with CYGWIN). +

    + 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, the ObjectName passed - * in parameter contains a pattern or no ObjectName - * 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 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 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, the ObjectName passed - * in parameter contains a pattern or no ObjectName - * 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 The ObjectInstance 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 the ObjectInstance for a given MBean - * registered with the MBean server. - * - * @param name The object name of the MBean. - * - * @return The ObjectInstance 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 the ObjectInstance - * 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 Set queryMBeans(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 Set queryNames(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 filter and handback parameters - * may be null if and only if they are null in a listener to be - * removed.

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

    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 filter and handback parameters - * may be null if and only if they are null in a listener to be - * removed.

    - * - * @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 of 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 The ObjectName 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}(name, n). See the example - * above.

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

    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:

    - * - *
      - *
    • 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. - *
    - * - * @return the names of all MBeans handled by this object. - */ - protected abstract Set 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 Set getMatchingNames(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 contained ObjectName - * is n, 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: - *

      - *
    • a java.lang.IllegalArgumentException: The className - * passed in parameter is null, the ObjectName passed in - * parameter contains a pattern or no ObjectName is specified - * for the MBean; or
    • - *
    • an {@code UnsupportedOperationException} if creating MBeans is not - * supported by this {@code MBeanServer} implementation. - *
    - */ - 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"); - } - - - /** - *

    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 Set names = 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 Set queryMBeans(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 Set queryNames(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, + Queue postRegisterQueue) { + 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 Map moiTb = 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 Map 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. + *

    + * @since 1.7 + */ +public abstract class HandlerInterceptor + 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 static Map 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; i 0) + 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 <code>com.sun.jmx.namespace</code> package + + + +

    The 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 javax.management.namespace + package. +

    + + 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. + *

    + * 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 + public T 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 + public T 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 ThreadLocal prefix = + 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. + **/ + public T 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. + **/ + public T 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 <code>com.sun.jmx.namespace.serial</code> package + + + +

    The 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 javax.management.namespace.JMXNamespaces +

    + + 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 PrivilegedAction 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.List component = 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]; + /** * Private SystemTray 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 as Thread(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 new Thread object. This constructor has - * the same effect as Thread(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 whose run 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 new Thread object. This constructor has - * the same effect as Thread(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 whose run 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 new Thread object. This constructor has - * the same effect as Thread(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 new Thread object. This constructor has - * the same effect as Thread(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 new Thread object. This constructor has - * the same effect as Thread(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 whose run 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 new Thread 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 by group. - *

    - * If group is null and there is a - * security manager, the group is determined by the security manager's - * getThreadGroup method. If group is - * null and there is not a security manager, or the - * security manager's getThreadGroup 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 - * or setContextClassLoader methods. - * This may result in a SecurityException. - - *

    - * If the target argument is not null, the - * run method of the target is called when - * this thread is started. If the target argument is - * null, this thread's run 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 whose run 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 new Thread object so that it has - * target as its run object, has the specified - * name as its name, belongs to the thread group referred to - * by group, 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() { + 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 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 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 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 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 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: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Option NameDescription
    {@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
    + *
    + * Additional (implementation specific) options may also be supported. + * *

    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.

    + * 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: + * + *
      + * + *
    1. 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.

    2. + * + *
    3. 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.

    4. + * + *
    5. 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.

    6. + * + *
    + * + *

    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: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Option NameDescription
    {@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
    + *
    + * Additional (implementation specific) options may also be supported. * *

    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: + *

    +     * bind(local, 0);
    +     * 
    + * + * @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. + * + *

    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: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Option NameDescription
    {@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
    + *
    + * Additional (implementation specific) options may also be supported. + * *

    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 abstract SocketChannel 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} -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.

    * * @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 @@ *
  • 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, - * or objectName may be omitted. If the - * member is omitted, the # may be too (but + *

    One or more of the mbeanServerName, className, + * member, or objectName may be omitted. If the + * mbeanServerName is omitted, the :: may be too (but + * does not have to be). + * If the member is omitted, the # may be too (but * does not have to be). If the objectName 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, * or objectName 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; + + /** * Parse actions 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 the name 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 the mbeanServerName 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 "*", p's * className always matches it. If it is "a.*", p's * className matches it if it begins with "a.".

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

    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.

      + * 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 instantiate methods, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, null, "instantiate")}.

    + * 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.

    * *
  • 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")}. + *

    * * * @@ -264,6 +295,8 @@ * is sent as described above.

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

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

    * * @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 postRegister * (MBeanRegistration interface) method of the MBean throws a - * RuntimeException, the createMBean method will + * RuntimeException, the createMBean method will * throw a RuntimeMBeanException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preRegister, in which case the MBean * will not be registered. * @exception RuntimeErrorException If the postRegister * (MBeanRegistration interface) method of the MBean throws an - * Error, the createMBean method will + * Error, the createMBean method will * throw a RuntimeErrorException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeErrorException can * also be thrown by preRegister, in which case the MBean * will not be registered. @@ -150,19 +150,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If the postRegister * (MBeanRegistration interface) method of the MBean throws a - * RuntimeException, the createMBean method will + * RuntimeException, the createMBean method will * throw a RuntimeMBeanException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preRegister, in which case the MBean * will not be registered. * @exception RuntimeErrorException If the postRegister * (MBeanRegistration interface) method of the MBean throws an - * Error, the createMBean method will + * Error, the createMBean method will * throw a RuntimeErrorException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeErrorException can * also be thrown by preRegister, in which case the MBean * will not be registered. @@ -225,19 +225,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If the postRegister * (MBeanRegistration interface) method of the MBean throws a - * RuntimeException, the createMBean method will + * RuntimeException, the createMBean method will * throw a RuntimeMBeanException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preRegister, in which case the MBean * will not be registered. * @exception RuntimeErrorException If the postRegister * (MBeanRegistration interface) method of the MBean throws an - * Error, the createMBean method will + * Error, the createMBean method will * throw a RuntimeErrorException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeErrorException can * also be thrown by preRegister, in which case the MBean * will not be registered. @@ -297,19 +297,19 @@ * MBean will not be registered. * @exception RuntimeMBeanException If the postRegister * (MBeanRegistration interface) method of the MBean throws a - * RuntimeException, the createMBean method will + * RuntimeException, the createMBean method will * throw a RuntimeMBeanException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preRegister, in which case the MBean * will not be registered. * @exception RuntimeErrorException If the postRegister method * (MBeanRegistration interface) method of the MBean throws an - * Error, the createMBean method will + * Error, the createMBean method will * throw a RuntimeErrorException, although the MBean creation * and registration succeeded. In such a case, the MBean will be actually - * registered even though the createMBean method + * registered even though the createMBean method * threw an exception. Note that RuntimeErrorException can * also be thrown by preRegister, in which case the MBean * will not be registered. @@ -351,19 +351,19 @@ * has thrown an exception. * @exception RuntimeMBeanException If the postDeregister * (MBeanRegistration interface) method of the MBean throws a - * RuntimeException, the unregisterMBean method + * RuntimeException, the unregisterMBean method * will throw a RuntimeMBeanException, although the MBean * unregistration succeeded. In such a case, the MBean will be actually - * unregistered even though the unregisterMBean method + * unregistered even though the unregisterMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preDeregister, in which case the MBean * will remain registered. * @exception RuntimeErrorException If the postDeregister * (MBeanRegistration interface) method of the MBean throws an - * Error, the unregisterMBean method will + * Error, the unregisterMBean method will * throw a RuntimeErrorException, although the MBean * unregistration succeeded. In such a case, the MBean will be actually - * unregistered even though the unregisterMBean method + * unregistered even though the unregisterMBean method * threw an exception. Note that RuntimeMBeanException can * also be thrown by preDeregister, 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 findMBeanServer to return a reference to + * this MBeanServer object.

    + * + * @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 imply {@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. findMBeanServer 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.

    + * + * @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 imply {@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 @@ ArrayList result = 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 or createNamedMBeanServer + * methods and not subsequently released with releaseMBeanServer.

    + *

    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 + * matching mbeanServerName 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 the MBeanServerId 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 calling findMBeanServerByName({@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 + List findMBeanServerByName(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, * if server is null, 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 ArrayList mBeanServerList = - 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() { public Object run() throws InstanceNotFoundException { @@ -731,6 +734,7 @@ String classname = oi.getClassName(); MBeanPermission perm = new MBeanPermission( + serverName, classname, null, name, @@ -746,6 +750,20 @@ return true; } + private String getMBeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedAction action = new PrivilegedAction() { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + // ------------------------------------ // private variables // ------------------------------------ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXDomain.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXDomain.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,382 @@ +/* + * 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.ListenerNotFoundException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +/** + * A special {@link JMXNamespace} that can handle part of + * the MBeanServer local name space. + *

    + * A {@code JMXDomain} makes a domain X of a + * {@linkplain #getSourceServer() source MBean server} appear in the same domain + * X of a containing {@code MBeanServer} in which the + * {@code JMXDomain} MBean {@linkplain #getMBeanServer() is registered}. + *

    + *

    + * The JMX infrastructure of the containing {@code MBeanServer} takes care of + * routing all calls to MBeans whose names have domain X to the + * {@linkplain #getSourceServer() source MBean server} exported by the + * {@code JMXDomain} MBean in charge of domain X. + *

    + *

    + * The {@linkplain #getSourceServer() source MBean server} of a {@code JMXDomain} + * can, but need not be a regular {@code MBeanServer} created through + * the {@link javax.management.MBeanServerFactory}. It could also be, + * for instance, an instance of a subclass of {@link MBeanServerSupport}, + * or a custom object implementing the {@link MBeanServer} interface. + *

    + * + *

    Differences between {@code JMXNamespace} and {@code JMXDomain}

    + * + *

    + * A {@code JMXDomain} is a special kind of {@code JMXNamespace}. + * A {@code JMXNamespace} such as {@code foo//} is triggered by an + * {@code ObjectName} that begins with the string {@code foo//}, for example + * {@code foo//bar:type=Baz}. A {@code JMXDomain} such as {@code foo} is + * triggered by an {@code ObjectName} with that exact domain, for example + * {@code foo:type=Baz}. A client can immediately see that an MBean is + * handled by a {@code JMXNamespace} because of the {@code //} in the name. + * A client cannot see whether a name such as {@code foo:type=Baz} is an + * ordinary MBean or is handled by a {@code JMXDomain}. + *

    + * + *

    + * A {@linkplain MBeanServer#queryNames query} on the containing {@code + * MBeanserver} will return all MBeans from the {@code JMXDomain} that match + * the query. In particular, {@code queryNames(null, null)} will return all + * MBeans including those from {@code JMXDomain} domains. On the other hand, + * a query will not include MBeans from a {@code JMXNamespace} unless the + * {@code ObjectName} pattern in the query starts with the name of that + * namespace. + *

    + * + *

    Permission checks

    + * + *

    + * When a JMXDomain MBean is registered in a containing + * MBean server created through the default {@link + * javax.management.MBeanServerBuilder}, and if a {@link + * SecurityManager SecurityManager} is + * {@linkplain System#getSecurityManager() present}, the containing MBeanServer will + * check an {@link javax.management.MBeanPermission} before invoking + * any method on the {@linkplain #getSourceServer() source MBeanServer} of the + * JMXDomain. + *

    + * + *

    First, if there is no security manager ({@link + * System#getSecurityManager()} is null), that containing + * {@code MBeanServer} is free not to make any checks. + *

    + * + *

    + * Assuming that there is a security manager, or that the + * implementation chooses to make checks anyway, the containing + * {@code MBeanServer} will perform + * {@link javax.management.MBeanPermission MBeanPermission} checks + * for access to the MBeans in domain X handled by a {@code JMXDomain} + * in the same way that it would do for MBeans registered in its own local + * repository, and as described in + * the MBeanServer interface, with the following exceptions: + *

    + * + *

    + * For those permissions that require a {@code className}, the + * className is the + * string returned by {@link #getSourceServer() getSourceServer()}. + * {@link MBeanServer#getObjectInstance(ObjectName) + * getObjectInstance(mbeanName)}. + * {@link javax.management.ObjectInstance#getClassName() getClassName()}, + * except for {@code createMBean} and {@code registerMBean} operations, + * for which the permission checks are performed as follows: + *

    + *
      + *
    • For {@code createMBean} operations, the {@code className} of the + * permission you need is the {@code className} passed as first parameter + * to {@code createMBean}.

      + * + *
    • For {@code registerMBean} operations, the {@code className} of the + * permission you need is the name of the class of the mbean object, as + * returned by {@code mbean.getClass().getClassName()}, where + * {@code mbean} is the mbean reference passed as first parameter + * to {@code registerMBean}.

      + * + *
    • In addition, for {@code createMBean} and {@code registerMBean}, the + * permission you need is checked with the {@linkplain ObjectName object name} of + * the mbean that is passed as second parameter to the {@code createMBean} or + * {@code registerMBean} operation. + *

      + * + *
    • Contrarily to what is done for regular MBeans registered in the + * MBeanServer local repository, the containing MBeanServer will not + * check the {@link javax.management.MBeanTrustPermission#MBeanTrustPermission(String) + * MBeanTrustPermission("register")} against the protection domain + * of the MBean's class. This check can be performed by the + * {@linkplain #getSourceServer source MBean server} implementation, + * if necessary. + *

      + *
    + * + *

    If a security check fails, the method throws {@link + * SecurityException}.

    + * + *

    For methods that can throw {@link InstanceNotFoundException}, + * this exception is thrown for a non-existent MBean, regardless of + * permissions. This is because a non-existent MBean has no + * className.

    + * + * All these checks are performed by the containing {@code MBeanServer}, + * before accessing the JMXDomain {@linkplain #getSourceServer source MBean server}. + * The implementation of the JMXDomain {@linkplain #getSourceServer source MBean + * server} is free to make any additional checks. In fact, if the JMXDomain + * {@linkplain #getSourceServer source MBean server} is an {@code MBeanServer} + * obtained through the {@link javax.management.MBeanServerFactory}, it will + * again make permission checks as described in the + * MBeanServer interface. + * + *

    See the MBeanServer interface + * for more details on permission checks.

    + * + * @since 1.7 + */ +public class JMXDomain extends JMXNamespace { + + + /** + * This constant contains the value of the {@code type} + * key used in defining a standard JMXDomain MBean object name. + * By definition, a standard JMXDomain MBean object name must be of + * the form: + *
    +     * {@code ":"}+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
    +     * 
    + */ + public static final String TYPE = "JMXDomain"; + + /** + * This constant contains the value of the standard + * {@linkplain javax.management.ObjectName#getKeyPropertyListString() key + * property list string} for JMXDomain MBean object names. + * By definition, a standard JMXDomain MBean object name must be of + * the form: + *
    +     * {@code }+":"+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
    +     * 
    + */ + public static final String TYPE_ASSIGNMENT = "type="+TYPE; + + + + /** + * Creates a new instance of JMXDomain. The MBeans contained in this + * domain are handled by the {@code virtualServer} object given to + * this constructor. Frequently, this will be an instance of + * {@link MBeanServerSupport}. + * @param virtualServer The virtual server that acts as a container for + * the MBeans handled by this JMXDomain object. Frequently, this will + * be an instance of {@link MBeanServerSupport} + * @see JMXNamespace#JMXNamespace(MBeanServer) + */ + public JMXDomain(MBeanServer virtualServer) { + super(virtualServer); + } + + /** + * Return the name of domain handled by this JMXDomain. + * @return the domain handled by this JMXDomain. + * @throws IOException - if the domain cannot be determined, + * for instance, if the MBean is not registered yet. + */ + @Override + public final String getDefaultDomain() { + final ObjectName name = getObjectName(); + if (name == null) + throw new IllegalStateException("DefaultDomain is not yet known"); + final String dom = name.getDomain(); + return dom; + } + + /** + * Returns a singleton array, containing the only domain handled by + * this JMXDomain object. This is + * {@code new String[] {getDefaultDomain()}}. + * @return the only domain handled by this JMXDomain. + * @throws IOException if the domain cannot be determined, + * for instance, if the MBean is not registered yet. + * @see #getDefaultDomain() + */ + @Override + public final String[] getDomains() { + return new String[] {getDefaultDomain()}; + } + + /** + * This method returns the number of MBeans in the domain handled + * by this JMXDomain object. The default implementation is: + *
    +     *    getSourceServer().queryNames(
    +     *        new ObjectName(getObjectName().getDomain()+":*"), null).size();
    +     * 
    + * If this JMXDomain is not yet registered, this method returns 0. + * Subclasses can override the above behavior and provide a better + * implementation. + *

    + * The getMBeanCount() method is called when computing the number + * of MBeans in the {@linkplain #getMBeanServer() containing MBeanServer}. + * @return the number of MBeans in this domain, or 0. + */ + @Override + public Integer getMBeanCount() { + final ObjectName name = getObjectName(); + if (name == null) return 0; + try { + return getSourceServer(). + queryNames(ObjectName.WILDCARD.withDomain(name.getDomain()), + null).size(); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("Unexpected exception: "+x,x); + } + } + + + + /** + * Return a canonical handler name for the provided local + * domain name, or null if the provided domain name is + * {@code null}. + * If not null, the handler name returned will be + * {@code domain+":type="+}{@link #TYPE TYPE}, for example + * {@code foo:type=JMXDomain}. + * @param domain A domain name + * @return a canonical ObjectName for a domain handler. + * @throws IllegalArgumentException if the provided + * domain is not valid - e.g it contains "//". + */ + public static ObjectName getDomainObjectName(String domain) { + if (domain == null) return null; + if (domain.contains(NAMESPACE_SEPARATOR)) + throw new IllegalArgumentException(domain); + try { + return ObjectName.getInstance(domain, "type", TYPE); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(domain,x); + } + } + + + /** + * 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. + **/ + @Override + 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 = getDomainObjectName(dirName); + if (!supliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + supliedName); + + return supliedName; + } + + /** + * This method is called by the JMX framework to register a + * NotificationListener that will forward {@linkplain + * javax.management.MBeanServerNotification mbean server notifications} + * through the delegate of the {@linkplain #getMBeanServer() + * containing MBeanServer}. + * The default implementation of this method is to call + *

    +     *    getSourceServer().addNotificationListener(
    +     *           MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
    +     * 
    + * Subclasses can redefine this behavior if needed. In particular, + * subclasses can send their own instances of {@link + * javax.management.MBeanServerNotification} by calling + * {@code listener.handleNotification()}. + * + * @param listener The MBeanServerNotification listener for this domain. + * @param filter A notification filter. + */ + public void addMBeanServerNotificationListener( + NotificationListener listener, NotificationFilter filter) { + try { + getSourceServer().addNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, listener, filter, null); + } catch(InstanceNotFoundException x) { + throw new UnsupportedOperationException( + "Unexpected exception: " + + "Emission of MBeanServerNotification disabled.", x); + } + } + + /** + * This method is called by the JMX framework to remove the + * NotificationListener that was added with {@link + * #addMBeanServerNotificationListener addMBeanServerNotificationListener}. + * The default implementation of this method is to call + *
    +     *    getSourceServer().removeNotificationListener(
    +     *           MBeanServerDelegate.DELEGATE_NAME, listener);
    +     * 
    + * Subclasses can redefine this behavior if needed. + * + * @param listener The MBeanServerNotification listener for this domain. + * @throws ListenerNotFoundException if the listener is not found. + */ + public void removeMBeanServerNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + try { + getSourceServer().removeNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, listener); + } catch(InstanceNotFoundException x) { + throw new UnsupportedOperationException( + "Unexpected exception: " + + "Emission of MBeanServerNotification disabled.", x); + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/namespace/JMXNamespace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespace.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,660 @@ +/* + * 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; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * MBean Servers can be federated into a single hierarchical name space: + * A JMXNamespace is an MBean that handles a sub name space in that + * hierarchical name space. + *

    + * A name space is created simply by registering a {@code JMXNamespace} + * MBean in the MBean Server. The name of the created name space is defined + * by the {@linkplain JMXNamespaces#getNamespaceObjectName name of the JMXNamespace} + * that handles it. A name space is equivalent to + * an MBean Server within an MBean Server. When creating a {@code JMXNamespace}, + * the MBean Server within is passed to the constructor. + *

    + *

    + * The {@code JMXNamespace} class is the base class for implementing + * all name space handlers. All name space handlers must be instances of + * {@code JMXNamespace} or a subclass of it. + *

    + *

    + * A concrete example of a {@code JMXNamespace} MBean subclass + * is the {@link JMXRemoteNamespace JMXRemoteNamespace} MBean which + * is able to mirror all MBeans contained in a remote MBean server known by its + * {@link javax.management.remote.JMXServiceURL}. + *

    + *

    + * You can create a local namespace by supplying a newly created MBean Server + * to an instance of {@code JMXNamespace}. For instance: + *

    + * final String namespace = "foo";
    + * final ObjectName namespaceName = {@link JMXNamespaces#getNamespaceObjectName
    + *       JMXNamespaces.getNamespaceObjectName(namespace)};
    + * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()),
    + *                      namespaceName);
    + * 
    + *

    + *

    + * 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: + *

    + *
      + *
    1. + * 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"}) + *
    2. + *
    3. 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"}), + *
    4. + *
    5. 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"}), + *
    6. + *
    7. 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))}). + *
    8. + *
    + *

    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 the JMXNamespacePermission + * 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 or a//**//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, let a//b//D:k=v be an MBean exposing an + * attribute Foo. + * If namespace a is a plain JMXNamespace pointing to + * a local MBeanServer in the same JVM, then the permissions you need + * to get the attribute Foo 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 attribute Foo 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."}. + *

    + *

    Depending on how your namespace hierarchy + * is defined some of these wildcard permission names can be useful:

    + *
    + *    // 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:

    + *
      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      patternmatchesdoesn't match
      **//D:k=va//D:k=v
      + * a//b//D:k=v
      + * a//b//c//D:k=v
      D:k=v
      a//**//D:k=va//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=va//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=va//b//e//D:k=va//b//c//e//D:k=v
      + * because in that case b**
      + * is not a meta-wildcard - and b**
      + * is thus equivalent to b*.
      + *
    + * + *

    If {@code ::} is omitted, then one of + * member or object name may be omitted. + * If the object 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; + + /** + * Parse actions 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; + } + + /** + * Parse name 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. + * If objectName is present, it is of + * the form namespace//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]". + * If objectName is present, it is of + * the form namespace//MBeanName. + * @param actions the action string. + * + * @exception IllegalArgumentException if the name 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 the mbeanServerName 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 the mbeanServerName 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 queryMBeans action + * is considered to include queryNames as well.

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

    + * @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 Set names = + 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 static T 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: + *
      + *
    • 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. + *
    • + *
    + * @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}. + *

    + * 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 Map optionsMap; + + 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, + Map optionsMap) { + 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 mergedResult =
    +     *            new HashSet();
    +     *      mergedResult.addAll(Arrays.asList(myOwnNotifs));
    +     *      mergedResult.addAll(Arrays.asList(parentNotifs));
    +     *      return mergeResult.toArray(
    +     *             new MBeanNotificationInfo[mergedResult.size()]);
    +     * 
    + */ + 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: + *
    • + * 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, Map env) + 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.
    + * 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). + *

    + * @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 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 setMBeanServer() method of the {@link QueryExp} + * object. However, this object can.

    + * + * @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; + } + + /** + *

    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 Set queryMBeans(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}(name, n). See the example + * above.

    + * + * @since 1.7 + */ +public abstract class MBeanServerSupport implements MBeanServer { + + /** + * A logger for this class. + */ + private static final Logger LOG = + JmxProperties.NAMESPACE_LOGGER; + + /** + *

    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:

    + * + *
      + *
    • 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. + *
    + * + * @return the names of all MBeans handled by this object. + */ + protected abstract Set 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 Set getMatchingNames(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 contained ObjectName + * is n, 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: + *

      + *
    • a java.lang.IllegalArgumentException: The className + * passed in parameter is null, the ObjectName passed in + * parameter contains a pattern or no ObjectName is specified + * for the MBean; or
    • + *
    • an {@code UnsupportedOperationException} if creating MBeans is not + * supported by this {@code MBeanServer} implementation. + *
    + */ + 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"); + } + + + /** + *

    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 Set names = 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 Set queryMBeans(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 Set queryNames(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 List listeners = 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(List listeners, 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: + *

    + *
      + *
    1. + * You can use the {@link javax.management.namespace.JMXNamespaceView} + * class shown above, + *
    2. + *
    3. + * or you can directly look for MBeans + * whose names match + * {@code "foo//*:*"}, + *
    4. + *
    5. + * 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}. + *
    6. + *
    + * + *

    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 this CompositeType 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 this CompositeType 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 this CompositeType 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 static Map 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() { - public Object run() { + AccessController.doPrivileged(new PrivilegedAction() { + public String run() { return System.getProperty(PROTOCOL_PROVIDER_PACKAGES); } }); @@ -423,8 +434,7 @@ static Iterator getProviderIterator(final Class providerClass, final ClassLoader loader) { ServiceLoader serviceLoader = - ServiceLoader.load(providerClass, - loader); + ServiceLoader.load(providerClass, loader); return serviceLoader.iterator(); } @@ -528,8 +538,8 @@ } if (loader == null) - loader = - AccessController.doPrivileged(new PrivilegedAction() { + loader = AccessController.doPrivileged( + new PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/remote/JMXServiceURL.java --- a/jdk/src/share/classes/javax/management/remote/JMXServiceURL.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/remote/JMXServiceURL.java Wed Jul 05 16:41:30 2017 +0200 @@ -30,13 +30,14 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; -import java.beans.ConstructorProperties; import java.io.Serializable; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.util.BitSet; import java.util.StringTokenizer; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.InvalidKeyException; /** *

    The address of a JMX API connector server. Instances of this class @@ -273,7 +274,6 @@ * is not possible to find the local host name, or if * port is negative. */ - @ConstructorProperties({"protocol", "host", "port", "URLPath"}) public JMXServiceURL(String protocol, String host, int port, String urlPath) throws MalformedURLException { @@ -338,6 +338,50 @@ validate(); } + /** + *

    Construct a {@code JMXServiceURL} instance from the given + * {@code CompositeData}. The presence of this method means that + * {@code JMXServiceURL} is + * reconstructible in MXBeans.

    + * + *

    (The effect of this method could have been obtained more simply + * with a @{@link java.beans.ConstructorProperties ConstructorProperties} + * annotation on the four-parameter {@linkplain #JMXServiceURL( + * String, String, int, String) constructor}, but that would have meant + * that this API could not be implemented on versions of the Java platform + * that predated the introduction of that annotation.)

    + * + * @param cd a {@code CompositeData} object that must contain items called + * {@code protocol}, {@code host}, and {@code URLPath} of type {@code String} + * and {@code port} of type {@code Integer}. Such an object will be produced + * by the MXBean framework when mapping a {@code JMXServiceURL} + * instance to an Open Data value. + * + * @return a {@code JMXServiceURL} constructed with the protocol, host, + * port, and URL path extracted from the given {@code CompositeData}. + * + * @throws MalformedURLException if the given {@code CompositeData} does + * not contain all the required items with the required types or if the + * resultant URL is syntactically incorrect. + */ + public static JMXServiceURL from(CompositeData cd) + throws MalformedURLException { + try { + String proto = (String) cd.get("protocol"); + String host = (String) cd.get("host"); + int port = (Integer) cd.get("port"); + String urlPath = (String) cd.get("URLPath"); + return new JMXServiceURL(proto, host, port, urlPath); + } catch (RuntimeException e) { + // Could be InvalidKeyException if the item is missing, + // or ClassCastException if it is present but with the wrong type. + MalformedURLException x = new MalformedURLException(e.getMessage()); + x.initCause(e); + throw x; + } + } + private void validate() throws MalformedURLException { // Check protocol diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java --- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -77,6 +77,7 @@ import javax.management.event.EventClientDelegateMBean; import javax.management.event.EventClientNotFoundException; import javax.management.event.FetchingEventForwarder; +import javax.management.namespace.JMXNamespaces; import javax.management.remote.JMXServerErrorException; import javax.management.remote.NotificationResult; import javax.management.remote.TargetedNotification; @@ -1292,11 +1293,27 @@ public void removeNotificationListener(ObjectName name, Integer id) throws InstanceNotFoundException, ListenerNotFoundException, IOException { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("removeNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "removeNotificationListener on name space MBeans. ")); + } forwarder.removeNotificationListener(name,id); } public void removeNotificationListener(ObjectName name, Integer[] ids) throws Exception { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("removeNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "removeNotificationListener on name space MBeans. ")); + } forwarder.removeNotificationListener(name,ids); } @@ -1307,6 +1324,14 @@ public Integer addNotificationListener(ObjectName name, NotificationFilter filter) throws InstanceNotFoundException, IOException { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("addNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "addNotificationListener on name space MBeans. ")); + } return forwarder.addNotificationListener(name,filter); } @@ -1326,6 +1351,7 @@ private final boolean checkNotificationEmission; private final String clientId; private final String connectionId; + private volatile String mbeanServerName; EventSubscriptionManager( MBeanServer mbeanServer, @@ -1343,6 +1369,11 @@ this.connectionId = connectionId; } + private String mbeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + @SuppressWarnings("serial") // no serialVersionUID private class AccessControlFilter implements NotificationFilter { private final NotificationFilter wrapped; @@ -1357,7 +1388,8 @@ try { if (checkNotificationEmission) { ServerNotifForwarder.checkMBeanPermission( - mbeanServer, name, "addNotificationListener"); + mbeanServerName(), mbeanServer, name, + "addNotificationListener"); } notifAC.fetchNotification( connectionId, name, notification, getSubject()); @@ -1392,7 +1424,7 @@ if (notifAC != null) notifAC.removeNotificationListener(connectionId, name, getSubject()); try { - delegate.removeListenerOrSubscriber(clientId,id); + delegate.removeListenerOrSubscriber(clientId, id); } catch (EventClientNotFoundException x) { throw new IOException("Unknown clientId: "+clientId,x); } @@ -1405,7 +1437,7 @@ notifAC.removeNotificationListener(connectionId, name, getSubject()); try { for (Integer id : ids) - delegate.removeListenerOrSubscriber(clientId,id); + delegate.removeListenerOrSubscriber(clientId, id); } catch (EventClientNotFoundException x) { throw new IOException("Unknown clientId: "+clientId,x); } @@ -1867,6 +1899,15 @@ return e; } + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedAction action = new PrivilegedAction() { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + private static final Object[] NO_OBJECTS = new Object[0]; private static final String[] NO_STRINGS = new String[0]; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/javax/swing/Popup.java --- a/jdk/src/share/classes/javax/swing/Popup.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/javax/swing/Popup.java Wed Jul 05 16:41:30 2017 +0200 @@ -26,7 +26,9 @@ package javax.swing; import java.awt.*; + import sun.awt.ModalExclude; +import sun.awt.SunToolkit; /** * Popups are used to display a Component to the user, typically @@ -225,7 +227,12 @@ HeavyWeightWindow(Window parent) { super(parent); setFocusableWindowState(false); - setName("###overrideRedirect###"); + Toolkit tk = Toolkit.getDefaultToolkit(); + if (tk instanceof SunToolkit) { + // all the short-lived windows like Popups should be + // OverrideRedirect on X11 platforms + ((SunToolkit)tk).setOverrideRedirect(this); + } // Popups are typically transient and most likely won't benefit // from true double buffering. Turn it off here. getRootPane().setUseTrueDoubleBuffering(false); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/awt/EmbeddedFrame.java --- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Wed Jul 05 16:41:30 2017 +0200 @@ -257,21 +257,27 @@ Set toTest; Component currentFocused = e.getComponent(); - Component last = getFocusTraversalPolicy().getLastComponent(this); toTest = getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); - if (toTest.contains(stroke) && (currentFocused == last || last == null)) { - if (traverseOut(FORWARD)) { - e.consume(); - return true; + if (toTest.contains(stroke)) { + // 6581899: performance improvement for SortingFocusTraversalPolicy + Component last = getFocusTraversalPolicy().getLastComponent(this); + if (currentFocused == last || last == null) { + if (traverseOut(FORWARD)) { + e.consume(); + return true; + } } } - Component first = getFocusTraversalPolicy().getFirstComponent(this); toTest = getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); - if (toTest.contains(stroke) && (currentFocused == first || first == null)) { - if (traverseOut(BACKWARD)) { - e.consume(); - return true; + if (toTest.contains(stroke)) { + // 6581899: performance improvement for SortingFocusTraversalPolicy + Component first = getFocusTraversalPolicy().getFirstComponent(this); + if (currentFocused == first || first == null) { + if (traverseOut(BACKWARD)) { + e.consume(); + return true; + } } } return false; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/awt/EventQueueItem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/awt/EventQueueItem.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,37 @@ +/* + * 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 sun.awt; + +import java.awt.AWTEvent; + +public class EventQueueItem { + public AWTEvent event; + public EventQueueItem next; + + public EventQueueItem(AWTEvent evt) { + event = evt; + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/awt/SunToolkit.java --- a/jdk/src/share/classes/sun/awt/SunToolkit.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 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 @@ -852,6 +852,15 @@ return AccessController.doPrivileged(new GetBooleanAction("sun.awt.erasebackgroundonresize")); } + + /** + * Makes the window OverrideRedirect, on X11 platforms. See + * ICCCM specification for more details about OverrideRedirect + * windows. Implemented in XToolkit, no-op in WToolkit. + */ + public void setOverrideRedirect(Window target) { + } + static SoftCache imgCache = new SoftCache(); static synchronized Image getImageFromHash(Toolkit tk, URL url) { @@ -2039,12 +2048,3 @@ SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance()); } } // class PostEventQueue - -class EventQueueItem { - AWTEvent event; - EventQueueItem next; - - EventQueueItem(AWTEvent evt) { - event = evt; - } -} // class EventQueueItem diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/misc/JavaNioAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/misc/JavaNioAccess.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,32 @@ +/* + * 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 sun.misc; + +import java.nio.BufferPoolMXBean; + +public interface JavaNioAccess { + BufferPoolMXBean getDirectBufferPoolMXBean(); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/misc/SharedSecrets.java --- a/jdk/src/share/classes/sun/misc/SharedSecrets.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java Wed Jul 05 16:41:30 2017 +0200 @@ -46,6 +46,7 @@ private static JavaIOAccess javaIOAccess; private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; private static JavaNetAccess javaNetAccess; + private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; public static JavaUtilJarAccess javaUtilJarAccess() { @@ -77,6 +78,20 @@ return javaNetAccess; } + public static void setJavaNioAccess(JavaNioAccess jna) { + javaNioAccess = jna; + } + + public static JavaNioAccess getJavaNioAccess() { + if (javaNioAccess == null) { + // Ensure java.nio.ByteOrder is initialized; we know that + // this class initializes java.nio.Bits that provides the + // shared secret. + unsafe.ensureClassInitialized(java.nio.ByteOrder.class); + } + return javaNioAccess; + } + public static void setJavaIOAccess(JavaIOAccess jia) { javaIOAccess = jia; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -31,7 +31,7 @@ import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; -import java.lang.ref.SoftReference; +import java.util.*; /** @@ -47,11 +47,14 @@ private static NativeDispatcher nd = new DatagramDispatcher(); // Our file descriptor - FileDescriptor fd = null; + private final FileDescriptor fd; // fd value needed for dev/poll. This value will remain valid // even after the value in the file descriptor object has been set to -1 - int fdVal; + private final int fdVal; + + // The protocol family of the socket + private final ProtocolFamily family; // IDs of native threads doing reads and writes, for signalling private volatile long readerThread = 0; @@ -59,8 +62,8 @@ // Cached InetAddress and port for unconnected DatagramChannels // used by receive0 - private InetAddress cachedSenderInetAddress = null; - private int cachedSenderPort = 0; + private InetAddress cachedSenderInetAddress; + private int cachedSenderPort; // Lock held by current reading or connecting thread private final Object readLock = new Object(); @@ -76,20 +79,20 @@ // State (does not necessarily increase monotonically) private static final int ST_UNINITIALIZED = -1; - private static int ST_UNCONNECTED = 0; - private static int ST_CONNECTED = 1; + private static final int ST_UNCONNECTED = 0; + private static final int ST_CONNECTED = 1; private static final int ST_KILLED = 2; private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; - SocketAddress remoteAddress = null; - - // Options - private SocketOpts.IP options = null; + private SocketAddress localAddress; + private SocketAddress remoteAddress; // Our socket adaptor, if any - private DatagramSocket socket = null; + private DatagramSocket socket; + + // Multicast support + private MembershipRegistry registry; // -- End of fields protected by stateLock @@ -98,7 +101,26 @@ throws IOException { super(sp); - this.fd = Net.socket(false); + this.family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + this.fd = Net.socket(family, false); + this.fdVal = IOUtil.fdVal(fd); + this.state = ST_UNCONNECTED; + } + + public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) { + super(sp); + if ((family != StandardProtocolFamily.INET) && + (family != StandardProtocolFamily.INET6)) { + throw new UnsupportedOperationException("Protocol family not supported"); + } + if (family == StandardProtocolFamily.INET6) { + if (!Net.isIPv6Available()) { + throw new UnsupportedOperationException("IPv6 not available"); + } + } + this.family = family; + this.fd = Net.socket(family, false); this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; } @@ -107,9 +129,12 @@ throws IOException { super(sp); + this.family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; + this.localAddress = Net.localAddress(fd); } public DatagramSocket socket() { @@ -120,6 +145,156 @@ } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public SocketAddress getConnectedAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return remoteAddress; + } + } + + @Override + public DatagramChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + ensureOpen(); + + if (name == StandardSocketOption.IP_TOS) { + // IPv4 only; no-op for IPv6 + if (family == StandardProtocolFamily.INET) { + Net.setSocketOption(fd, family, name, value); + } + return this; + } + + if (name == StandardSocketOption.IP_MULTICAST_TTL || + name == StandardSocketOption.IP_MULTICAST_LOOP) + { + // options are protocol dependent + Net.setSocketOption(fd, family, name, value); + return this; + } + + if (name == StandardSocketOption.IP_MULTICAST_IF) { + if (value == null) + throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'"); + NetworkInterface interf = (NetworkInterface)value; + if (family == StandardProtocolFamily.INET6) { + int index = interf.getIndex(); + if (index == -1) + throw new IOException("Network interface cannot be identified"); + Net.setInterface6(fd, index); + } else { + // need IPv4 address to identify interface + Inet4Address target = Net.anyInet4Address(interf); + if (target == null) + throw new IOException("Network interface not configured for IPv4"); + int targetAddress = Net.inet4AsInt(target); + Net.setInterface4(fd, targetAddress); + } + return this; + } + + // remaining options don't need any special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + ensureOpen(); + + if (name == StandardSocketOption.IP_TOS) { + // IPv4 only; always return 0 on IPv6 + if (family == StandardProtocolFamily.INET) { + return (T) Net.getSocketOption(fd, family, name); + } else { + return (T) Integer.valueOf(0); + } + } + + if (name == StandardSocketOption.IP_MULTICAST_TTL || + name == StandardSocketOption.IP_MULTICAST_LOOP) + { + return (T) Net.getSocketOption(fd, family, name); + } + + if (name == StandardSocketOption.IP_MULTICAST_IF) { + if (family == StandardProtocolFamily.INET) { + int address = Net.getInterface4(fd); + if (address == 0) + return null; // default interface + + InetAddress ia = Net.inet4FromInt(address); + NetworkInterface ni = NetworkInterface.getByInetAddress(ia); + if (ni == null) + throw new IOException("Unable to map address to interface"); + return (T) ni; + } else { + int index = Net.getInterface6(fd); + if (index == 0) + return null; // default interface + + NetworkInterface ni = NetworkInterface.getByIndex(index); + if (ni == null) + throw new IOException("Unable to map index to interface"); + return (T) ni; + } + } + + // no special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(8); + set.add(StandardSocketOption.SO_SNDBUF); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + set.add(StandardSocketOption.SO_BROADCAST); + set.add(StandardSocketOption.IP_TOS); + set.add(StandardSocketOption.IP_MULTICAST_IF); + set.add(StandardSocketOption.IP_MULTICAST_TTL); + set.add(StandardSocketOption.IP_MULTICAST_LOOP); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + private void ensureOpen() throws ClosedChannelException { if (!isOpen()) throw new ClosedChannelException(); @@ -135,8 +310,10 @@ synchronized (readLock) { ensureOpen(); // If socket is not bound then behave as if nothing received - if (!isBound()) // ## NotYetBoundException ?? + // Will be fixed by 6621699 + if (localAddress() == null) { return null; + } int n = 0; ByteBuffer bb = null; try { @@ -267,6 +444,12 @@ do { n = send(fd, src, target); } while ((n == IOStatus.INTERRUPTED) && isOpen()); + + synchronized (stateLock) { + if (isOpen() && (localAddress == null)) { + localAddress = Net.localAddress(fd); + } + } return IOStatus.normalize(n); } finally { writerThread = 0; @@ -316,7 +499,8 @@ assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - int written = send0(fd, ((DirectBuffer)bb).address() + pos, + boolean preferIPv6 = (family != StandardProtocolFamily.INET); + int written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos, rem, target); if (written > 0) bb.position(pos + written); @@ -453,42 +637,8 @@ IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) - throws IOException - { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP(d); - } - return options; - } - } - - public boolean isBound() { - return Net.localPortNumber(fd) != 0; - } - public SocketAddress localAddress() { synchronized (stateLock) { - if (isConnected() && (localAddress == null)) { - // Socket was not bound before connecting, - // so ask what the address turned out to be - localAddress = Net.localAddress(fd); - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - InetSocketAddress isa = (InetSocketAddress)localAddress; - sm.checkConnect(isa.getAddress().getHostAddress(), -1); - } return localAddress; } } @@ -499,22 +649,37 @@ } } - public void bind(SocketAddress local) throws IOException { + @Override + public DatagramChannel bind(SocketAddress local) throws IOException { synchronized (readLock) { synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); - if (isBound()) + if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa; + if (local == null) { + isa = new InetSocketAddress(0); + } else { + isa = Net.checkAddress(local); + + // only Inet4Address allowed with IPv4 socket + if (family == StandardProtocolFamily.INET) { + InetAddress addr = isa.getAddress(); + if (!(addr instanceof Inet4Address)) + throw new UnsupportedAddressTypeException(); + } + } SecurityManager sm = System.getSecurityManager(); - if (sm != null) + if (sm != null) { sm.checkListen(isa.getPort()); - Net.bind(fd, isa.getAddress(), isa.getPort()); + } + Net.bind(family, fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); } } } + return this; } public boolean isConnected() { @@ -533,7 +698,6 @@ } public DatagramChannel connect(SocketAddress sa) throws IOException { - int trafficClass = 0; int localPort = 0; synchronized(readLock) { @@ -545,10 +709,10 @@ if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); - int n = Net.connect(fd, + int n = Net.connect(family, + fd, isa.getAddress(), - isa.getPort(), - trafficClass); + isa.getPort()); if (n <= 0) throw new Error(); // Can't happen @@ -558,6 +722,11 @@ sender = isa; cachedSenderInetAddress = isa.getAddress(); cachedSenderPort = isa.getPort(); + + // Socket was not bound before connecting, + if (localAddress == null) { + localAddress = Net.localAddress(fd); + } } } } @@ -584,9 +753,215 @@ return this; } + /** + * Joins channel's socket to the given group/interface and + * optional source address. + */ + private MembershipKey innerJoin(InetAddress group, + NetworkInterface interf, + InetAddress source) + throws IOException + { + if (!group.isMulticastAddress()) + throw new IllegalArgumentException("Group not a multicast address"); + + // check multicast address is compatible with this socket + if (!(group instanceof Inet4Address)) { + if (family == StandardProtocolFamily.INET) + throw new IllegalArgumentException("Group is not IPv4 address"); + if (!(group instanceof Inet6Address)) + throw new IllegalArgumentException("Address type not supported"); + } + + // check source address + if (source != null) { + if (source.isAnyLocalAddress()) + throw new IllegalArgumentException("Source address is a wildcard address"); + if (source.isMulticastAddress()) + throw new IllegalArgumentException("Source address is multicast address"); + if (source.getClass() != group.getClass()) + throw new IllegalArgumentException("Source address is different type to group"); + } + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkMulticast(group); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // check the registry to see if we are already a member of the group + if (registry == null) { + registry = new MembershipRegistry(); + } else { + // return existing membership key + MembershipKey key = registry.checkMembership(group, interf, source); + if (key != null) + return key; + } + + MembershipKeyImpl key; + if (family == StandardProtocolFamily.INET6) { + int index = interf.getIndex(); + if (index == -1) + throw new IOException("Network interface cannot be identified"); + + // need multicast and source address as byte arrays + byte[] groupAddress = Net.inet6AsByteArray(group); + byte[] sourceAddress = (source == null) ? null : + Net.inet6AsByteArray(source); + + // join the group + int n = Net.join6(fd, groupAddress, index, sourceAddress); + if (n == IOStatus.UNAVAILABLE) + throw new UnsupportedOperationException(); + + key = new MembershipKeyImpl.Type6(this, group, interf, source, + groupAddress, index, sourceAddress); + + } else { + // need IPv4 address to identify interface + Inet4Address target = Net.anyInet4Address(interf); + if (target == null) + throw new IOException("Network interface not configured for IPv4"); + + int groupAddress = Net.inet4AsInt(group); + int targetAddress = Net.inet4AsInt(target); + int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source); + + // join the group + int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress); + if (n == IOStatus.UNAVAILABLE) + throw new UnsupportedOperationException(); + + key = new MembershipKeyImpl.Type4(this, group, interf, source, + groupAddress, targetAddress, sourceAddress); + } + + registry.add(key); + return key; + } + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf) + throws IOException + { + return innerJoin(group, interf, null); + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf, + InetAddress source) + throws IOException + { + if (source == null) + throw new NullPointerException("source address is null"); + return innerJoin(group, interf, source); + } + + // package-private + void drop(MembershipKeyImpl key) + throws IOException + { + assert key.getChannel() == this; + + synchronized (stateLock) { + if (!key.isValid()) + return; + + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.drop6(fd, key6.group(), key6.index(), key6.source()); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source()); + } + + key.invalidate(); + registry.remove(key); + } + } + + /** + * Block datagrams from given source if a memory to receive all + * datagrams. + */ + void block(MembershipKeyImpl key, InetAddress source) + throws IOException + { + assert key.getChannel() == this; + assert key.getSourceAddress() == null; + + synchronized (stateLock) { + if (!key.isValid()) + throw new IllegalStateException("key is no longer valid"); + if (source.isAnyLocalAddress()) + throw new IllegalArgumentException("Source address is a wildcard address"); + if (source.isMulticastAddress()) + throw new IllegalArgumentException("Source address is multicast address"); + if (source.getClass() != key.getGroup().getClass()) + throw new IllegalArgumentException("Source address is different type to group"); + + int n; + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + n = Net.block6(fd, key6.group(), key6.index(), + Net.inet6AsByteArray(source)); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + n = Net.block4(fd, key4.group(), key4.interfaceAddress(), + Net.inet4AsInt(source)); + } + if (n == IOStatus.UNAVAILABLE) { + // ancient kernel + throw new UnsupportedOperationException(); + } + } + } + + /** + * Unblock given source. + */ + void unblock(MembershipKeyImpl key, InetAddress source) + throws IOException + { + assert key.getChannel() == this; + assert key.getSourceAddress() == null; + + synchronized (stateLock) { + if (!key.isValid()) + throw new IllegalStateException("key is no longer valid"); + + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.unblock6(fd, key6.group(), key6.index(), + Net.inet6AsByteArray(source)); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + Net.unblock4(fd, key4.group(), key4.interfaceAddress(), + Net.inet4AsInt(source)); + } + } + } + protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { nd.preClose(fd); + + // if member of mulitcast group then invalidate all keys + if (registry != null) + registry.invalidateAll(); + long th; if ((th = readerThread) != 0) NativeThread.signal(th); @@ -695,8 +1070,8 @@ boolean connected) throws IOException; - private native int send0(FileDescriptor fd, long address, int len, - SocketAddress sa) + private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len, + SocketAddress sa) throws IOException; static { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java --- a/jdk/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -45,16 +45,9 @@ // The channel being adapted private final DatagramChannelImpl dc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for receives private volatile int timeout = 0; - // Traffic-class/Type-of-service - private volatile int trafficClass = 0; - - // ## super will create a useless impl private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { // Invoke the DatagramSocketAdaptor(SocketAddress) constructor, @@ -82,7 +75,7 @@ throw new IllegalArgumentException("connect: " + port); if (remote == null) throw new IllegalArgumentException("connect: null address"); - if (!isClosed()) + if (isClosed()) return; try { dc.connect(remote); @@ -124,11 +117,11 @@ } public boolean isBound() { - return dc.isBound(); + return dc.localAddress() != null; } public boolean isConnected() { - return dc.isConnected(); + return dc.remoteAddress() != null; } public InetAddress getInetAddress() { @@ -157,7 +150,7 @@ // Legacy DatagramSocket will send in this case // and set address and port of the packet InetSocketAddress isa = (InetSocketAddress) - dc.remoteAddress; + dc.remoteAddress(); p.setPort(isa.getPort()); p.setAddress(isa.getAddress()); dc.write(bb); @@ -241,21 +234,32 @@ public InetAddress getLocalAddress() { if (isClosed()) return null; - try { - return Net.asInetSocketAddress(dc.localAddress()).getAddress(); - } catch (Exception x) { - return new InetSocketAddress(0).getAddress(); + SocketAddress local = dc.localAddress(); + if (local == null) + local = new InetSocketAddress(0); + InetAddress result = ((InetSocketAddress)local).getAddress(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkConnect(result.getHostAddress(), -1); + } catch (SecurityException x) { + return new InetSocketAddress(0).getAddress(); + } } + return result; } public int getLocalPort() { if (isClosed()) return -1; try { - return Net.asInetSocketAddress(dc.localAddress()).getPort(); + SocketAddress local = dc.getLocalAddress(); + if (local != null) { + return ((InetSocketAddress)local).getPort(); + } } catch (Exception x) { - return 0; } + return 0; } public void setSoTimeout(int timeout) throws SocketException { @@ -266,55 +270,87 @@ return timeout; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(dc); - return opts; + private void setBooleanOption(SocketOption name, boolean value) + throws SocketException + { + try { + dc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private void setIntOption(SocketOption name, int value) + throws SocketException + { + try { + dc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private boolean getBooleanOption(SocketOption name) throws SocketException { + try { + return dc.getOption(name).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // keep compiler happy + } + } + + private int getIntOption(SocketOption name) throws SocketException { + try { + return dc.getOption(name).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // keep compiler happy + } } public void setSendBufferSize(int size) throws SocketException { - opts().setSendBufferSize(size); + if (size <= 0) + throw new IllegalArgumentException("Invalid send size"); + setIntOption(StandardSocketOption.SO_SNDBUF, size); } public int getSendBufferSize() throws SocketException { - return opts().getSendBufferSize(); + return getIntOption(StandardSocketOption.SO_SNDBUF); } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + if (size <= 0) + throw new IllegalArgumentException("Invalid receive size"); + setIntOption(StandardSocketOption.SO_RCVBUF, size); } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + return getIntOption(StandardSocketOption.SO_RCVBUF); } public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + setBooleanOption(StandardSocketOption.SO_REUSEADDR, on); } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + return getBooleanOption(StandardSocketOption.SO_REUSEADDR); + } public void setBroadcast(boolean on) throws SocketException { - opts().setBroadcast(on); + setBooleanOption(StandardSocketOption.SO_BROADCAST, on); } public boolean getBroadcast() throws SocketException { - return opts().getBroadcast(); + return getBooleanOption(StandardSocketOption.SO_BROADCAST); } public void setTrafficClass(int tc) throws SocketException { - opts().setTrafficClass(tc); - trafficClass = tc; + setIntOption(StandardSocketOption.IP_TOS, tc); } public int getTrafficClass() throws SocketException { - int tc = opts().getTrafficClass(); - if (tc < 0) { - tc = trafficClass; - } - return tc; + return getIntOption(StandardSocketOption.IP_TOS); } public void close() { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,44 @@ +/* + * 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 sun.nio.ch; + +import java.net.SocketOption; + +/** + * Defines socket options that are supported by the implementation + * but not defined in StandardSocketOption. + */ + +class ExtendedSocketOption { + private ExtendedSocketOption() { } + + static final SocketOption SO_OOBINLINE = + new SocketOption() { + public String name() { return "SO_OOBINLINE"; } + public Class type() { return Boolean.class; } + public String toString() { return name(); } + }; +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -32,6 +32,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; +import java.nio.BufferPoolMXBean; import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.ArrayList; @@ -43,10 +44,12 @@ import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + import sun.misc.Cleaner; import sun.security.action.GetPropertyAction; - public class FileChannelImpl extends FileChannel { @@ -681,14 +684,26 @@ private static class Unmapper implements Runnable { + // keep track of mapped buffer usage + static volatile int count; + static volatile long totalSize; + static volatile long totalCapacity; private long address; private long size; + private int cap; - private Unmapper(long address, long size) { + private Unmapper(long address, long size, int cap) { assert (address != 0); this.address = address; this.size = size; + this.cap = cap; + + synchronized (Unmapper.class) { + count++; + totalSize += size; + totalCapacity += cap; + } } public void run() { @@ -696,8 +711,13 @@ return; unmap0(address, size); address = 0; + + synchronized (Unmapper.class) { + count--; + totalSize -= size; + totalCapacity -= cap; + } } - } private static void unmap(MappedByteBuffer bb) { @@ -786,7 +806,7 @@ assert (IOStatus.checkAll(addr)); assert (addr % allocationGranularity == 0); int isize = (int)size; - Unmapper um = new Unmapper(addr, size + pagePosition); + Unmapper um = new Unmapper(addr, size + pagePosition, isize); if ((!writable) || (imode == MAP_RO)) return Util.newMappedByteBufferR(isize, addr + pagePosition, um); else @@ -797,6 +817,49 @@ } } + /** + * Returns the management interface for mapped buffers + */ + public static BufferPoolMXBean getMappedBufferPoolMXBean() { + return LazyInitialization.mappedBufferPoolMXBean; + } + + // Lazy initialization of management interface + private static class LazyInitialization { + static final BufferPoolMXBean mappedBufferPoolMXBean = mappedBufferPoolMXBean(); + + private static BufferPoolMXBean mappedBufferPoolMXBean() { + final String pool = "mapped"; + 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 Unmapper.count; + } + @Override + public long getTotalCapacity() { + return Unmapper.totalCapacity; + } + @Override + public long getMemoryUsed() { + return Unmapper.totalSize; + } + }; + } + } // -- Locks -- diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,222 @@ +/* + * 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 sun.nio.ch; + +import java.nio.channels.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.io.IOException; +import java.util.HashSet; + +/** + * MembershipKey implementation. + */ + +class MembershipKeyImpl + extends MembershipKey +{ + private final MulticastChannel ch; + private final InetAddress group; + private final NetworkInterface interf; + private final InetAddress source; + + // true when key is valid + private volatile boolean valid = true; + + // lock used when creating or accessing blockedSet + private Object stateLock = new Object(); + + // set of source addresses that are blocked + private HashSet blockedSet; + + private MembershipKeyImpl(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source) + { + this.ch = ch; + this.group = group; + this.interf = interf; + this.source = source; + } + + /** + * MembershipKey will additional context for IPv4 membership + */ + static class Type4 extends MembershipKeyImpl { + private final int groupAddress; + private final int interfAddress; + private final int sourceAddress; + + Type4(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source, + int groupAddress, + int interfAddress, + int sourceAddress) + { + super(ch, group, interf, source); + this.groupAddress = groupAddress; + this.interfAddress = interfAddress; + this.sourceAddress = sourceAddress; + } + + int group() { + return groupAddress; + } + + int interfaceAddress() { + return interfAddress; + } + + int source() { + return sourceAddress; + } + } + + /** + * MembershipKey will additional context for IPv6 membership + */ + static class Type6 extends MembershipKeyImpl { + private final byte[] groupAddress; + private final int index; + private final byte[] sourceAddress; + + Type6(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source, + byte[] groupAddress, + int index, + byte[] sourceAddress) + { + super(ch, group, interf, source); + this.groupAddress = groupAddress; + this.index = index; + this.sourceAddress = sourceAddress; + } + + byte[] group() { + return groupAddress; + } + + int index() { + return index; + } + + byte[] source() { + return sourceAddress; + } + } + + public boolean isValid() { + return valid; + } + + // package-private + void invalidate() { + valid = false; + } + + public void drop() throws IOException { + // delegate to channel + ((DatagramChannelImpl)ch).drop(this); + } + + @Override + public MulticastChannel getChannel() { + return ch; + } + + @Override + public InetAddress getGroup() { + return group; + } + + @Override + public NetworkInterface getNetworkInterface() { + return interf; + } + + @Override + public InetAddress getSourceAddress() { + return source; + } + + @Override + public MembershipKey block(InetAddress toBlock) + throws IOException + { + if (source != null) + throw new IllegalStateException("key is source-specific"); + + synchronized (stateLock) { + if ((blockedSet != null) && blockedSet.contains(toBlock)) { + // already blocked, nothing to do + return this; + } + + ((DatagramChannelImpl)ch).block(this, toBlock); + + // created blocked set if required and add source address + if (blockedSet == null) + blockedSet = new HashSet(); + blockedSet.add(toBlock); + } + return this; + } + + @Override + public MembershipKey unblock(InetAddress toUnblock) + throws IOException + { + synchronized (stateLock) { + if ((blockedSet == null) || !blockedSet.contains(toUnblock)) + throw new IllegalStateException("not blocked"); + + ((DatagramChannelImpl)ch).unblock(this, toUnblock); + + blockedSet.remove(toUnblock); + } + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(64); + sb.append('<'); + sb.append(group.getHostAddress()); + sb.append(','); + sb.append(interf.getName()); + if (source != null) { + sb.append(','); + sb.append(source.getHostAddress()); + } + sb.append('>'); + return sb.toString(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,129 @@ +/* + * 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 sun.nio.ch; + +import java.nio.channels.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.*; + +/** + * Simple registry of membership keys for a MulticastChannel. + * + * Instances of this object are not safe by multiple concurrent threads. + */ + +class MembershipRegistry { + + // map multicast group to keys + private Map> groups = null; + + MembershipRegistry() { + } + + /** + * Checks registry for membership of the group on the given + * network interface. + */ + MembershipKey checkMembership(InetAddress group, NetworkInterface interf, + InetAddress source) + { + if (groups != null) { + List keys = groups.get(group); + if (keys != null) { + for (MembershipKeyImpl key: keys) { + if (key.getNetworkInterface().equals(interf)) { + // already a member to receive all packets so return + // existing key or detect conflict + if (source == null) { + if (key.getSourceAddress() == null) + return key; + throw new IllegalStateException("Already a member to receive all packets"); + } + + // already have source-specific membership so return key + // or detect conflict + if (key.getSourceAddress() == null) + throw new IllegalStateException("Already have source-specific membership"); + if (source.equals(key.getSourceAddress())) + return key; + } + } + } + } + return null; + } + + /** + * Add membership to the registry, returning a new membership key. + */ + void add(MembershipKeyImpl key) { + InetAddress group = key.getGroup(); + List keys; + if (groups == null) { + groups = new HashMap>(); + keys = null; + } else { + keys = groups.get(group); + } + if (keys == null) { + keys = new LinkedList(); + groups.put(group, keys); + } + keys.add(key); + } + + /** + * Remove a key from the registry + */ + void remove(MembershipKeyImpl key) { + InetAddress group = key.getGroup(); + List keys = groups.get(group); + if (keys != null) { + Iterator i = keys.iterator(); + while (i.hasNext()) { + if (i.next() == key) { + i.remove(); + break; + } + } + if (keys.isEmpty()) { + groups.remove(group); + } + } + } + + /** + * Invalidate all keys in the registry + */ + void invalidateAll() { + for (InetAddress group: groups.keySet()) { + for (MembershipKeyImpl key: groups.get(group)) { + key.invalidate(); + } + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/Net.java --- a/jdk/src/share/classes/sun/nio/ch/Net.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/Net.java Wed Jul 05 16:41:30 2017 +0200 @@ -26,21 +26,43 @@ package sun.nio.ch; import java.io.*; -import java.lang.reflect.*; import java.net.*; import java.nio.channels.*; +import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; class Net { // package-private private Net() { } + // unspecified protocol family + static final ProtocolFamily UNSPEC = new ProtocolFamily() { + public String name() { + return "UNSPEC"; + } + }; // -- Miscellaneous utilities -- + private static volatile boolean checkedIPv6 = false; + private static volatile boolean isIPv6Available; + + /** + * Tells whether dual-IPv4/IPv6 sockets should be used. + */ + static boolean isIPv6Available() { + if (!checkedIPv6) { + isIPv6Available = isIPv6Available0(); + checkedIPv6 = true; + } + return isIPv6Available; + } + static InetSocketAddress checkAddress(SocketAddress sa) { if (sa == null) - throw new IllegalArgumentException(); + throw new NullPointerException(); if (!(sa instanceof InetSocketAddress)) throw new UnsupportedAddressTypeException(); // ## needs arg InetSocketAddress isa = (InetSocketAddress)sa; @@ -63,6 +85,8 @@ Exception nx = x; if (x instanceof ClosedChannelException) nx = new SocketException("Socket is closed"); + else if (x instanceof NotYetConnectedException) + nx = new SocketException("Socket is not connected"); else if (x instanceof AlreadyBoundException) nx = new SocketException("Already bound"); else if (x instanceof NotYetBoundException) @@ -105,73 +129,359 @@ translateException(x, false); } + /** + * Returns any IPv4 address of the given network interface, or + * null if the interface does not have any IPv4 addresses. + */ + static Inet4Address anyInet4Address(final NetworkInterface interf) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Inet4Address run() { + Enumeration addrs = interf.getInetAddresses(); + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); + if (addr instanceof Inet4Address) { + return (Inet4Address)addr; + } + } + return null; + } + }); + } + + /** + * Returns an IPv4 address as an int. + */ + static int inet4AsInt(InetAddress ia) { + if (ia instanceof Inet4Address) { + byte[] addr = ia.getAddress(); + int address = addr[3] & 0xFF; + address |= ((addr[2] << 8) & 0xFF00); + address |= ((addr[1] << 16) & 0xFF0000); + address |= ((addr[0] << 24) & 0xFF000000); + return address; + } + throw new AssertionError("Should not reach here"); + } + + /** + * Returns an InetAddress from the given IPv4 address + * represented as an int. + */ + static InetAddress inet4FromInt(int address) { + byte[] addr = new byte[4]; + addr[0] = (byte) ((address >>> 24) & 0xFF); + addr[1] = (byte) ((address >>> 16) & 0xFF); + addr[2] = (byte) ((address >>> 8) & 0xFF); + addr[3] = (byte) (address & 0xFF); + try { + return InetAddress.getByAddress(addr); + } catch (UnknownHostException uhe) { + throw new AssertionError("Should not reach here"); + } + } + + /** + * Returns an IPv6 address as a byte array + */ + static byte[] inet6AsByteArray(InetAddress ia) { + if (ia instanceof Inet6Address) { + return ia.getAddress(); + } + + // need to construct IPv4-mapped address + if (ia instanceof Inet4Address) { + byte[] ip4address = ia.getAddress(); + byte[] address = new byte[16]; + address[10] = (byte)0xff; + address[11] = (byte)0xff; + address[12] = ip4address[0]; + address[13] = ip4address[1]; + address[14] = ip4address[2]; + address[15] = ip4address[3]; + return address; + } + + throw new AssertionError("Should not reach here"); + } + + // -- Socket options + + static void setSocketOption(FileDescriptor fd, ProtocolFamily family, + SocketOption name, Object value) + throws IOException + { + if (value == null) + throw new IllegalArgumentException("Invalid option value"); + + // only simple values supported by this method + Class type = name.type(); + if (type != Integer.class && type != Boolean.class) + throw new AssertionError("Should not reach here"); + + // special handling + if (name == StandardSocketOption.SO_RCVBUF || + name == StandardSocketOption.SO_SNDBUF) + { + int i = ((Integer)value).intValue(); + if (i < 0) + throw new IllegalArgumentException("Invalid send/receive buffer size"); + } + if (name == StandardSocketOption.SO_LINGER) { + int i = ((Integer)value).intValue(); + if (i < 0) + value = Integer.valueOf(-1); + if (i > 65535) + value = Integer.valueOf(65535); + } + if (name == StandardSocketOption.IP_TOS) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid IP_TOS value"); + } + if (name == StandardSocketOption.IP_MULTICAST_TTL) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid TTL/hop value"); + } + + // map option name to platform level/name + OptionKey key = SocketOptionRegistry.findOption(name, family); + if (key == null) + throw new AssertionError("Option not found"); + + int arg; + if (type == Integer.class) { + arg = ((Integer)value).intValue(); + } else { + boolean b = ((Boolean)value).booleanValue(); + arg = (b) ? 1 : 0; + } + + boolean mayNeedConversion = (family == UNSPEC); + setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg); + } + + static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, + SocketOption name) + throws IOException + { + Class type = name.type(); + + // only simple values supported by this method + if (type != Integer.class && type != Boolean.class) + throw new AssertionError("Should not reach here"); + + // map option name to platform level/name + OptionKey key = SocketOptionRegistry.findOption(name, family); + if (key == null) + throw new AssertionError("Option not found"); + + boolean mayNeedConversion = (family == UNSPEC); + int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name()); + + if (type == Integer.class) { + return Integer.valueOf(value); + } else { + return (value == 0) ? Boolean.FALSE : Boolean.TRUE; + } + } // -- Socket operations -- + static native boolean isIPv6Available0(); + static FileDescriptor socket(boolean stream) { - return IOUtil.newFD(socket0(stream, false)); + return socket(UNSPEC, stream); + } + + static FileDescriptor socket(ProtocolFamily family, boolean stream) { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + return IOUtil.newFD(socket0(preferIPv6, stream, false)); } static FileDescriptor serverSocket(boolean stream) { - return IOUtil.newFD(socket0(stream, true)); + return IOUtil.newFD(socket0(isIPv6Available(), stream, true)); } // Due to oddities SO_REUSEADDR on windows reuse is ignored - private static native int socket0(boolean stream, boolean reuse); + private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse); + + static void bind(FileDescriptor fd, InetAddress addr, int port) + throws IOException + { + bind(UNSPEC, fd, addr, port); + } - static native void bind(FileDescriptor fd, InetAddress addr, int port) + static void bind(ProtocolFamily family, FileDescriptor fd, + InetAddress addr, int port) throws IOException + { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + bind0(preferIPv6, fd, addr, port); + } + + private static native void bind0(boolean preferIPv6, FileDescriptor fd, + InetAddress addr, int port) throws IOException; - static native int connect(FileDescriptor fd, - InetAddress remote, - int remotePort, - int trafficClass) + static native void listen(FileDescriptor fd, int backlog) throws IOException; + + static int connect(FileDescriptor fd, InetAddress remote, int remotePort) + throws IOException + { + return connect(UNSPEC, fd, remote, remotePort); + } + + static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort) + throws IOException + { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + return connect0(preferIPv6, fd, remote, remotePort); + } + + private static native int connect0(boolean preferIPv6, + FileDescriptor fd, + InetAddress remote, + int remotePort) throws IOException; + public final static int SHUT_RD = 0; + public final static int SHUT_WR = 1; + public final static int SHUT_RDWR = 2; + + static native void shutdown(FileDescriptor fd, int how) throws IOException; + private static native int localPort(FileDescriptor fd) throws IOException; private static native InetAddress localInetAddress(FileDescriptor fd) throws IOException; - static InetSocketAddress localAddress(FileDescriptor fd) { - try { - return new InetSocketAddress(localInetAddress(fd), - localPort(fd)); - } catch (IOException x) { - throw new Error(x); // Can't happen - } + static InetSocketAddress localAddress(FileDescriptor fd) + throws IOException + { + return new InetSocketAddress(localInetAddress(fd), localPort(fd)); + } + + private static native int remotePort(FileDescriptor fd) + throws IOException; + + private static native InetAddress remoteInetAddress(FileDescriptor fd) + throws IOException; + + static InetSocketAddress remoteAddress(FileDescriptor fd) + throws IOException + { + return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd)); } - static int localPortNumber(FileDescriptor fd) { - try { - return localPort(fd); - } catch (IOException x) { - throw new Error(x); // Can't happen - } + private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion, + int level, int opt) + throws IOException; + + private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, + int level, int opt, int arg) + throws IOException; + + // -- Multicast support -- + + + /** + * Join IPv4 multicast group + */ + static int join4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + return joinOrDrop4(true, fd, group, interf, source); + } + + /** + * Drop membership of IPv4 multicast group + */ + static void drop4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + joinOrDrop4(false, fd, group, interf, source); + } + + private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source) + throws IOException; + + /** + * Block IPv4 source + */ + static int block4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + return blockOrUnblock4(true, fd, group, interf, source); } - private static native int getIntOption0(FileDescriptor fd, int opt) + /** + * Unblock IPv6 source + */ + static void unblock4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + blockOrUnblock4(false, fd, group, interf, source); + } + + private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group, + int interf, int source) throws IOException; - static int getIntOption(FileDescriptor fd, int opt) + /** + * Join IPv6 multicast group + */ + static int join6(FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException { - return getIntOption0(fd, opt); + return joinOrDrop6(true, fd, group, index, source); + } + + /** + * Drop membership of IPv6 multicast group + */ + static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException + { + joinOrDrop6(false, fd, group, index, source); } - - private static native void setIntOption0(FileDescriptor fd, - int opt, int arg) + private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException; - static void setIntOption(FileDescriptor fd, int opt, int arg) + /** + * Block IPv6 source + */ + static int block6(FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException { - setIntOption0(fd, opt, arg); + return blockOrUnblock6(true, fd, group, index, source); + } + + /** + * Unblock IPv6 source + */ + static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException + { + blockOrUnblock6(false, fd, group, index, source); } + static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException; + + static native void setInterface4(FileDescriptor fd, int interf) throws IOException; + + static native int getInterface4(FileDescriptor fd) throws IOException; + + static native void setInterface6(FileDescriptor fd, int index) throws IOException; + + static native int getInterface6(FileDescriptor fd) throws IOException; + private static native void initIDs(); static { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/OptionAdaptor.java --- a/jdk/src/share/classes/sun/nio/ch/OptionAdaptor.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; - - -// Adaptor class for java.net-style options -// -// The option get/set methods in the socket, server-socket, and datagram-socket -// adaptors delegate to an instance of this class. -// - -class OptionAdaptor { // package-private - - private final SocketOpts.IP opts; - - OptionAdaptor(SocketChannelImpl sc) { - opts = (SocketOpts.IP)sc.options(); - } - - OptionAdaptor(ServerSocketChannelImpl ssc) { - opts = (SocketOpts.IP)ssc.options(); - } - - OptionAdaptor(DatagramChannelImpl dc) { - opts = (SocketOpts.IP)dc.options(); - } - - private SocketOpts.IP opts() { - return opts; - } - - private SocketOpts.IP.TCP tcpOpts() { - return (SocketOpts.IP.TCP)opts; - } - - public void setTcpNoDelay(boolean on) throws SocketException { - try { - tcpOpts().noDelay(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getTcpNoDelay() throws SocketException { - try { - return tcpOpts().noDelay(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setSoLinger(boolean on, int linger) throws SocketException { - try { - if (linger > 65535) - linger = 65535; - opts().linger(on ? linger : -1); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getSoLinger() throws SocketException { - try { - return opts().linger(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setOOBInline(boolean on) throws SocketException { - try { - opts().outOfBandInline(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getOOBInline() throws SocketException { - try { - return opts().outOfBandInline(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setSendBufferSize(int size) - throws SocketException - { - try { - opts().sendBufferSize(size); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getSendBufferSize() throws SocketException { - try { - return opts().sendBufferSize(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setReceiveBufferSize(int size) - throws SocketException - { - try { - opts().receiveBufferSize(size); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getReceiveBufferSize() throws SocketException { - try { - return opts().receiveBufferSize(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setKeepAlive(boolean on) throws SocketException { - try { - opts().keepAlive(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getKeepAlive() throws SocketException { - try { - return opts().keepAlive(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setTrafficClass(int tc) throws SocketException { - if (tc < 0 || tc > 255) - throw new IllegalArgumentException("tc is not in range 0 -- 255"); - try { - opts().typeOfService(tc); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getTrafficClass() throws SocketException { - try { - return opts().typeOfService(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setReuseAddress(boolean on) - throws SocketException - { - try { - opts().reuseAddress(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getReuseAddress() throws SocketException { - try { - return opts().reuseAddress(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setBroadcast(boolean on) - throws SocketException - { - try { - opts().broadcast(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getBroadcast() throws SocketException { - try { - return opts().broadcast(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/OptionKey.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/OptionKey.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,48 @@ +/* + * 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 sun.nio.ch; + +/** + * Represents the level/name of a socket option + */ + +class OptionKey { + private int level; + private int name; + + OptionKey(int level, int name) { + this.level = level; + this.name = name; + } + + int level() { + return level; + } + + int name() { + return name; + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/SelectorProviderImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SelectorProviderImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/SelectorProviderImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -29,6 +29,7 @@ import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; +import java.net.ProtocolFamily; import java.nio.channels.*; import java.nio.channels.spi.*; @@ -41,6 +42,10 @@ return new DatagramChannelImpl(this); } + public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { + return new DatagramChannelImpl(this, family); + } + public Pipe openPipe() throws IOException { return new PipeImpl(this); } @@ -54,5 +59,4 @@ public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } - } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -44,9 +44,6 @@ // The channel being adapted private final ServerSocketChannelImpl ssc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for accepts private volatile int timeout = 0; @@ -174,18 +171,21 @@ return timeout; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(ssc); - return opts; - } - public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + try { + ssc.setOption(StandardSocketOption.SO_REUSEADDR, on); + } catch (IOException x) { + Net.translateToSocketException(x); + } } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + try { + return ssc.getOption(StandardSocketOption.SO_REUSEADDR).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // Never happens + } } public String toString() { @@ -197,11 +197,23 @@ } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + // size 0 valid for ServerSocketChannel, invalid for ServerSocket + if (size <= 0) + throw new IllegalArgumentException("size cannot be 0 or negative"); + try { + ssc.setOption(StandardSocketOption.SO_RCVBUF, size); + } catch (IOException x) { + Net.translateToSocketException(x); + } } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + try { + return ssc.getOption(StandardSocketOption.SO_RCVBUF).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // Never happens + } } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -33,8 +33,7 @@ import java.nio.channels.spi.*; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.HashSet; -import java.util.Iterator; +import java.util.*; /** @@ -75,10 +74,7 @@ private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; // null => unbound - - // Options, created on demand - private SocketOpts.IP.TCP options = null; + private SocketAddress localAddress; // null => unbound // Our socket adaptor, if any ServerSocket socket; @@ -103,7 +99,6 @@ localAddress = Net.localAddress(fd); } - public ServerSocket socket() { synchronized (stateLock) { if (socket == null) @@ -112,6 +107,69 @@ } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public ServerSocketChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // no options that require special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // no options that require special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(2); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + public boolean isBound() { synchronized (stateLock) { return localAddress != null; @@ -124,22 +182,25 @@ } } - public void bind(SocketAddress local, int backlog) throws IOException { + @Override + public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { synchronized (lock) { if (!isOpen()) throw new ClosedChannelException(); if (isBound()) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : + Net.checkAddress(local); SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkListen(isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); - listen(fd, backlog < 1 ? 50 : backlog); + Net.listen(fd, backlog < 1 ? 50 : backlog); synchronized (stateLock) { localAddress = Net.localAddress(fd); } } + return this; } public SocketChannel accept() throws IOException { @@ -196,24 +257,6 @@ IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) throws IOException { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP.TCP(d); - } - return options; - } - } - protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { nd.preClose(fd); @@ -320,9 +363,6 @@ // -- Native methods -- - private static native void listen(FileDescriptor fd, int backlog) - throws IOException; - // Accepts a new connection, setting the given file descriptor to refer to // the new socket and setting isaa[0] to the socket's remote address. // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java --- a/jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java Wed Jul 05 16:41:30 2017 +0200 @@ -54,16 +54,9 @@ // The channel being adapted private final SocketChannelImpl sc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for reads private volatile int timeout = 0; - // Traffic-class/Type-of-service - private volatile int trafficClass = 0; - - // ## super will create a useless impl private SocketAdaptor(SocketChannelImpl sc) { this.sc = sc; @@ -145,8 +138,6 @@ public void bind(SocketAddress local) throws IOException { try { - if (local == null) - local = new InetSocketAddress(0); sc.bind(local); } catch (Exception x) { Net.translateException(x); @@ -154,27 +145,39 @@ } public InetAddress getInetAddress() { - if (!sc.isConnected()) + SocketAddress remote = sc.remoteAddress(); + if (remote == null) { return null; - return Net.asInetSocketAddress(sc.remoteAddress()).getAddress(); + } else { + return ((InetSocketAddress)remote).getAddress(); + } } public InetAddress getLocalAddress() { - if (!sc.isBound()) - return new InetSocketAddress(0).getAddress(); - return Net.asInetSocketAddress(sc.localAddress()).getAddress(); + if (sc.isOpen()) { + SocketAddress local = sc.localAddress(); + if (local != null) + return ((InetSocketAddress)local).getAddress(); + } + return new InetSocketAddress(0).getAddress(); } public int getPort() { - if (!sc.isConnected()) + SocketAddress remote = sc.remoteAddress(); + if (remote == null) { return 0; - return Net.asInetSocketAddress(sc.remoteAddress()).getPort(); + } else { + return ((InetSocketAddress)remote).getPort(); + } } public int getLocalPort() { - if (!sc.isBound()) + SocketAddress local = sc.localAddress(); + if (local == null) { return -1; - return Net.asInetSocketAddress(sc.localAddress()).getPort(); + } else { + return ((InetSocketAddress)local).getPort(); + } } private class SocketInputStream @@ -276,26 +279,60 @@ return os; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(sc); - return opts; + private void setBooleanOption(SocketOption name, boolean value) + throws SocketException + { + try { + sc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private void setIntOption(SocketOption name, int value) + throws SocketException + { + try { + sc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private boolean getBooleanOption(SocketOption name) throws SocketException { + try { + return sc.getOption(name).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // keep compiler happy + } + } + + private int getIntOption(SocketOption name) throws SocketException { + try { + return sc.getOption(name).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // keep compiler happy + } } public void setTcpNoDelay(boolean on) throws SocketException { - opts().setTcpNoDelay(on); + setBooleanOption(StandardSocketOption.TCP_NODELAY, on); } public boolean getTcpNoDelay() throws SocketException { - return opts().getTcpNoDelay(); + return getBooleanOption(StandardSocketOption.TCP_NODELAY); } public void setSoLinger(boolean on, int linger) throws SocketException { - opts().setSoLinger(on, linger); + if (!on) + linger = -1; + setIntOption(StandardSocketOption.SO_LINGER, linger); } public int getSoLinger() throws SocketException { - return opts().getSoLinger(); + return getIntOption(StandardSocketOption.SO_LINGER); } public void sendUrgentData(int data) throws IOException { @@ -303,11 +340,11 @@ } public void setOOBInline(boolean on) throws SocketException { - opts().setOOBInline(on); + setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on); } public boolean getOOBInline() throws SocketException { - return opts().getOOBInline(); + return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE); } public void setSoTimeout(int timeout) throws SocketException { @@ -321,48 +358,49 @@ } public void setSendBufferSize(int size) throws SocketException { - opts().setSendBufferSize(size); + // size 0 valid for SocketChannel, invalid for Socket + if (size <= 0) + throw new IllegalArgumentException("Invalid send size"); + setIntOption(StandardSocketOption.SO_SNDBUF, size); } public int getSendBufferSize() throws SocketException { - return opts().getSendBufferSize(); + return getIntOption(StandardSocketOption.SO_SNDBUF); } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + // size 0 valid for SocketChannel, invalid for Socket + if (size <= 0) + throw new IllegalArgumentException("Invalid receive size"); + setIntOption(StandardSocketOption.SO_RCVBUF, size); } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + return getIntOption(StandardSocketOption.SO_RCVBUF); } public void setKeepAlive(boolean on) throws SocketException { - opts().setKeepAlive(on); + setBooleanOption(StandardSocketOption.SO_KEEPALIVE, on); } public boolean getKeepAlive() throws SocketException { - return opts().getKeepAlive(); + return getBooleanOption(StandardSocketOption.SO_KEEPALIVE); } public void setTrafficClass(int tc) throws SocketException { - opts().setTrafficClass(tc); - trafficClass = tc; + setIntOption(StandardSocketOption.IP_TOS, tc); } public int getTrafficClass() throws SocketException { - int tc = opts().getTrafficClass(); - if (tc < 0) { - tc = trafficClass; - } - return tc; + return getIntOption(StandardSocketOption.IP_TOS); } public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + setBooleanOption(StandardSocketOption.SO_REUSEADDR, on); } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + return getBooleanOption(StandardSocketOption.SO_REUSEADDR); } public void close() throws IOException { @@ -402,7 +440,7 @@ } public boolean isBound() { - return sc.isBound(); + return sc.localAddress() != null; } public boolean isClosed() { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Wed Jul 05 16:41:30 2017 +0200 @@ -31,6 +31,7 @@ import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; +import java.util.*; /** @@ -78,19 +79,16 @@ private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; - private SocketAddress remoteAddress = null; + private SocketAddress localAddress; + private SocketAddress remoteAddress; // Input/Output open private boolean isInputOpen = true; private boolean isOutputOpen = true; private boolean readyToConnect = false; - // Options, created on demand - private SocketOpts.IP.TCP options = null; - // Socket adaptor, created on demand - private Socket socket = null; + private Socket socket; // -- End of fields protected by stateLock @@ -114,6 +112,7 @@ this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_CONNECTED; + this.localAddress = Net.localAddress(fd); this.remoteAddress = remote; } @@ -125,6 +124,98 @@ } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public SocketAddress getConnectedAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return remoteAddress; + } + } + + @Override + public SocketChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // special handling for IP_TOS: no-op when IPv6 + if (name == StandardSocketOption.IP_TOS) { + if (!Net.isIPv6Available()) + Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); + return this; + } + + // no options that require special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // special handling for IP_TOS: always return 0 when IPv6 + if (name == StandardSocketOption.IP_TOS) { + return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : + (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name); + } + + // no options that require special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(8); + set.add(StandardSocketOption.SO_SNDBUF); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_KEEPALIVE); + set.add(StandardSocketOption.SO_REUSEADDR); + set.add(StandardSocketOption.SO_LINGER); + set.add(StandardSocketOption.TCP_NODELAY); + // additional options required by socket adaptor + set.add(StandardSocketOption.IP_TOS); + set.add(ExtendedSocketOption.SO_OOBINLINE); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + private boolean ensureReadOpen() throws ClosedChannelException { synchronized (stateLock) { if (!isOpen()) @@ -410,43 +501,8 @@ IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) - throws IOException - { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP.TCP(d); - } - return options; - } - } - - public boolean isBound() { - synchronized (stateLock) { - if (state == ST_CONNECTED) - return true; - return localAddress != null; - } - } - public SocketAddress localAddress() { synchronized (stateLock) { - if (state == ST_CONNECTED && - (localAddress == null || - ((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress())) { - // Socket was not bound before connecting or - // Socket was bound with an "anyLocalAddress" - localAddress = Net.localAddress(fd); - } return localAddress; } } @@ -457,19 +513,25 @@ } } - public void bind(SocketAddress local) throws IOException { + @Override + public SocketChannel bind(SocketAddress local) throws IOException { synchronized (readLock) { synchronized (writeLock) { synchronized (stateLock) { - ensureOpenAndUnconnected(); + if (!isOpen()) + throw new ClosedChannelException(); + if (state == ST_PENDING) + throw new ConnectionPendingException(); if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa = (local == null) ? + new InetSocketAddress(0) : Net.checkAddress(local); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); } } } + return this; } public boolean isConnected() { @@ -496,7 +558,6 @@ } public boolean connect(SocketAddress sa) throws IOException { - int trafficClass = 0; // ## Pick up from options int localPort = 0; synchronized (readLock) { @@ -524,13 +585,24 @@ ia = InetAddress.getLocalHost(); n = Net.connect(fd, ia, - isa.getPort(), - trafficClass); + isa.getPort()); if ( (n == IOStatus.INTERRUPTED) && isOpen()) continue; break; } + + synchronized (stateLock) { + if (isOpen() && (localAddress == null) || + ((InetSocketAddress)localAddress) + .getAddress().isAnyLocalAddress()) + { + // Socket was not bound before connecting or + // Socket was bound with an "anyLocalAddress" + localAddress = Net.localAddress(fd); + } + } + } finally { readerCleanup(); end((n > 0) || (n == IOStatus.UNAVAILABLE)); @@ -646,29 +718,37 @@ } } - public final static int SHUT_RD = 0; - public final static int SHUT_WR = 1; - public final static int SHUT_RDWR = 2; - - public void shutdownInput() throws IOException { + @Override + public SocketChannel shutdownInput() throws IOException { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); - isInputOpen = false; - shutdown(fd, SHUT_RD); - if (readerThread != 0) - NativeThread.signal(readerThread); + if (!isConnected()) + throw new NotYetConnectedException(); + if (isInputOpen) { + Net.shutdown(fd, Net.SHUT_RD); + if (readerThread != 0) + NativeThread.signal(readerThread); + isInputOpen = false; + } + return this; } } - public void shutdownOutput() throws IOException { + @Override + public SocketChannel shutdownOutput() throws IOException { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); - isOutputOpen = false; - shutdown(fd, SHUT_WR); - if (writerThread != 0) - NativeThread.signal(writerThread); + if (!isConnected()) + throw new NotYetConnectedException(); + if (isOutputOpen) { + Net.shutdown(fd, Net.SHUT_WR); + if (writerThread != 0) + NativeThread.signal(writerThread); + isOutputOpen = false; + } + return this; } } @@ -869,9 +949,6 @@ boolean block, boolean ready) throws IOException; - private static native void shutdown(FileDescriptor fd, int how) - throws IOException; - static { Util.load(); nd = new SocketDispatcher(); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/SocketOpts.java --- a/jdk/src/share/classes/sun/nio/ch/SocketOpts.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.IOException; -import java.nio.*; -import java.net.NetworkInterface; - - -// Typical use: -// -// sc.options() -// .noDelay(true) -// .typeOfService(SocketOpts.IP.TOS_RELIABILITY) -// .sendBufferSize(1024) -// .receiveBufferSize(1024) -// .keepAlive(true); -// - - -public interface SocketOpts { // SocketOptions already used in java.net - - // Options that apply to all kinds of sockets - - // SO_BROADCAST - public abstract boolean broadcast() throws IOException; - public abstract SocketOpts broadcast(boolean b) throws IOException; - - // SO_KEEPALIVE - public abstract boolean keepAlive() throws IOException; - public abstract SocketOpts keepAlive(boolean b) throws IOException; - - // SO_LINGER - public abstract int linger() throws IOException; - public abstract SocketOpts linger(int n) throws IOException; - - // SO_OOBINLINE - public abstract boolean outOfBandInline() throws IOException; - public abstract SocketOpts outOfBandInline(boolean b) throws IOException; - - // SO_RCVBUF - public abstract int receiveBufferSize() throws IOException; - public abstract SocketOpts receiveBufferSize(int n) throws IOException; - - // SO_SNDBUF - public abstract int sendBufferSize() throws IOException; - public abstract SocketOpts sendBufferSize(int n) throws IOException; - - // SO_REUSEADDR - public abstract boolean reuseAddress() throws IOException; - public abstract SocketOpts reuseAddress(boolean b) throws IOException; - - - // IP-specific options - - public static interface IP - extends SocketOpts - { - - // IP_MULTICAST_IF2 - public abstract NetworkInterface multicastInterface() - throws IOException; - public abstract IP multicastInterface(NetworkInterface ni) - throws IOException; - - // IP_MULTICAST_LOOP - public abstract boolean multicastLoop() throws IOException; - public abstract IP multicastLoop(boolean b) throws IOException; - - // IP_TOS - public static final int TOS_LOWDELAY = 0x10; - public static final int TOS_THROUGHPUT = 0x08; - public static final int TOS_RELIABILITY = 0x04; - public static final int TOS_MINCOST = 0x02; - public abstract int typeOfService() throws IOException; - public abstract IP typeOfService(int tos) throws IOException; - - - // TCP-specific options - - public static interface TCP - extends IP - { - // TCP_NODELAY - public abstract boolean noDelay() throws IOException; - public abstract TCP noDelay(boolean b) throws IOException; - - } - - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/SocketOptsImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SocketOptsImpl.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,318 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.NetworkInterface; -import java.net.SocketOptions; -import java.nio.channels.*; - - -class SocketOptsImpl - implements SocketOpts -{ - - static abstract class Dispatcher { - abstract int getInt(int opt) throws IOException; - abstract void setInt(int opt, int arg) throws IOException; - // Others that pass addresses, etc., will come later - } - - private final Dispatcher d; - - SocketOptsImpl(Dispatcher d) { - this.d = d; - } - - protected boolean getBoolean(int opt) throws IOException { - return d.getInt(opt) > 0; - } - - protected void setBoolean(int opt, boolean b) throws IOException { - d.setInt(opt, b ? 1 : 0); - } - - protected int getInt(int opt) throws IOException { - return d.getInt(opt); - } - - protected void setInt(int opt, int n) throws IOException { - d.setInt(opt, n); - } - - protected NetworkInterface getNetworkInterface(int opt) - throws IOException - { - throw new UnsupportedOperationException("NYI"); - } - - protected void setNetworkInterface(int opt, NetworkInterface ni) - throws IOException - { - throw new UnsupportedOperationException("NYI"); - } - - protected void addToString(StringBuffer sb, String s) { - char c = sb.charAt(sb.length() - 1); - if ((c != '[') && (c != '=')) - sb.append(' '); - sb.append(s); - } - - protected void addToString(StringBuffer sb, int n) { - addToString(sb, Integer.toString(n)); - } - - - // SO_BROADCAST - - public boolean broadcast() throws IOException { - return getBoolean(SocketOptions.SO_BROADCAST); - } - - public SocketOpts broadcast(boolean b) throws IOException { - setBoolean(SocketOptions.SO_BROADCAST, b); - return this; - } - - - // SO_KEEPALIVE - - public boolean keepAlive() throws IOException { - return getBoolean(SocketOptions.SO_KEEPALIVE); - } - - public SocketOpts keepAlive(boolean b) throws IOException { - setBoolean(SocketOptions.SO_KEEPALIVE, b); - return this; - } - - - // SO_LINGER - - public int linger() throws IOException { - return getInt(SocketOptions.SO_LINGER); - } - - public SocketOpts linger(int n) throws IOException { - setInt(SocketOptions.SO_LINGER, n); - return this; - } - - - // SO_OOBINLINE - - public boolean outOfBandInline() throws IOException { - return getBoolean(SocketOptions.SO_OOBINLINE); - } - - public SocketOpts outOfBandInline(boolean b) throws IOException { - setBoolean(SocketOptions.SO_OOBINLINE, b); - return this; - } - - - // SO_RCVBUF - - public int receiveBufferSize() throws IOException { - return getInt(SocketOptions.SO_RCVBUF); - } - - public SocketOpts receiveBufferSize(int n) throws IOException { - if (n <= 0) - throw new IllegalArgumentException("Invalid receive size"); - setInt(SocketOptions.SO_RCVBUF, n); - return this; - } - - - // SO_SNDBUF - - public int sendBufferSize() throws IOException { - return getInt(SocketOptions.SO_SNDBUF); - } - - public SocketOpts sendBufferSize(int n) throws IOException { - if (n <= 0) - throw new IllegalArgumentException("Invalid send size"); - setInt(SocketOptions.SO_SNDBUF, n); - return this; - } - - - // SO_REUSEADDR - - public boolean reuseAddress() throws IOException { - return getBoolean(SocketOptions.SO_REUSEADDR); - } - - public SocketOpts reuseAddress(boolean b) throws IOException { - setBoolean(SocketOptions.SO_REUSEADDR, b); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - int n; - if (broadcast()) - addToString(sb, "broadcast"); - if (keepAlive()) - addToString(sb, "keepalive"); - if ((n = linger()) > 0) { - addToString(sb, "linger="); - addToString(sb, n); - } - if (outOfBandInline()) - addToString(sb, "oobinline"); - if ((n = receiveBufferSize()) > 0) { - addToString(sb, "rcvbuf="); - addToString(sb, n); - } - if ((n = sendBufferSize()) > 0) { - addToString(sb, "sndbuf="); - addToString(sb, n); - } - if (reuseAddress()) - addToString(sb, "reuseaddr"); - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(this.getClass().getInterfaces()[0].getName()); - sb.append('['); - int i = sb.length(); - try { - toString(sb); - } catch (IOException x) { - sb.setLength(i); - sb.append("closed"); - } - sb.append(']'); - return sb.toString(); - } - - - // IP-specific socket options - - static class IP - extends SocketOptsImpl - implements SocketOpts.IP - { - - IP(Dispatcher d) { - super(d); - } - - - // IP_MULTICAST_IF2 - // ## Do we need IP_MULTICAST_IF also? - - public NetworkInterface multicastInterface() throws IOException { - return getNetworkInterface(SocketOptions.IP_MULTICAST_IF2); - } - - public SocketOpts.IP multicastInterface(NetworkInterface ni) - throws IOException - { - setNetworkInterface(SocketOptions.IP_MULTICAST_IF2, ni); - return this; - } - - - // IP_MULTICAST_LOOP - - public boolean multicastLoop() throws IOException { - return getBoolean(SocketOptions.IP_MULTICAST_LOOP); - } - - public SocketOpts.IP multicastLoop(boolean b) throws IOException { - setBoolean(SocketOptions.IP_MULTICAST_LOOP, b); - return this; - } - - - // IP_TOS - - public int typeOfService() throws IOException { - return getInt(SocketOptions.IP_TOS); - } - - public SocketOpts.IP typeOfService(int tos) throws IOException { - setInt(SocketOptions.IP_TOS, tos); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - super.toString(sb); - int n; - if ((n = typeOfService()) > 0) { - addToString(sb, "tos="); - addToString(sb, n); - } - } - - - // TCP-specific IP options - - public static class TCP - extends SocketOptsImpl.IP - implements SocketOpts.IP.TCP - { - - TCP(Dispatcher d) { - super(d); - } - - // TCP_NODELAY - - public boolean noDelay() throws IOException { - return getBoolean(SocketOptions.TCP_NODELAY); - } - - public SocketOpts.IP.TCP noDelay(boolean b) throws IOException { - setBoolean(SocketOptions.TCP_NODELAY, b); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - super.toString(sb); - if (noDelay()) - addToString(sb, "nodelay"); - } - - } - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/ch/exceptions --- a/jdk/src/share/classes/sun/nio/ch/exceptions Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -# -# Copyright 2000-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. -# - -# Generated exception classes for sun.nio.ch - -SINCE=1.4 -PACKAGE=sun.nio.ch -# This year should only change if the generated source is modified. -COPYRIGHT_YEARS=2000-2007 - - -SUPER=IllegalStateException - -gen AlreadyBoundException " - * Unchecked exception thrown when an attempt is made to bind a {@link - * SocketChannel} that is already bound." \ - 9002280723481772026L diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java --- a/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java Wed Jul 05 16:41:30 2017 +0200 @@ -916,7 +916,7 @@ "ccsid01140", "cp01140", "1140", - // "ebcdic-us-037+euro" + "ebcdic-us-037+euro" }); charset("IBM01141", "IBM1141", @@ -925,7 +925,7 @@ "ccsid01141", "cp01141", "1141", - // "ebcdic-de-273+euro" + "ebcdic-de-273+euro" }); charset("IBM01142", "IBM1142", @@ -934,8 +934,8 @@ "ccsid01142", "cp01142", "1142", - // "ebcdic-no-277+euro", - // "ebcdic-dk-277+euro" + "ebcdic-no-277+euro", + "ebcdic-dk-277+euro" }); charset("IBM01143", "IBM1143", @@ -944,8 +944,8 @@ "ccsid01143", "cp01143", "1143", - // "ebcdic-fi-278+euro", - // "ebcdic-se-278+euro" + "ebcdic-fi-278+euro", + "ebcdic-se-278+euro" }); charset("IBM01144", "IBM1144", @@ -954,7 +954,7 @@ "ccsid01144", "cp01144", "1144", - // "ebcdic-it-280+euro" + "ebcdic-it-280+euro" }); charset("IBM01145", "IBM1145", @@ -963,7 +963,7 @@ "ccsid01145", "cp01145", "1145", - // "ebcdic-es-284+euro" + "ebcdic-es-284+euro" }); charset("IBM01146", "IBM1146", @@ -972,7 +972,7 @@ "ccsid01146", "cp01146", "1146", - // "ebcdic-gb-285+euro" + "ebcdic-gb-285+euro" }); charset("IBM01147", "IBM1147", @@ -981,7 +981,7 @@ "ccsid01147", "cp01147", "1147", - // "ebcdic-fr-277+euro" + "ebcdic-fr-277+euro" }); charset("IBM01148", "IBM1148", @@ -990,7 +990,7 @@ "ccsid01148", "cp01148", "1148", - // "ebcdic-international-500+euro" + "ebcdic-international-500+euro" }); charset("IBM01149", "IBM1149", @@ -999,7 +999,7 @@ "ccsid01149", "cp01149", "1149", - // "ebcdic-s-871+euro" + "ebcdic-s-871+euro" }); // Macintosh MacOS/Apple char encodingd diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/nio/cs/standard-charsets --- a/jdk/src/share/classes/sun/nio/cs/standard-charsets Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/cs/standard-charsets Wed Jul 05 16:41:30 2017 +0200 @@ -314,6 +314,7 @@ alias ccsid00858 alias cp00858 alias 858 + alias PC-Multilingual-850+euro charset IBM862 IBM862 alias cp862 #JDK historical diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java --- a/jdk/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java Wed Jul 05 16:41:30 2017 +0200 @@ -25,6 +25,7 @@ package sun.reflect.generics.factory; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Method; @@ -118,7 +119,10 @@ } public Type makeArrayType(Type componentType){ - return GenericArrayTypeImpl.make(componentType); + if (componentType instanceof Class) + return Array.newInstance((Class) componentType, 0).getClass(); + else + return GenericArrayTypeImpl.make(componentType); } public Type makeByte(){return byte.class;} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/native/java/net/net_util.c --- a/jdk/src/share/native/java/net/net_util.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/native/java/net/net_util.c Wed Jul 05 16:41:30 2017 +0200 @@ -82,7 +82,7 @@ } } -jobject +JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; init(env); @@ -159,7 +159,7 @@ return iaObj; } -jint +JNIEXPORT jint JNICALL NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) { jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/native/java/net/net_util.h --- a/jdk/src/share/native/java/net/net_util.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/native/java/net/net_util.h Wed Jul 05 16:41:30 2017 +0200 @@ -116,7 +116,7 @@ JNIEXPORT int JNICALL NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress); -jobject +JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port); void initLocalAddrTable (); @@ -124,10 +124,10 @@ void NET_SetTrafficClass(struct sockaddr *him, int trafficClass); -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him); -jint +JNIEXPORT jint JNICALL NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj); int diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/native/java/nio/Bits.c --- a/jdk/src/share/native/java/nio/Bits.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/share/native/java/nio/Bits.c Wed Jul 05 16:41:30 2017 +0200 @@ -68,46 +68,6 @@ ((jlong)SWAPINT((jint)((x) >> 32)) & 0xffffffff))) JNIEXPORT void JNICALL -Java_java_nio_Bits_copyFromByteArray(JNIEnv *env, jobject this, jobject src, - jlong srcPos, jlong dstAddr, jlong length) -{ - jbyte *bytes; - size_t size; - - while (length > 0) { - size = (length > MBYTE ? MBYTE : length); - - GETCRITICAL(bytes, env, src); - memcpy((void *)dstAddr, bytes + srcPos, size); - RELEASECRITICAL(bytes, env, src, JNI_ABORT); - - length -= size; - dstAddr += size; - srcPos += size; - } -} - -JNIEXPORT void JNICALL -Java_java_nio_Bits_copyToByteArray(JNIEnv *env, jobject this, jlong srcAddr, - jobject dst, jlong dstPos, jlong length) -{ - jbyte *bytes; - size_t size; - - while (length > 0) { - size = (length > MBYTE ? MBYTE : length); - - GETCRITICAL(bytes, env, dst); - memcpy(bytes + dstPos, (void *)srcAddr, size); - RELEASECRITICAL(bytes, env, dst, 0); - - length -= size; - srcAddr += size; - dstPos += size; - } -} - -JNIEXPORT void JNICALL Java_java_nio_Bits_copyFromShortArray(JNIEnv *env, jobject this, jobject src, jlong srcPos, jlong dstAddr, jlong length) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + +/** + * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level + * socket options to the platform specific level and option. + */ + +static void out(char* s) { + printf("%s\n", s); +} + +static void emit(const char *name, char * family, int level, int optname) { + printf(" map.put(new RegistryKey(%s, %s),", name, family); + printf(" new OptionKey(%d, %d));\n", level, optname); +} + +static void emit_unspec(const char *name, int level, int optname) { + emit(name, "Net.UNSPEC", level, optname); +} + +static void emit_inet(const char *name, int level, int optname) { + emit(name, "StandardProtocolFamily.INET", level, optname); +} + +static void emit_inet6(const char *name, int level, int optname) { + emit(name, "StandardProtocolFamily.INET6", level, optname); +} + +int main(int argc, const char* argv[]) { + out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT "); + out("package sun.nio.ch; "); + out("import java.net.SocketOption; "); + out("import java.net.StandardSocketOption; "); + out("import java.net.ProtocolFamily; "); + out("import java.net.StandardProtocolFamily; "); + out("import java.util.Map; "); + out("import java.util.HashMap; "); + out("class SocketOptionRegistry { "); + out(" private SocketOptionRegistry() { } "); + out(" private static class RegistryKey { "); + out(" private final SocketOption name; "); + out(" private final ProtocolFamily family; "); + out(" RegistryKey(SocketOption name, ProtocolFamily family) { "); + out(" this.name = name; "); + out(" this.family = family; "); + out(" } "); + out(" public int hashCode() { "); + out(" return name.hashCode() + family.hashCode(); "); + out(" } "); + out(" public boolean equals(Object ob) { "); + out(" if (ob == null) return false; "); + out(" if (!(ob instanceof RegistryKey)) return false; "); + out(" RegistryKey other = (RegistryKey)ob; "); + out(" if (this.name != other.name) return false; "); + out(" if (this.family != other.family) return false; "); + out(" return true; "); + out(" } "); + out(" } "); + out(" private static class LazyInitialization { "); + out(" static final Map options = options(); "); + out(" private static Map options() { "); + out(" Map map = "); + out(" new HashMap(); "); + + emit_unspec("StandardSocketOption.SO_BROADCAST", SOL_SOCKET, SO_BROADCAST); + emit_unspec("StandardSocketOption.SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE); + emit_unspec("StandardSocketOption.SO_LINGER", SOL_SOCKET, SO_LINGER); + emit_unspec("StandardSocketOption.SO_SNDBUF", SOL_SOCKET, SO_SNDBUF); + emit_unspec("StandardSocketOption.SO_RCVBUF", SOL_SOCKET, SO_RCVBUF); + emit_unspec("StandardSocketOption.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR); + emit_unspec("StandardSocketOption.TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY); + + emit_inet("StandardSocketOption.IP_TOS", IPPROTO_IP, IP_TOS); + emit_inet("StandardSocketOption.IP_MULTICAST_IF", IPPROTO_IP, IP_MULTICAST_IF); + emit_inet("StandardSocketOption.IP_MULTICAST_TTL", IPPROTO_IP, IP_MULTICAST_TTL); + emit_inet("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP); + +#ifdef AF_INET6 + emit_inet6("StandardSocketOption.IP_MULTICAST_IF", IPPROTO_IPV6, IPV6_MULTICAST_IF); + emit_inet6("StandardSocketOption.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS); + emit_inet6("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +#endif + + emit_unspec("ExtendedSocketOption.SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE); + + out(" return map; "); + out(" } "); + out(" } "); + out(" public static OptionKey findOption(SocketOption name, ProtocolFamily family) { "); + out(" RegistryKey key = new RegistryKey(name, family); "); + out(" return LazyInitialization.options.get(key); "); + out(" } "); + out("} "); + + return 0; +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/sample/nio/multicast/MulticastAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/multicast/MulticastAddress.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,127 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.net.SocketException; + +/** + * Parses and represents a multicast address. + */ + +class MulticastAddress { + private final InetAddress group; + private final int port; + private final NetworkInterface interf; + + private MulticastAddress(InetAddress group, int port, NetworkInterface interf) { + this.group = group; + this.port = port; + this.interf = interf; + } + + InetAddress group() { + return group; + } + + int port() { + return port; + } + + /** + * @return The network interface, may be {@code null} + */ + NetworkInterface interf() { + return interf; + } + + /** + * Parses a string of the form "group:port[@interface]", returning + * a MulticastAddress representing the address + */ + static MulticastAddress parse(String s) { + String[] components = s.split("@"); + if (components.length > 2) + throw new IllegalArgumentException("At most one '@' expected"); + + // get group and port + String target = components[0]; + int len = components[0].length(); + int colon = components[0].lastIndexOf(':'); + if ((colon < 1) || (colon > (len-2))) + throw new IllegalArgumentException("group:port expected"); + String groupString = target.substring(0, colon); + int port = -1; + try { + port = Integer.parseInt(target.substring(colon+1, len)); + } catch (NumberFormatException x) { + throw new IllegalArgumentException(x); + } + + // handle IPv6 literal address + if (groupString.charAt(0) == '[') { + len = groupString.length(); + if (groupString.charAt(len-1) != ']') + throw new IllegalArgumentException("missing ']'"); + groupString = groupString.substring(1,len-1); + if (groupString.length() == 0) + throw new IllegalArgumentException("missing IPv6 address"); + } + + // get group address + InetAddress group = null; + try { + group = InetAddress.getByName(groupString); + } catch (UnknownHostException x) { + throw new IllegalArgumentException(x); + } + if (!group.isMulticastAddress()) { + throw new IllegalArgumentException("'" + group.getHostAddress() + + "' is not multicast address"); + } + + // optional interface + NetworkInterface interf = null; + if (components.length == 2) { + try { + interf = NetworkInterface.getByName(components[1]); + } catch (SocketException x) { + throw new IllegalArgumentException(x); + } + if (interf == null) { + throw new IllegalArgumentException("'" + components[1] + + "' is not valid interface"); + } + } + return new MulticastAddress(group, port, interf); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/sample/nio/multicast/Reader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/multicast/Reader.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.channels.*; +import java.nio.charset.*; +import java.nio.ByteBuffer; +import java.net.*; +import java.io.IOException; +import java.util.*; + +public class Reader { + + static void usage() { + System.err.println("usage: java Reader group:port@interf [-only source...] [-block source...]"); + System.exit(-1); + } + + static void printDatagram(SocketAddress sa, ByteBuffer buf) { + System.out.format("-- datagram from %s --\n", + ((InetSocketAddress)sa).getAddress().getHostAddress()); + System.out.println(Charset.defaultCharset().decode(buf)); + } + + static void parseAddessList(String s, List list) + throws UnknownHostException + { + String[] sources = s.split(","); + for (int i=0; i includeList = new ArrayList(); + List excludeList = new ArrayList(); + int argc = 1; + while (argc < args.length) { + String option = args[argc++]; + if (argc >= args.length) + usage(); + String value = args[argc++]; + if (option.equals("-only")) { + parseAddessList(value, includeList); + continue; + } + if (option.equals("-block")) { + parseAddessList(value, excludeList); + continue; + } + usage(); + } + if (!includeList.isEmpty() && !excludeList.isEmpty()) { + usage(); + } + + // create and bind socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) { + family = StandardProtocolFamily.INET6; + } + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(target.port())); + + if (includeList.isEmpty()) { + // join group and block addresses on the exclude list + MembershipKey key = dc.join(target.group(), target.interf()); + for (InetAddress source: excludeList) { + key.block(source); + } + } else { + // join with source-specific membership for each source + for (InetAddress source: includeList) { + dc.join(target.group(), target.interf(), source); + } + } + + // register socket with Selector + Selector sel = Selector.open(); + dc.configureBlocking(false); + dc.register(sel, SelectionKey.OP_READ); + + // print out each datagram that we receive + ByteBuffer buf = ByteBuffer.allocateDirect(4096); + for (;;) { + int updated = sel.select(); + if (updated > 0) { + Iterator iter = sel.selectedKeys().iterator(); + while (iter.hasNext()) { + SelectionKey sk = iter.next(); + iter.remove(); + + DatagramChannel ch = (DatagramChannel)sk.channel(); + SocketAddress sa = ch.receive(buf); + if (sa != null) { + buf.flip(); + printDatagram(sa, buf); + buf.rewind(); + buf.limit(buf.capacity()); + } + } + } + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/share/sample/nio/multicast/Sender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/multicast/Sender.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.channels.*; +import java.nio.charset.Charset; +import java.net.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample multicast sender to send a message in a multicast datagram + * to a given group. + */ + +public class Sender { + + private static void usage() { + System.err.println("usage: java Sender group:port[@interface] message"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length < 2) + usage(); + + MulticastAddress target = MulticastAddress.parse(args[0]); + + // create socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) + family = StandardProtocolFamily.INET6; + DatagramChannel dc = DatagramChannel.open(family).bind(new InetSocketAddress(0)); + if (target.interf() != null) { + dc.setOption(StandardSocketOption.IP_MULTICAST_IF, target.interf()); + } + + // send multicast packet + dc.send(Charset.defaultCharset().encode(args[1]), + new InetSocketAddress(target.group(), target.port())); + dc.close(); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/bin/java_md.c --- a/jdk/src/solaris/bin/java_md.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/bin/java_md.c Wed Jul 05 16:41:30 2017 +0200 @@ -289,13 +289,13 @@ if (wanted == running) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { - ReportErrorMessage(JRE_ERROR1); + JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { - ReportErrorMessage(CFG_ERROR7); + JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } @@ -303,7 +303,7 @@ jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { - ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); + JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } } else { /* do the same speculatively or exit */ @@ -330,7 +330,7 @@ EndDataModelSpeculate: /* give up and let other code report error message */ ; #else - ReportErrorMessage(JRE_ERROR2, wanted); + JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); #endif } @@ -391,7 +391,7 @@ break; default: - ReportErrorMessage(JRE_ERROR3, __LINE__); + JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); exit(1); /* unknown value in wanted */ break; } @@ -553,17 +553,17 @@ (void)fflush(stdout); (void)fflush(stderr); execve(newexec, argv, newenvp); - ReportErrorMessageSys(JRE_ERROR4, newexec); + JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); #ifdef DUAL_MODE if (running != wanted) { - ReportErrorMessage(JRE_ERROR5, wanted, running); + JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); # ifdef __solaris__ # ifdef __sparc - ReportErrorMessage(JRE_ERROR6); + JLI_ReportErrorMessage(JRE_ERROR6); # else - ReportErrorMessage(JRE_ERROR7); + JLI_ReportErrorMessage(JRE_ERROR7); # endif } # endif @@ -627,7 +627,7 @@ } if (!speculative) - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -680,13 +680,13 @@ if(length > 0) { location = JLI_StrStr(buf, "sparcv8plus "); if(location == NULL) { - ReportErrorMessage(JVM_ERROR3); + JLI_ReportErrorMessage(JVM_ERROR3); return JNI_FALSE; } } } #endif - ReportErrorMessage(DLL_ERROR1, __LINE__); + JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); goto error; } @@ -703,7 +703,7 @@ return JNI_TRUE; error: - ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } @@ -848,7 +848,7 @@ fptr = (int (*)())dlsym(RTLD_DEFAULT, "main"); if (fptr == NULL) { - ReportErrorMessage(DLL_ERROR3, dlerror()); + JLI_ReportErrorMessage(DLL_ERROR3, dlerror()); return JNI_FALSE; } @@ -885,7 +885,7 @@ return exec_path; } -void ReportErrorMessage(const char* fmt, ...) { +void JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl, fmt); vfprintf(stderr, fmt, vl); @@ -893,7 +893,7 @@ va_end(vl); } -void ReportErrorMessageSys(const char* fmt, ...) { +void JLI_ReportErrorMessageSys(const char* fmt, ...) { va_list vl; char *emsg; @@ -912,7 +912,7 @@ va_end(vl); } -void ReportExceptionDescription(JNIEnv * env) { +void JLI_ReportExceptionDescription(JNIEnv * env) { (*env)->ExceptionDescribe(env); } @@ -1078,7 +1078,7 @@ * Resolve the real path to the directory containing the selected JRE. */ if (realpath(jre, wanted) == NULL) { - ReportErrorMessage(JRE_ERROR9, jre); + JLI_ReportErrorMessage(JRE_ERROR9, jre); exit(1); } @@ -1087,7 +1087,7 @@ */ SetExecname(argv); if (execname == NULL) { - ReportErrorMessage(JRE_ERROR10); + JLI_ReportErrorMessage(JRE_ERROR10); exit(1); } @@ -1106,7 +1106,7 @@ * can be so deadly. */ if (JLI_StrLen(wanted) + JLI_StrLen(progname) + 6 > PATH_MAX) { - ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(JRE_ERROR11); exit(1); } @@ -1126,7 +1126,7 @@ (void)fflush(stdout); (void)fflush(stderr); execv(wanted, argv); - ReportErrorMessageSys(JRE_ERROR12, wanted); + JLI_ReportErrorMessageSys(JRE_ERROR12, wanted); exit(1); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/X11/XKeysym.java --- a/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java Wed Jul 05 16:41:30 2017 +0200 @@ -101,10 +101,15 @@ // Otherwise, it is [1]. int ndx = XToolkit.isXsunServer() && ! XToolkit.isXKBenabled() ? 2 : 1; + // Even if XKB is enabled, we have another problem: some symbol tables (e.g. cz) force + // a regular comma instead of KP_comma for a decimal separator. Result is, + // bugs like 6454041. So, we will try for keypadness a keysym with ndx==0 as well. XToolkit.awtLock(); try { - return XlibWrapper.IsKeypadKey( - XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), ndx ) ); + return (XlibWrapper.IsKeypadKey( + XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), ndx ) ) || + XlibWrapper.IsKeypadKey( + XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), 0 ) )); } finally { XToolkit.awtUnlock(); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java --- a/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Wed Jul 05 16:41:30 2017 +0200 @@ -189,6 +189,8 @@ req.set_format(32); req.set_data(0, (!set) ? _NET_WM_STATE_REMOVE : _NET_WM_STATE_ADD); req.set_data(1, state.getAtom()); + // Fix for 6735584: req.data[2] must be set to 0 when only one property is changed + req.set_data(2, 0); log.log(Level.FINE, "Setting _NET_STATE atom {0} on {1} for {2}", new Object[] {state, window, Boolean.valueOf(set)}); XToolkit.awtLock(); try { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Jul 05 16:41:30 2017 +0200 @@ -97,6 +97,11 @@ static int awt_multiclick_time; static boolean securityWarningEnabled; + // WeakSet should be used here, but there is no such class + // in JDK (at least in JDK6 and earlier versions) + private WeakHashMap overrideRedirectWindows = + new WeakHashMap(); + private static int screenWidth = -1, screenHeight = -1; // Dimensions of default screen static long awt_defaultFg; // Pixel private static XMouseInfoPeer xPeer; @@ -1248,6 +1253,19 @@ } } + @Override + public void setOverrideRedirect(Window target) { + synchronized (overrideRedirectWindows) { + overrideRedirectWindows.put(target, true); + } + } + + public boolean isOverrideRedirect(Window target) { + synchronized (overrideRedirectWindows) { + return overrideRedirectWindows.containsKey(target); + } + } + static void dumpPeers() { if (log.isLoggable(Level.FINE)) { log.fine("Mapped windows:"); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Wed Jul 05 16:41:30 2017 +0200 @@ -129,6 +129,7 @@ private static final int MAXIMUM_BUFFER_LENGTH_NET_WM_ICON = (2<<15) - 1; void preInit(XCreateWindowParams params) { + target = (Component)params.get(TARGET); params.put(REPARENTED, Boolean.valueOf(isOverrideRedirect() || isSimpleWindow())); super.preInit(params); @@ -1117,6 +1118,7 @@ boolean isOverrideRedirect() { return (XWM.getWMID() == XWM.OPENLOOK_WM ? true : false) || + ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target) || XTrayIconPeer.isTrayIconStuffWindow((Window)target); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h --- a/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h Wed Jul 05 16:41:30 2017 +0200 @@ -139,10 +139,15 @@ tojava // Otherwise, it is [1]. tojava int ndx = XToolkit.isXsunServer() && tojava ! XToolkit.isXKBenabled() ? 2 : 1; +tojava // Even if XKB is enabled, we have another problem: some symbol tables (e.g. cz) force +tojava // a regular comma instead of KP_comma for a decimal separator. Result is, +tojava // bugs like 6454041. So, we will try for keypadness a keysym with ndx==0 as well. tojava XToolkit.awtLock(); tojava try { -tojava return XlibWrapper.IsKeypadKey( -tojava XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), ndx ) ); +tojava return (XlibWrapper.IsKeypadKey( +tojava XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), ndx ) ) || +tojava XlibWrapper.IsKeypadKey( +tojava XlibWrapper.XKeycodeToKeysym(ev.get_display(), ev.get_keycode(), 0 ) )); tojava } finally { tojava XToolkit.awtUnlock(); tojava } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MButtonPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MButtonPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright 1995-2001 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.ActionEvent; - -class MButtonPeer extends MComponentPeer implements ButtonPeer { - native void create(MComponentPeer peer); - public native void setLabel(String label); - - MButtonPeer(Button target) { - super(target); - } - - public Dimension getMinimumSize() { - FontMetrics fm = getFontMetrics(target.getFont()); - String label = ((Button)target).getLabel(); - if ( label == null ) { - label = ""; - } - return new Dimension(fm.stringWidth(label) + 14, - fm.getHeight() + 8); - } - - public boolean isFocusable() { - return true; - } - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void action(final long when, final int modifiers) { - MToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, - ((Button)target).getActionCommand(), - when, modifiers)); - } - }); - } - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information. - */ - public void print(Graphics g) { - Button b = (Button)target; - Dimension d = b.size(); - Color bg = b.getBackground(); - Color fg = b.getForeground(); - - g.setColor(bg); - g.fillRect(2, 2, d.width - 3, d.height - 3); - draw3DRect(g, bg, 1, 1, d.width - 2, d.height - 2, true); - - g.setColor(fg); - g.setFont(b.getFont()); - FontMetrics fm = g.getFontMetrics(); - String lbl = b.getLabel(); - g.drawString(lbl, (d.width - fm.stringWidth(lbl)) / 2, - (d.height + fm.getMaxAscent() - fm.getMaxDescent()) / 2); - - target.print(g); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MCanvasPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MCanvasPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - * Copyright 1995-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. - */ -package sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import sun.awt.DisplayChangedListener; -import sun.awt.X11GraphicsConfig; -import sun.awt.X11GraphicsDevice; -import sun.awt.X11GraphicsEnvironment; - -class MCanvasPeer extends MComponentPeer implements CanvasPeer, - DisplayChangedListener { - - native void create(MComponentPeer parent); - private static native void initIDs(); - static { - initIDs(); - } - - MCanvasPeer() {} - - MCanvasPeer(Component target) { - super(target); - } - - MCanvasPeer(Component target, Object arg) { - super(target, arg); - } - -/* --- DisplayChangedListener Stuff --- */ - public void displayChanged() {} - public void paletteChanged() {} - native void resetTargetGC(Component target); - - /* - * Called when the Window this - * Canvas is on is moved onto another Xinerama screen. - * - * Canvases can be created with a non-defulat GraphicsConfiguration. The - * GraphicsConfiguration needs to be changed to one on the new screen, - * preferably with the same visual ID. - * - * Up-called for other windows peer instances (WPanelPeer, WWindowPeer). - * - * Should only be called from the event thread. - */ - public void displayChanged(int screenNum) { - resetLocalGC(screenNum); - resetTargetGC(target); /* call Canvas.setGCFromPeer() via native */ - } - - /* Set graphicsConfig to a GraphicsConfig with the same visual on the new - * screen, which should be easy in Xinerama mode. - * - * Should only be called from displayChanged(), and therefore only from - * the event thread. - */ - void resetLocalGC(int screenNum) { - // Opt: Only need to do if we're not using the default GC - if (graphicsConfig != null) { - X11GraphicsConfig parentgc; - // save vis id of current gc - int visual = graphicsConfig.getVisual(); - - X11GraphicsDevice newDev = (X11GraphicsDevice) GraphicsEnvironment. - getLocalGraphicsEnvironment(). - getScreenDevices()[screenNum]; - - for (int i = 0; i < newDev.getNumConfigs(screenNum); i++) { - if (visual == newDev.getConfigVisualId(i, screenNum)) { - // use that - graphicsConfig = (X11GraphicsConfig)newDev.getConfigurations()[i]; - break; - } - } - // just in case... - if (graphicsConfig == null) { - graphicsConfig = (X11GraphicsConfig) GraphicsEnvironment. - getLocalGraphicsEnvironment(). - getScreenDevices()[screenNum]. - getDefaultConfiguration(); - } - } - } - - protected boolean shouldFocusOnClick() { - // Canvas should always be able to be focused by mouse clicks. - return true; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MCheckboxMenuItemPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MCheckboxMenuItemPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright 1995-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. - */ - -package sun.awt.motif; - - -import java.awt.*; -import java.awt.event.*; -import java.awt.peer.*; - -class MCheckboxMenuItemPeer extends MMenuItemPeer - implements CheckboxMenuItemPeer { - private boolean inUpCall=false; - private boolean inInit=false; - - native void pSetState(boolean t); - native boolean getState(); - - void create(MMenuPeer parent) { - super.create(parent); - inInit=true; - setState(((CheckboxMenuItem)target).getState()); - inInit=false; - } - - MCheckboxMenuItemPeer(CheckboxMenuItem target) { - this.target = target; - isCheckbox = true; - MMenuPeer parent = (MMenuPeer) MToolkit.targetToPeer(getParent_NoClientCode(target)); - create(parent); - } - - public void setState(boolean t) { - if (!nativeCreated) { - return; - } - if (!inUpCall && (t != getState())) { - pSetState(t); - if (!inInit) { - // 4135725 : do not notify on programatic changes - // notifyStateChanged(t); - } - } - } - - void notifyStateChanged(boolean state) { - CheckboxMenuItem cb = (CheckboxMenuItem)target; - ItemEvent e = new ItemEvent(cb, - ItemEvent.ITEM_STATE_CHANGED, - cb.getLabel(), - state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); - postEvent(e); - } - - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void action(long when, int modifiers, boolean state) { - final CheckboxMenuItem cb = (CheckboxMenuItem)target; - final boolean newState = state; - - MToolkit.executeOnEventHandlerThread(cb, new Runnable() { - public void run() { - cb.setState(newState); - notifyStateChanged(newState); - } - }); - //Fix for 5005195: MAWT: CheckboxMenuItem fires action events - //super.action() is not invoked - } // action() -} // class MCheckboxMenuItemPeer diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MCheckboxPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MCheckboxPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - * Copyright 1995-2000 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.*; - -public class MCheckboxPeer extends MComponentPeer implements CheckboxPeer { - private boolean inUpCall = false; - private boolean inInit=false; - - native void create(MComponentPeer parent); - native void pSetState(boolean state); - native boolean pGetState(); - - public native void setLabel(String label); - public native void setCheckboxGroup(CheckboxGroup g); - - - void initialize() { - Checkbox t = (Checkbox)target; - inInit=true; - - setState(t.getState()); - setCheckboxGroup(t.getCheckboxGroup()); - super.initialize(); - inInit=false; - } - - public MCheckboxPeer(Checkbox target) { - super(target); - } - - public boolean isFocusable() { - return true; - } - - public void setState(boolean state) { - if (inInit) { - pSetState(state); - } else if (!inUpCall && (state != pGetState())) { - pSetState(state); - // 4135725 : do not notify on programatic changes - // notifyStateChanged(state); - } - } - private native int getIndicatorSize(); - private native int getSpacing(); - - public Dimension getMinimumSize() { - String lbl = ((Checkbox)target).getLabel(); - if (lbl == null) { - lbl = ""; - } - FontMetrics fm = getFontMetrics(target.getFont()); - /* - * Spacing (number of pixels between check mark and label text) is - * currently set to 0, but in case it ever changes we have to add - * it. 8 is a heuristic number. Indicator size depends on font - * height, so we don't need to include it in checkbox's height - * calculation. - */ - int wdth = fm.stringWidth(lbl) + getIndicatorSize() + getSpacing() + 8; - int hght = Math.max(fm.getHeight() + 8, 15); - return new Dimension(wdth, hght); - } - - - void notifyStateChanged(boolean state) { - Checkbox cb = (Checkbox) target; - ItemEvent e = new ItemEvent(cb, - ItemEvent.ITEM_STATE_CHANGED, - cb.getLabel(), - state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); - postEvent(e); - } - - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - void action(boolean state) { - final Checkbox cb = (Checkbox)target; - final boolean newState = state; - MToolkit.executeOnEventHandlerThread(cb, new Runnable() { - public void run() { - CheckboxGroup cbg = cb.getCheckboxGroup(); - /* Bugid 4039594. If this is the current Checkbox in - * a CheckboxGroup, then return to prevent deselection. - * Otherwise, it's logical state will be turned off, - * but it will appear on. - */ - if ((cbg != null) && (cbg.getSelectedCheckbox() == cb) && - cb.getState()) { - inUpCall = false; - cb.setState(true); - return; - } - // All clear - set the new state - cb.setState(newState); - notifyStateChanged(newState); - } // run() - }); - } // action() - - - - static final int SIZE = 19; - static final int BORDER = 4; - static final int SIZ = SIZE - BORDER*2 - 1; - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information; need to render check mark. - */ - public void print(Graphics g) { - Checkbox cb = (Checkbox)target; - Dimension d = cb.size(); - Color bg = cb.getBackground(); - Color fg = cb.getForeground(); - Color shadow = bg.darker(); - int x = BORDER; - int y = ((d.height - SIZE) / 2) + BORDER; - - g.setColor(cb.getState()? shadow : bg); - - if (cb.getCheckboxGroup() != null) { - g.fillOval(x, y, SIZ, SIZ); - draw3DOval(g, bg, x, y, SIZ, SIZ, !(cb.getState())); - if (cb.getState()) { - g.setColor(fg); - g.fillOval(x + 3, y + 3, SIZ - 6, SIZ - 6); - } - } else { - g.fillRect(x, y, SIZ, SIZ); - draw3DRect(g, bg, x, y, SIZ, SIZ, !(cb.getState())); - if (cb.getState()) { - g.setColor(fg); - g.drawLine(x+1, y+1, x+SIZ-1, y+SIZ-1); - g.drawLine(x+1, y+SIZ-1, x+SIZ-1, y+1); - } - } - g.setColor(fg); - String lbl = cb.getLabel(); - if (lbl != null) { - // REMIND: align - g.setFont(cb.getFont()); - FontMetrics fm = g.getFontMetrics(); - g.drawString(lbl, SIZE, - (d.height + fm.getMaxAscent() - fm.getMaxDescent()) / 2); - } - - target.print(g); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MChoicePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MChoicePeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.ItemEvent; - -class MChoicePeer extends MComponentPeer implements ChoicePeer { - boolean inUpCall=false; - - native void create(MComponentPeer parent); - native void pReshape(int x, int y, int width, int height); - native void pSelect(int index, boolean init); - native void appendItems(String[] items); - - void initialize() { - Choice opt = (Choice)target; - int itemCount = opt.countItems(); - String[] items = new String[itemCount]; - for (int i=0; i < itemCount; i++) { - items[i] = opt.getItem(i); - } - if (itemCount > 0) { - appendItems(items); - pSelect(opt.getSelectedIndex(), true); - } - super.initialize(); - } - - public MChoicePeer(Choice target) { - super(target); - } - - public boolean isFocusable() { - return true; - } - - public Dimension getMinimumSize() { - FontMetrics fm = getFontMetrics(target.getFont()); - Choice c = (Choice)target; - int w = 0; - for (int i = c.countItems() ; i-- > 0 ;) { - w = Math.max(fm.stringWidth(c.getItem(i)), w); - } - return new Dimension(32 + w, Math.max(fm.getHeight() + 8, 15) + 5); - } - - public native void setFont(Font f); - - public void add(String item, int index) { - addItem(item, index); - // Adding an item can change the size of the Choice, so do - // a reshape, based on the font size. - Rectangle r = target.getBounds(); - reshape(r.x, r.y, 0, 0); - } - - public native void remove(int index); - - public native void removeAll(); - - /** - * DEPRECATED, but for now, called by add(String, int). - */ - public native void addItem(String item, int index); - - // public native void remove(int index); - - public native void setBackground(Color c); - - public native void setForeground(Color c); - - public void select(int index) { - if (!inUpCall) { - pSelect(index, false); - } - } - - void notifySelection(String item) { - Choice c = (Choice)target; - ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED, - item, ItemEvent.SELECTED); - postEvent(e); - } - - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - void action(final int index) { - final Choice c = (Choice)target; - inUpCall = false; /* Used to prevent native selection. */ - MToolkit.executeOnEventHandlerThread(c, new Runnable() { - public void run() { - String item; - synchronized(c) { - if (index >= c.getItemCount()) { - /* Nothing to do when the list is too short */ - return; - } - inUpCall = true; /* Prevent native selection. */ - c.select(index); /* set value in target */ - item = c.getItem(index); - inUpCall = false; - } - notifySelection(item); - } - }); - } - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information. - */ - public void print(Graphics g) { - Choice ch = (Choice)target; - Dimension d = ch.size(); - Color bg = ch.getBackground(); - Color fg = ch.getForeground(); - - g.setColor(bg); - g.fillRect(2, 2, d.width-1, d.height-1); - draw3DRect(g, bg, 1, 1, d.width-2, d.height-2, true); - draw3DRect(g, bg, d.width - 18, (d.height / 2) - 3, 10, 6, true); - - g.setColor(fg); - g.setFont(ch.getFont()); - FontMetrics fm = g.getFontMetrics(); - String lbl = ch.getSelectedItem(); - if (lbl == null){ - lbl = ""; - } - if (lbl != ""){ - g.drawString(lbl, 5, (d.height + fm.getMaxAscent()-fm.getMaxDescent())/2); - } - - target.print(g); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - - protected void disposeImpl() { - freeNativeData(); - super.disposeImpl(); - } - - private native void freeNativeData(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MComponentPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MComponentPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1185 +0,0 @@ -/* - * 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 - * 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.PaintEvent; -import java.awt.event.MouseEvent; -import java.awt.event.InputEvent; - -import sun.awt.*; -import sun.awt.image.ToolkitImage; -import sun.awt.image.SunVolatileImage; -import java.awt.image.ImageProducer; -import java.awt.image.ImageObserver; -import java.awt.image.ColorModel; -import java.awt.image.VolatileImage; - -import java.awt.dnd.DropTarget; -import java.awt.dnd.peer.DropTargetPeer; - -import sun.java2d.SunGraphics2D; -import sun.java2d.SurfaceData; - -import java.lang.reflect.Method; - -import java.util.logging.*; - -import sun.java2d.pipe.Region; - - -public /* REMIND: should not be public */ -abstract class MComponentPeer implements ComponentPeer, DropTargetPeer, X11ComponentPeer { - - private static final Logger log = Logger.getLogger("sun.awt.motif.MComponentPeer"); - private static final Logger focusLog = Logger.getLogger("sun.awt.motif.focus.MComponentPeer"); - - Component target; - long pData; - long jniGlobalRef; - protected X11GraphicsConfig graphicsConfig; - SurfaceData surfaceData; - int oldWidth = -1; - int oldHeight = -1; - - private RepaintArea paintArea; - - boolean isLayouting = false; - boolean paintPending = false; - - protected boolean disposed = false; - private static int JAWT_LOCK_ERROR=0x00000001; - private static int JAWT_LOCK_CLIP_CHANGED=0x00000002; - private static int JAWT_LOCK_BOUNDS_CHANGED=0x00000004; - private static int JAWT_LOCK_SURFACE_CHANGED=0x00000008; - private int drawState = JAWT_LOCK_CLIP_CHANGED | - JAWT_LOCK_BOUNDS_CHANGED | - JAWT_LOCK_SURFACE_CHANGED; - - /* These are the enumerated types in awt_p.h*/ - static final int MOTIF_NA = 0 ; - static final int MOTIF_V1 = 1 ; - static final int MOTIF_V2 = 2 ; - - private Font font; - private long backBuffer = 0; - private VolatileImage xBackBuffer = null; - - static { - initIDs(); - } - - /* initialize the fieldIDs of fields that may be accessed from C */ - private native static void initIDs(); - - - /* This will return the last state of a window. ie the specific - * "gotcha" is that if you iconify a window its obscurity remains - * unchanged. Current use of this is just in user-initiated scrolling. - * If that use expands to more cases you may need to "and" this with - * the value of the iconic state of a Frame. - * Note that de-iconifying an X11 window DOES generate a new event - * correctly notifying you of the new visibility of the window - */ - public boolean isObscured() { - - Container container = (target instanceof Container) ? - (Container)target : target.getParent(); - - if (container == null) { - return true; - } - - Container parent; - while ((parent = container.getParent()) != null) { - container = parent; - } - - if (container instanceof Window) { - MWindowPeer wpeer = (MWindowPeer)(container.getPeer()); - if (wpeer != null) { - return (wpeer.winAttr.visibilityState != - MWindowAttributes.AWT_UNOBSCURED); - } - } - return true; - } - - public boolean canDetermineObscurity() { - return true; - } - - abstract void create(MComponentPeer parent); - void create(MComponentPeer parent, Object arg) { - create(parent); - } - - void EFcreate(MComponentPeer parent, int x){} - - native void pInitialize(); - native void pShow(); - native void pHide(); - native void pEnable(); - native void pDisable(); - native void pReshape(int x, int y, int width, int height); - native void pDispose(); - native void pMakeCursorVisible(); - native Point pGetLocationOnScreen(); - native Point pGetLocationOnScreen2(Window win, MWindowPeer wpeer); - native void pSetForeground(Color c); - native void pSetBackground(Color c); - private native void pSetFont(Font f); - - //Added for bug 4175560 - //Returns the native representation for the Color argument, - //using the given GraphicsConfiguration. - native int getNativeColor(Color clr, GraphicsConfiguration gc); - - // Returns the parent of the component, without invoking client - // code. This must go through native code, because it invokes - // private methods in the java.awt package, which we cannot - // do from this package. - static native Container getParent_NoClientCode(Component component); - - // Returns the parent of the component, without invoking client - // code. This must go through native code, because it invokes - // private methods in the java.awt package, which we cannot - // do from this package. - static native Component[] getComponents_NoClientCode(Container container); - - void initialize() { - if (!target.isVisible()) { - hide(); - } - Color c; - Font f; - Cursor cursor; - - pInitialize(); - - if ((c = target.getForeground()) != null) { - setForeground(c); - } - if ((c = target.getBackground()) != null) { - setBackground(c); - } - if ((f = target.getFont()) != null) { - setFont(f); - } - pSetCursor(target.getCursor()); - if (!target.isEnabled()) { - disable(); - } - Rectangle r = target.getBounds(); - reshape(r.x, r.y, r.width, r.height); - if (target.isVisible()) { - show(); - } - - surfaceData = graphicsConfig.createSurfaceData(this); - } - - public void init(Component target, Object arg) { - this.target = target; - this.paintArea = new RepaintArea(); - - Container parent = MToolkit.getNativeContainer(target); - MComponentPeer parentPeer = (MComponentPeer) MToolkit.targetToPeer(parent); - create(parentPeer, arg); - - initialize(); - } - - MComponentPeer(Component target, Object arg) { - init(target, arg); - } - - MComponentPeer() {} - - public void init(Component target) { - this.target = target; - this.paintArea = new RepaintArea(); - - Container parent = MToolkit.getNativeContainer(target); - MComponentPeer parentPeer = (MComponentPeer) MToolkit.targetToPeer(parent); - create(parentPeer); - - if (parent != null && parent instanceof ScrollPane) { - MScrollPanePeer speer = (MScrollPanePeer) parentPeer; - speer.setScrollChild(this); - } - initialize(); - } - - MComponentPeer(Component target) { - init(target); - } - - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } - - public void setForeground(Color c) { - pSetForeground(c); - } - - public void setBackground(Color c) { - pSetBackground(c); - } - - public void updateCursorImmediately() { - MGlobalCursorManager.getCursorManager().updateCursorImmediately(); - } - - public void setFont(Font f) { - ComponentPeer peer; - if (f == null) { - f = defaultFont; - } - pSetFont(f); - if ( target instanceof Container ) { - Container container = (Container) target; - int count = container.getComponentCount(); - Component[] children = container.getComponents(); - for (int i=0; i>1)); - v2 = 7; - } - - int ctr = thickness/2; - int sbmin = ctr - w2/2; - int sbmax = ctr + w2/2; - - // paint the background slightly darker - { - Color d = new Color((int) (bg.getRed() * 0.85), - (int) (bg.getGreen() * 0.85), - (int) (bg.getBlue() * 0.85)); - - g.setColor(d); - if (horizontal) { - g.fillRect(0, 0, length, thickness); - } else { - g.fillRect(0, 0, thickness, length); - } - } - - // paint the thumb and arrows in the normal background color - g.setColor(bg); - if (v1 > 0) { - if (horizontal) { - g.fillRect(v1, 3, v2, thickness-3); - } else { - g.fillRect(3, v1, thickness-3, v2); - } - } - - tpts_x[0] = ctr; tpts_y[0] = 2; - tpts_x[1] = sbmin; tpts_y[1] = w2; - tpts_x[2] = sbmax; tpts_y[2] = w2; - if (horizontal) { - g.fillPolygon(tpts_y, tpts_x, 3); - } else { - g.fillPolygon(tpts_x, tpts_y, 3); - } - - tpts_y[0] = length-2; - tpts_y[1] = length-w2; - tpts_y[2] = length-w2; - if (horizontal) { - g.fillPolygon(tpts_y, tpts_x, 3); - } else { - g.fillPolygon(tpts_x, tpts_y, 3); - } - - Color highlight = bg.brighter(); - - // // // // draw the "highlighted" edges - g.setColor(highlight); - - // outline & arrows - if (horizontal) { - g.drawLine(1, thickness, length - 1, thickness); - g.drawLine(length - 1, 1, length - 1, thickness); - - // arrows - g.drawLine(1, ctr, w2, sbmin); - g.drawLine(length - w2, sbmin, length - w2, sbmax); - g.drawLine(length - w2, sbmin, length - 2, ctr); - - } else { - g.drawLine(thickness, 1, thickness, length - 1); - g.drawLine(1, length - 1, thickness, length - 1); - - // arrows - g.drawLine(ctr, 1, sbmin, w2); - g.drawLine(sbmin, length - w2, sbmax, length - w2); - g.drawLine(sbmin, length - w2, ctr, length - 2); - } - - // thumb - if (v1 > 0) { - if (horizontal) { - g.drawLine(v1, 2, v1 + v2, 2); - g.drawLine(v1, 2, v1, thickness-3); - } else { - g.drawLine(2, v1, 2, v1 + v2); - g.drawLine(2, v1, thickness-3, v1); - } - } - - Color shadow = bg.darker(); - - // // // // draw the "shadowed" edges - g.setColor(shadow); - - // outline && arrows - if (horizontal) { - g.drawLine(0, 0, 0, thickness); - g.drawLine(0, 0, length - 1, 0); - - // arrows - g.drawLine(w2, sbmin, w2, sbmax); - g.drawLine(w2, sbmax, 1, ctr); - g.drawLine(length-2, ctr, length-w2, sbmax); - - } else { - g.drawLine(0, 0, thickness, 0); - g.drawLine(0, 0, 0, length - 1); - - // arrows - g.drawLine(sbmin, w2, sbmax, w2); - g.drawLine(sbmax, w2, ctr, 1); - g.drawLine(ctr, length-2, sbmax, length-w2); - } - - // thumb - if (v1 > 0) { - if (horizontal) { - g.drawLine(v1 + v2, 2, v1 + v2, thickness-2); - g.drawLine(v1, thickness-2, v1 + v2, thickness-2); - } else { - g.drawLine(2, v1 + v2, thickness-2, v1 + v2); - g.drawLine(thickness-2, v1, thickness-2, v1 + v2); - } - } - g.setColor(c); - } - - public String toString() { - return getClass().getName() + "[" + target + "]"; - } - - /* New 1.1 API */ - public void setVisible(boolean b) { - if (b) { - Dimension s = target.getSize(); - oldWidth = s.width; - oldHeight = s.height; - pShow(); - } else { - pHide(); - } - } - - /* New 1.1 API */ - public void setEnabled(boolean b) { - if (b) { - pEnable(); - } else { - pDisable(); - } - } - - /* New 1.1 API */ - public Point getLocationOnScreen() { - synchronized (target.getTreeLock()) { - Component comp = target; - while (comp != null && !(comp instanceof Window)) { - comp = getParent_NoClientCode(comp); - } - - // applets, embedded, etc - translate directly - if (comp == null || comp instanceof sun.awt.EmbeddedFrame) { - return pGetLocationOnScreen(); - } - - MWindowPeer wpeer = (MWindowPeer)(MToolkit.targetToPeer(comp)); - if (wpeer == null) { - return pGetLocationOnScreen(); - } - return pGetLocationOnScreen2((Window)comp, wpeer); - } - } - - public int serialNum = 0; - - /* Returns the native paint should be posted after setting new size - */ - public boolean checkNativePaintOnSetBounds(int width, int height) { - return (width != oldWidth) || (height != oldHeight); - } - - void setBounds(int x, int y, int width, int height) { - setBounds(x, y, width, height, SET_BOUNDS); - } - - /* New 1.1 API */ - public void setBounds(int x, int y, int width, int height, int op) { - if (disposed) return; - - Container parent = getParent_NoClientCode(target); - - // Should set paintPending before reshape to prevent - // thread race between PaintEvent and setBounds - // This part of the 4267393 fix proved to be unstable under solaris, - // dissabled due to regressions 4418155, 4486762, 4490079 - paintPending = false; //checkNativePaintOnSetBounds(width, height); - - // Note: it would be ideal to NOT execute this if it's - // merely a Move which is occurring. - if (parent != null && parent instanceof ScrollPane) { - MScrollPanePeer speer = (MScrollPanePeer)parent.getPeer(); - if (!speer.ignore) { - pReshape(x, y, width, height); - speer.childResized(width, height); - } - } else { - pReshape(x, y, width, height); - } - - if ((width != oldWidth) || (height != oldHeight)) { - SurfaceData oldData = surfaceData; - if (oldData != null) { - surfaceData = graphicsConfig.createSurfaceData(this); - oldData.invalidate(); - } - oldWidth = width; - oldHeight = height; - } - validateSurface(width, height); - serialNum++; - } - - void validateSurface(int width, int height) { - SunToolkit.awtLock(); - try { - if (!disposed && (width != oldWidth || height != oldHeight)) { - SurfaceData oldData = surfaceData; - if (oldData != null) { - surfaceData = graphicsConfig.createSurfaceData(this); - oldData.invalidate(); - } - oldWidth = width; - oldHeight = height; - } - } finally { - SunToolkit.awtUnlock(); - } - } - - public void beginValidate() { - } - - native void restoreFocus(); - - public void endValidate() { - restoreFocus(); - } - - public void beginLayout() { - // Skip all painting till endLayout - isLayouting = true; - } - - public void endLayout() { - if (!paintPending && !paintArea.isEmpty() && - !((Component)target).getIgnoreRepaint()) { - // if not waiting for native painting repaint damaged area - postEvent(new PaintEvent((Component)target, PaintEvent.PAINT, - new Rectangle())); - } - isLayouting = false; - } - - /** - * DEPRECATED: Replaced by setVisible(boolean). - */ - public void show() { - setVisible(true); - } - - /** - * DEPRECATED: Replaced by setVisible(boolean). - */ - public void hide() { - setVisible(false); - } - - /** - * DEPRECATED: Replaced by setEnabled(boolean). - */ - public void enable() { - setEnabled(true); - } - - /** - * DEPRECATED: Replaced by setEnabled(boolean). - */ - public void disable() { - setEnabled(false); - } - - /** - * DEPRECATED: Replaced by setBounds(int, int, int, int). - */ - public void reshape(int x, int y, int width, int height) { - setBounds(x, y, width, height); - } - - /** - * DEPRECATED: Replaced by getMinimumSize(). - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - - /** - * DEPRECATED: Replaced by getPreferredSize(). - */ - public Dimension preferredSize() { - return getPreferredSize(); - } - - /** - * - */ - - public void addDropTarget(DropTarget dt) { - if (MToolkit.useMotifDnD()) { - addNativeDropTarget(dt); - } else { - Component comp = target; - while(!(comp == null || comp instanceof java.awt.Window)) { - comp = getParent_NoClientCode(comp); - } - - if (comp instanceof Window) { - MWindowPeer wpeer = (MWindowPeer)(comp.getPeer()); - if (wpeer != null) { - wpeer.addDropTarget(); - } - } - } - } - - /** - * - */ - - public void removeDropTarget(DropTarget dt) { - if (MToolkit.useMotifDnD()) { - removeNativeDropTarget(dt); - } else { - Component comp = target; - while(!(comp == null || comp instanceof java.awt.Window)) { - comp = getParent_NoClientCode(comp); - } - - if (comp instanceof Window) { - MWindowPeer wpeer = (MWindowPeer)(comp.getPeer()); - if (wpeer != null) { - wpeer.removeDropTarget(); - } - } - } - } - - public void notifyTextComponentChange(boolean add){ - Container parent = getParent_NoClientCode(target); - while(!(parent == null || - parent instanceof java.awt.Frame || - parent instanceof java.awt.Dialog)) { - parent = getParent_NoClientCode(parent); - } - - if (parent instanceof java.awt.Frame || - parent instanceof java.awt.Dialog) { - if (add) - ((MInputMethodControl)parent.getPeer()).addTextComponent((MComponentPeer)this); - else - ((MInputMethodControl)parent.getPeer()).removeTextComponent((MComponentPeer)this); - } - } - - native void addNativeDropTarget(DropTarget dt); - - native void removeNativeDropTarget(DropTarget dt); - - public GraphicsConfiguration getGraphicsConfiguration() { - GraphicsConfiguration ret = graphicsConfig; - if (ret == null) { - ret = target.getGraphicsConfiguration(); - } - return ret; - } - - // Returns true if we are inside begin/endLayout and - // are waiting for native painting - public boolean isPaintPending() { - return paintPending && isLayouting; - } - - public boolean handlesWheelScrolling() { - return false; - } - - /** - * The following multibuffering-related methods delegate to our - * associated GraphicsConfig (X11 or GLX) to handle the appropriate - * native windowing system specific actions. - */ - - private native long getWindow(long pData); - - public long getContentWindow() { - return getWindow(pData); - } - - public void createBuffers(int numBuffers, BufferCapabilities caps) - throws AWTException - { - backBuffer = graphicsConfig.createBackBuffer(this, numBuffers, caps); - xBackBuffer = graphicsConfig.createBackBufferImage(target, - backBuffer); - } - - public void flip(int x1, int y1, int x2, int y2, - BufferCapabilities.FlipContents flipAction) - { - if (backBuffer == 0) { - throw new IllegalStateException("Buffers have not been created"); - } - graphicsConfig.flip(this, target, xBackBuffer, - x1, y1, x2, y2, flipAction); - } - - public Image getBackBuffer() { - if (backBuffer == 0) { - throw new IllegalStateException("Buffers have not been created"); - } - return xBackBuffer; - } - - public void destroyBuffers() { - graphicsConfig.destroyBackBuffer(backBuffer); - backBuffer = 0; - xBackBuffer = null; - } - - /** - * @see java.awt.peer.ComponentPeer#isReparentSupported - */ - public boolean isReparentSupported() { - return false; - } - - /** - * @see java.awt.peer.ComponentPeer#reparent - */ - public void reparent(ContainerPeer newNativeParent) { - throw new UnsupportedOperationException(); - } - - /** - * Applies the shape to the native component window. - * @since 1.7 - */ - public void applyShape(Region shape) { - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MCustomCursor.java --- a/jdk/src/solaris/classes/sun/awt/motif/MCustomCursor.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright 2003 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 sun.awt.motif; - -import sun.awt.X11CustomCursor; -import sun.awt.CustomCursor; -import java.awt.*; -import java.awt.image.*; -import sun.awt.image.ImageRepresentation; - -public class MCustomCursor extends X11CustomCursor { - - public MCustomCursor(Image cursor, Point hotSpot, String name) - throws IndexOutOfBoundsException { - super(cursor, hotSpot, name); - } - /** - * Returns the supported cursor size - */ - public static Dimension getBestCursorSize( - int preferredWidth, int preferredHeight) { - - // Fix for bug 4212593 The Toolkit.createCustomCursor does not - // check absence of the image of cursor - // We use XQueryBestCursor which accepts unsigned ints to obtain - // the largest cursor size that could be dislpayed - Dimension d = new Dimension(Math.abs(preferredWidth), Math.abs(preferredHeight)); - - queryBestCursor(d); - return d; - } - - private static native void queryBestCursor(Dimension d); - - protected native void createCursor(byte[] xorMask, byte[] andMask, - int width, int height, - int fcolor, int bcolor, - int xHotSpot, int yHotSpot); - - static { - cacheInit(); - } - - private native static void cacheInit(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MDataTransferer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MDataTransferer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,386 +0,0 @@ -/* - * Copyright 2000-2004 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 sun.awt.motif; - -import java.awt.Image; - -import java.awt.datatransfer.DataFlavor; - -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.WritableRaster; - -import java.io.InputStream; -import java.io.IOException; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.imageio.ImageIO; -import javax.imageio.ImageTypeSpecifier; -import javax.imageio.ImageWriter; -import javax.imageio.spi.ImageWriterSpi; - -import sun.awt.datatransfer.DataTransferer; -import sun.awt.datatransfer.ToolkitThreadBlockedHandler; - -/** - * Platform-specific support for the data transfer subsystem. - * - * @author Roger Brinkley - * @author Danila Sinopalnikov - * - * @since 1.3.1 - */ -public class MDataTransferer extends DataTransferer { - private static final long FILE_NAME_ATOM; - private static final long DT_NET_FILE_ATOM; - private static final long PNG_ATOM; - private static final long JFIF_ATOM; - - static { - FILE_NAME_ATOM = getAtomForTarget("FILE_NAME"); - DT_NET_FILE_ATOM = getAtomForTarget("_DT_NETFILE"); - PNG_ATOM = getAtomForTarget("PNG"); - JFIF_ATOM = getAtomForTarget("JFIF"); - } - - /** - * Singleton constructor - */ - private MDataTransferer() { - } - - private static MDataTransferer transferer; - - static MDataTransferer getInstanceImpl() { - if (transferer == null) { - synchronized (MDataTransferer.class) { - if (transferer == null) { - transferer = new MDataTransferer(); - } - } - } - return transferer; - } - - public String getDefaultUnicodeEncoding() { - return "iso-10646-ucs-2"; - } - - public boolean isLocaleDependentTextFormat(long format) { - return false; - } - - public boolean isTextFormat(long format) { - return super.isTextFormat(format) - || isMimeFormat(format, "text"); - } - - protected String getCharsetForTextFormat(Long lFormat) { - long format = lFormat.longValue(); - if (isMimeFormat(format, "text")) { - String nat = getNativeForFormat(format); - DataFlavor df = new DataFlavor(nat, null); - // Ignore the charset parameter of the MIME type if the subtype - // doesn't support charset. - if (!DataTransferer.doesSubtypeSupportCharset(df)) { - return null; - } - String charset = df.getParameter("charset"); - if (charset != null) { - return charset; - } - } - return super.getCharsetForTextFormat(lFormat); - } - - public boolean isFileFormat(long format) { - return format == FILE_NAME_ATOM || format == DT_NET_FILE_ATOM; - } - - public boolean isImageFormat(long format) { - return format == PNG_ATOM || format == JFIF_ATOM - || isMimeFormat(format, "image"); - } - - protected Long getFormatForNativeAsLong(String str) { - // Just get the atom. If it has already been retrived - // once, we'll get a copy so this should be very fast. - long atom = getAtomForTarget(str); - if (atom <= 0) { - throw new InternalError("Cannot register a target"); - } - return Long.valueOf(atom); - } - - protected String getNativeForFormat(long format) { - return getTargetNameForAtom(format); - } - - public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() { - return MToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler(); - } - - /** - * Gets an atom for a format name. - */ - static native long getAtomForTarget(String name); - - /** - * Gets an format name for a given format (atom) - */ - private static native String getTargetNameForAtom(long atom); - - protected byte[] imageToPlatformBytes(Image image, long format) - throws IOException { - String mimeType = null; - if (format == PNG_ATOM) { - mimeType = "image/png"; - } else if (format == JFIF_ATOM) { - mimeType = "image/jpeg"; - } else { - // Check if an image MIME format. - try { - String nat = getNativeForFormat(format); - DataFlavor df = new DataFlavor(nat); - String primaryType = df.getPrimaryType(); - if ("image".equals(primaryType)) { - mimeType = df.getPrimaryType() + "/" + df.getSubType(); - } - } catch (Exception e) { - // Not an image MIME format. - } - } - if (mimeType != null) { - return imageToStandardBytes(image, mimeType); - } else { - String nativeFormat = getNativeForFormat(format); - throw new IOException("Translation to " + nativeFormat + - " is not supported."); - } - } - - /** - * Translates either a byte array or an input stream which contain - * platform-specific image data in the given format into an Image. - */ - protected Image platformImageBytesOrStreamToImage(InputStream inputStream, - byte[] bytes, - long format) - throws IOException { - String mimeType = null; - if (format == PNG_ATOM) { - mimeType = "image/png"; - } else if (format == JFIF_ATOM) { - mimeType = "image/jpeg"; - } else { - // Check if an image MIME format. - try { - String nat = getNativeForFormat(format); - DataFlavor df = new DataFlavor(nat); - String primaryType = df.getPrimaryType(); - if ("image".equals(primaryType)) { - mimeType = df.getPrimaryType() + "/" + df.getSubType(); - } - } catch (Exception e) { - // Not an image MIME format. - } - } - if (mimeType != null) { - return standardImageBytesOrStreamToImage(inputStream, bytes, mimeType); - } else { - String nativeFormat = getNativeForFormat(format); - throw new IOException("Translation from " + nativeFormat + - " is not supported."); - } - } - - /** - * Returns true if and only if the name of the specified format Atom - * constitutes a valid MIME type with the specified primary type. - */ - private boolean isMimeFormat(long format, String primaryType) { - String nat = getNativeForFormat(format); - - if (nat == null) { - return false; - } - - try { - DataFlavor df = new DataFlavor(nat); - if (primaryType.equals(df.getPrimaryType())) { - return true; - } - } catch (Exception e) { - // Not a MIME format. - } - - return false; - } - - /* - * The XDnD protocol prescribes that the Atoms used as targets for data - * transfer should have string names that represent the corresponding MIME - * types. - * To meet this requirement we check if the passed native format constitutes - * a valid MIME and return a list of flavors to which the data in this MIME - * type can be translated by the Data Transfer subsystem. - */ - public List getPlatformMappingsForNative(String nat) { - List flavors = new ArrayList(); - - if (nat == null) { - return flavors; - } - - DataFlavor df = null; - - try { - df = new DataFlavor(nat); - } catch (Exception e) { - // The string doesn't constitute a valid MIME type. - return flavors; - } - - Object value = df; - final String primaryType = df.getPrimaryType(); - final String baseType = primaryType + "/" + df.getSubType(); - - // For text formats we map natives to MIME strings instead of data - // flavors to enable dynamic text native-to-flavor mapping generation. - // See SystemFlavorMap.getFlavorsForNative() for details. - if ("text".equals(primaryType)) { - value = primaryType + "/" + df.getSubType(); - } else if ("image".equals(primaryType)) { - Iterator readers = ImageIO.getImageReadersByMIMEType(baseType); - if (readers.hasNext()) { - flavors.add(DataFlavor.imageFlavor); - } - } - - flavors.add(value); - - return flavors; - } - - private static ImageTypeSpecifier defaultSpecifier = null; - - private ImageTypeSpecifier getDefaultImageTypeSpecifier() { - if (defaultSpecifier == null) { - ColorModel model = ColorModel.getRGBdefault(); - WritableRaster raster = - model.createCompatibleWritableRaster(10, 10); - - BufferedImage bufferedImage = - new BufferedImage(model, raster, model.isAlphaPremultiplied(), - null); - - defaultSpecifier = new ImageTypeSpecifier(bufferedImage); - } - - return defaultSpecifier; - } - - /* - * The XDnD protocol prescribes that the Atoms used as targets for data - * transfer should have string names that represent the corresponding MIME - * types. - * To meet this requirement we return a list of formats that represent - * MIME types to which the data in this flavor can be translated by the Data - * Transfer subsystem. - */ - public List getPlatformMappingsForFlavor(DataFlavor df) { - List natives = new ArrayList(1); - - if (df == null) { - return natives; - } - - String charset = df.getParameter("charset"); - String baseType = df.getPrimaryType() + "/" + df.getSubType(); - String mimeType = baseType; - - if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) { - mimeType += ";charset=" + charset; - } - - // Add a mapping to the MIME native whenever the representation class - // doesn't require translation. - if (df.getRepresentationClass() != null && - (df.isRepresentationClassInputStream() || - df.isRepresentationClassByteBuffer() || - byteArrayClass.equals(df.getRepresentationClass()))) { - natives.add(mimeType); - } - - if (DataFlavor.imageFlavor.equals(df)) { - String[] mimeTypes = ImageIO.getWriterMIMETypes(); - if (mimeTypes != null) { - for (int i = 0; i < mimeTypes.length; i++) { - Iterator writers = - ImageIO.getImageWritersByMIMEType(mimeTypes[i]); - - while (writers.hasNext()) { - ImageWriter imageWriter = (ImageWriter)writers.next(); - ImageWriterSpi writerSpi = - imageWriter.getOriginatingProvider(); - - if (writerSpi != null && - writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) { - natives.add(mimeTypes[i]); - break; - } - } - } - } - } else if (DataTransferer.isFlavorCharsetTextType(df)) { - final Iterator iter = DataTransferer.standardEncodings(); - - // stringFlavor is semantically equivalent to the standard - // "text/plain" MIME type. - if (DataFlavor.stringFlavor.equals(df)) { - baseType = "text/plain"; - } - - while (iter.hasNext()) { - String encoding = (String)iter.next(); - if (!encoding.equals(charset)) { - natives.add(baseType + ";charset=" + encoding); - } - } - - // Add a MIME format without specified charset. - if (!natives.contains(baseType)) { - natives.add(baseType); - } - } - - return natives; - } - protected native String[] dragQueryFile(byte[] bytes); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MDialogPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MDialogPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * 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 - * 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 sun.awt.motif; - -import java.util.Vector; -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.*; -import sun.awt.motif.MInputMethodControl; -import sun.awt.im.*; - -class MDialogPeer extends MWindowPeer implements DialogPeer, MInputMethodControl { - - static Vector allDialogs = new Vector(); - - MDialogPeer(Dialog target) { - - /* create MWindowPeer object */ - super(); - - winAttr.nativeDecor = !target.isUndecorated(); - winAttr.initialFocus = true; - winAttr.isResizable = target.isResizable(); - winAttr.initialState = MWindowAttributes.NORMAL; - winAttr.title = target.getTitle(); - winAttr.icon = null; - if (winAttr.nativeDecor) { - winAttr.decorations = winAttr.AWT_DECOR_ALL | - winAttr.AWT_DECOR_MINIMIZE | - winAttr.AWT_DECOR_MAXIMIZE; - } else { - winAttr.decorations = winAttr.AWT_DECOR_NONE; - } - /* create and init native component */ - init(target); - allDialogs.addElement(this); - } - - public void setTitle(String title) { - pSetTitle(title); - } - - protected void disposeImpl() { - allDialogs.removeElement(this); - super.disposeImpl(); - } - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleMoved(int x, int y) { - postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); - } - - public void show() { - pShowModal( ((Dialog)target).isModal() ); - updateAlwaysOnTop(alwaysOnTop); - } - - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleIconify() { -// Note: These routines are necessary for Coaleseing of native implementations -// As Dialogs do not currently send Iconify/DeIconify messages but -// Windows/Frames do. If this should be made consistent...to do so -// uncomment the postEvent. -// postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleDeiconify() { -// Note: These routines are necessary for Coaleseing of native implementations -// As Dialogs do not currently send Iconify/DeIconify messages but -// Windows/Frames do. If this should be made consistent...to do so -// uncomment the postEvent. -// postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); - } - - public void blockWindows(java.util.List toBlock) { - // do nothing - } - - @Override - final boolean isTargetUndecorated() { - return ((Dialog)target).isUndecorated(); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MDragSourceContextPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MDragSourceContextPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * Copyright 1997-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. - */ - -package sun.awt.motif; - -import java.awt.Component; -import java.awt.Cursor; -import java.awt.Image; -import java.awt.Point; - -import java.awt.datatransfer.Transferable; - -import java.awt.dnd.DragSourceContext; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.InvalidDnDOperationException; - -import java.awt.event.InputEvent; - -import java.awt.peer.ComponentPeer; -import java.awt.peer.LightweightPeer; - -import java.util.Map; -import sun.awt.SunToolkit; -import sun.awt.dnd.SunDragSourceContextPeer; - -/** - *

    - * TBC - *

    - * - * @since JDK1.2 - * - */ - -final class MDragSourceContextPeer extends SunDragSourceContextPeer { - - private static final MDragSourceContextPeer theInstance = - new MDragSourceContextPeer(null); - - /** - * construct a new MDragSourceContextPeer - */ - - private MDragSourceContextPeer(DragGestureEvent dge) { - super(dge); - } - - static MDragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { - theInstance.setTrigger(dge); - return theInstance; - } - - protected void startDrag(Transferable transferable, - long[] formats, Map formatMap) { - try { - long nativeCtxtLocal = startDrag(getTrigger().getComponent(), - transferable, - getTrigger().getTriggerEvent(), - getCursor(), - getCursor() == null ? 0 : getCursor().getType(), - getDragSourceContext().getSourceActions(), - formats, - formatMap); - setNativeContext(nativeCtxtLocal); - } catch (Exception e) { - throw new InvalidDnDOperationException("failed to create native peer: " + e); - } - - if (getNativeContext() == 0) { - throw new InvalidDnDOperationException("failed to create native peer"); - } - - MDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(transferable); - } - - /** - * downcall into native code - */ - - private native long startDrag(Component component, - Transferable transferable, - InputEvent nativeTrigger, - Cursor c, int ctype, int actions, - long[] formats, Map formatMap); - - /** - * set cursor - */ - - public void setCursor(Cursor c) throws InvalidDnDOperationException { - SunToolkit.awtLock(); - super.setCursor(c); - SunToolkit.awtUnlock(); - } - - protected native void setNativeCursor(long nativeCtxt, Cursor c, int cType); - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MDropTargetContextPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MDropTargetContextPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - * Copyright 1997-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. - */ - -package sun.awt.motif; - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.UnsupportedFlavorException; - -import java.awt.dnd.DnDConstants; -import java.awt.dnd.InvalidDnDOperationException; - -import java.io.InputStream; - -import java.util.Map; - -import java.io.IOException; -import sun.awt.dnd.SunDropTargetContextPeer; -import sun.awt.SunToolkit; - -/** - *

    - * The MDropTargetContextPeer class is the class responsible for handling - * the interaction between the Motif DnD system and Java. - *

    - * - * @since JDK1.2 - * - */ - -final class MDropTargetContextPeer extends SunDropTargetContextPeer { - - private long nativeDropTransfer; - - long nativeDataAvailable = 0; - Object nativeData = null; - - /** - * create the peer - */ - - static MDropTargetContextPeer createMDropTargetContextPeer() { - return new MDropTargetContextPeer(); - } - - /** - * create the peer - */ - - private MDropTargetContextPeer() { - super(); - } - - protected Object getNativeData(long format) { - SunToolkit.awtLock(); - if (nativeDropTransfer == 0) { - nativeDropTransfer = startTransfer(getNativeDragContext(), - format); - } else { - addTransfer (nativeDropTransfer, format); - } - - for (nativeDataAvailable = 0; - format != nativeDataAvailable;) { - try { - SunToolkit.awtLockWait(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - SunToolkit.awtUnlock(); - - return nativeData; - } - - /** - * signal drop complete - */ - - protected void doDropDone(boolean success, int dropAction, - boolean isLocal) { - dropDone(getNativeDragContext(), nativeDropTransfer, isLocal, - success, dropAction); - } - - /** - * notify transfer complete - */ - - private void newData(long format, String type, byte[] data) { - nativeDataAvailable = format; - nativeData = data; - - SunToolkit.awtLockNotifyAll(); - } - - /** - * notify transfer failed - */ - - private void transferFailed(long format) { - nativeDataAvailable = format; - nativeData = null; - - SunToolkit.awtLockNotifyAll(); - } - - /** - * schedule a native DnD transfer - */ - - private native long startTransfer(long nativeDragContext, long format); - - /** - * schedule a native DnD data transfer - */ - - private native void addTransfer(long nativeDropTransfer, long format); - - /** - * signal that drop is completed - */ - - private native void dropDone(long nativeDragContext, long nativeDropTransfer, - boolean localTx, boolean success, int dropAction); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,584 +0,0 @@ -/* - * Copyright 2003-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. - */ - -package sun.awt.motif; - -import java.awt.*; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetListener; -import java.awt.event.*; -import java.awt.image.ColorModel; -import java.awt.image.ImageObserver; -import java.awt.image.ImageProducer; -import java.awt.image.VolatileImage; -import java.awt.peer.*; -import sun.awt.*; -import sun.awt.motif.X11FontMetrics; -import java.lang.reflect.*; -import java.util.logging.*; -import java.util.*; - -// FIXME: Add X errors handling -// FIXME: Add chaining of parameters to XEmbed-client if we are both(accelerators; XDND; focus already automatically) -public class MEmbedCanvasPeer extends MCanvasPeer implements WindowFocusListener, KeyEventPostProcessor, ModalityListener, WindowIDProvider { - private static final Logger xembedLog = Logger.getLogger("sun.awt.motif.xembed.MEmbedCanvasPeer"); - - final static int XEMBED_VERSION = 0, - XEMBED_MAPPED = (1 << 0); -/* XEMBED messages */ - final static int XEMBED_EMBEDDED_NOTIFY = 0; - final static int XEMBED_WINDOW_ACTIVATE = 1; - final static int XEMBED_WINDOW_DEACTIVATE = 2; - final static int XEMBED_REQUEST_FOCUS =3; - final static int XEMBED_FOCUS_IN = 4; - final static int XEMBED_FOCUS_OUT = 5; - final static int XEMBED_FOCUS_NEXT = 6; - final static int XEMBED_FOCUS_PREV = 7; -/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */ - final static int XEMBED_GRAB_KEY = 8; - final static int XEMBED_UNGRAB_KEY = 9; - final static int XEMBED_MODALITY_ON = 10; - final static int XEMBED_MODALITY_OFF = 11; - final static int XEMBED_REGISTER_ACCELERATOR = 12; - final static int XEMBED_UNREGISTER_ACCELERATOR= 13; - final static int XEMBED_ACTIVATE_ACCELERATOR = 14; - - final static int NON_STANDARD_XEMBED_GTK_GRAB_KEY = 108; - final static int NON_STANDARD_XEMBED_GTK_UNGRAB_KEY = 109; - -// A detail code is required for XEMBED_FOCUS_IN. The following values are valid: -/* Details for XEMBED_FOCUS_IN: */ - final static int XEMBED_FOCUS_CURRENT = 0; - final static int XEMBED_FOCUS_FIRST = 1; - final static int XEMBED_FOCUS_LAST = 2; - -// Modifiers bits - final static int XEMBED_MODIFIER_SHIFT = (1 << 0); - final static int XEMBED_MODIFIER_CONTROL = (1 << 1); - final static int XEMBED_MODIFIER_ALT = (1 << 2); - final static int XEMBED_MODIFIER_SUPER = (1 << 3); - final static int XEMBED_MODIFIER_HYPER = (1 << 4); - - boolean applicationActive; // Whether the application is active(has focus) - Map accelerators = new HashMap(); // Maps accelerator ID into AWTKeyStroke - Map accel_lookup = new HashMap(); // Maps AWTKeyStroke into accelerator ID - Set grabbed_keys = new HashSet(); // A set of keys grabbed by client - Object ACCEL_LOCK = accelerators; // Lock object for working with accelerators; - Object GRAB_LOCK = grabbed_keys; // Lock object for working with keys grabbed by client - - MEmbedCanvasPeer() {} - - MEmbedCanvasPeer(Component target) { - super(target); - } - - void initialize() { - super.initialize(); - - installActivateListener(); - installAcceleratorListener(); - installModalityListener(); - - // XEmbed canvas should be non-traversable. - // FIXME: Probably should be removed and enforced setting of it by the users - target.setFocusTraversalKeysEnabled(false); - - initXEmbedServer(); - } - - void installModalityListener() { - ((SunToolkit)Toolkit.getDefaultToolkit()).addModalityListener(this); - } - - void deinstallModalityListener() { - ((SunToolkit)Toolkit.getDefaultToolkit()).removeModalityListener(this); - } - - void installAcceleratorListener() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this); - } - - void deinstallAcceleratorListener() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this); - } - - void installActivateListener() { - // FIXME: should watch for hierarchy changes - Window toplevel = getTopLevel(target); - if (toplevel != null) { - toplevel.addWindowFocusListener(this); - applicationActive = toplevel.isFocused(); - } - } - - void deinstallActivateListener() { - Window toplevel = getTopLevel(target); - if (toplevel != null) { - toplevel.removeWindowFocusListener(this); - } - } - - native boolean isXEmbedActive(); - - boolean isApplicationActive() { - return applicationActive; - } - - native void initDispatching(); - - native void endDispatching(); - - native void embedChild(long child); - - native void childDestroyed(); - - public void handleEvent(AWTEvent e) { - super.handleEvent(e); - if (isXEmbedActive()) { - switch (e.getID()) { - case FocusEvent.FOCUS_GAINED: - canvasFocusGained((FocusEvent)e); - break; - case FocusEvent.FOCUS_LOST: - canvasFocusLost((FocusEvent)e); - break; - case KeyEvent.KEY_PRESSED: - case KeyEvent.KEY_RELEASED: - if (!((InputEvent)e).isConsumed()) { - forwardKeyEvent((KeyEvent)e); - } - break; - } - } - } - - public Dimension getPreferredSize() { - if (isXEmbedActive()) { - Dimension dim = getEmbedPreferredSize(); - if (dim == null) { - return super.getPreferredSize(); - } else { - return dim; - } - } else { - return super.getPreferredSize(); - } - } - native Dimension getEmbedPreferredSize(); - public Dimension getMinimumSize() { - if (isXEmbedActive()) { - Dimension dim = getEmbedMinimumSize(); - if (dim == null) { - return super.getMinimumSize(); - } else { - return dim; - } - } else { - return super.getMinimumSize(); - } - } - native Dimension getEmbedMinimumSize(); - protected void disposeImpl() { - if (isXEmbedActive()) { - detachChild(); - } - deinstallActivateListener(); - deinstallModalityListener(); - deinstallAcceleratorListener(); - - destroyXEmbedServer(); - super.disposeImpl(); - } - - public boolean isFocusable() { - return true; - } - - Window getTopLevel(Component comp) { - while (comp != null && !(comp instanceof Window)) { - comp = comp.getParent(); - } - return (Window)comp; - } - - native Rectangle getClientBounds(); - - void childResized() { - if (xembedLog.isLoggable(Level.FINER)) { - Rectangle bounds = getClientBounds(); - xembedLog.finer("Child resized: " + bounds); - // It is not required to update embedder's size when client size changes - // However, since there is no any means to get client size it seems to be the - // only way to provide it. However, it contradicts with Java layout concept - - // so it is disabled for now. -// Rectangle my_bounds = getBounds(); -// setBounds(my_bounds.x, my_bounds.y, bounds.width, bounds.height, SET_BOUNDS); - } - postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED)); - } - - void focusNext() { - if (isXEmbedActive()) { - xembedLog.fine("Requesting focus for the next component after embedder"); - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(target); - } - })); - } else { - xembedLog.fine("Application is not active - denying focus next"); - } - } - - void focusPrev() { - if (isXEmbedActive()) { - xembedLog.fine("Requesting focus for the next component after embedder"); - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(target); - } - })); - } else { - xembedLog.fine("Application is not active - denying focus prev"); - } - } - - void requestXEmbedFocus() { - if (isXEmbedActive()) { - xembedLog.fine("Requesting focus for client"); - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - target.requestFocusInWindow(); - } - })); - } else { - xembedLog.fine("Application is not active - denying request focus"); - } - } - - native void notifyChildEmbedded(); - - native void detachChild(); - - public void windowGainedFocus(WindowEvent e) { - applicationActive = true; - if (isXEmbedActive()) { - xembedLog.fine("Sending WINDOW_ACTIVATE"); - sendMessage(XEMBED_WINDOW_ACTIVATE); - } - } - - public void windowLostFocus(WindowEvent e) { - applicationActive = false; - if (isXEmbedActive()) { - xembedLog.fine("Sending WINDOW_DEACTIVATE"); - sendMessage(XEMBED_WINDOW_DEACTIVATE); - } - } - - void canvasFocusGained(FocusEvent e) { - if (isXEmbedActive()) { - xembedLog.fine("Forwarding FOCUS_GAINED"); - int flavor = XEMBED_FOCUS_CURRENT; - if (e instanceof CausedFocusEvent) { - CausedFocusEvent ce = (CausedFocusEvent)e; - if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_FORWARD) { - flavor = XEMBED_FOCUS_FIRST; - } else if (ce.getCause() == CausedFocusEvent.Cause.TRAVERSAL_BACKWARD) { - flavor = XEMBED_FOCUS_LAST; - } - } - sendMessage(XEMBED_FOCUS_IN, flavor, 0, 0); - } - } - - void canvasFocusLost(FocusEvent e) { - if (isXEmbedActive() && !e.isTemporary()) { - xembedLog.fine("Forwarding FOCUS_LOST"); - Component opp = e.getOppositeComponent(); - int num = 0; - try { - num = Integer.parseInt(opp.getName()); - } catch (NumberFormatException nfe) { - } - sendMessage(XEMBED_FOCUS_OUT, num, 0, 0); - } - } - - native void forwardKeyEvent(KeyEvent e); - - void grabKey(final long keysym, final long modifiers) { - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - GrabbedKey grab = new GrabbedKey(keysym, modifiers); - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Grabbing key: " + grab); - synchronized(GRAB_LOCK) { - grabbed_keys.add(grab); - } - } - })); - } - - void ungrabKey(final long keysym, final long modifiers) { - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - GrabbedKey grab = new GrabbedKey(keysym, modifiers); - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("UnGrabbing key: " + grab); - synchronized(GRAB_LOCK) { - grabbed_keys.remove(grab); - } - } - })); - } - - void registerAccelerator(final long accel_id, final long keysym, final long modifiers) { - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - AWTKeyStroke stroke = getKeyStrokeForKeySym(keysym, modifiers); - if (stroke != null) { - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke); - synchronized(ACCEL_LOCK) { - accelerators.put(accel_id, stroke); - accel_lookup.put(stroke, accel_id); - } - } - // Propogate accelerators to the another embedder - propogateRegisterAccelerator(stroke); - } - })); - } - - void unregisterAccelerator(final long accel_id) { - postEvent(new InvocationEvent(target, new Runnable() { - public void run() { - AWTKeyStroke stroke = null; - synchronized(ACCEL_LOCK) { - stroke = accelerators.get(accel_id); - if (stroke != null) { - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Unregistering accelerator: " + accel_id); - accelerators.remove(accel_id); - accel_lookup.remove(stroke); // FIXME: How about several accelerators with the same stroke? - } - } - // Propogate accelerators to the another embedder - propogateUnRegisterAccelerator(stroke); - } - })); - } - - void propogateRegisterAccelerator(AWTKeyStroke stroke) { - // Find the top-level and see if it is XEmbed client. If so, ask him to - // register the accelerator - MWindowPeer parent = getParentWindow(); - if (parent != null && parent instanceof MEmbeddedFramePeer) { - MEmbeddedFramePeer embedded = (MEmbeddedFramePeer)parent; - embedded.registerAccelerator(stroke); - } - } - - void propogateUnRegisterAccelerator(AWTKeyStroke stroke) { - // Find the top-level and see if it is XEmbed client. If so, ask him to - // register the accelerator - MWindowPeer parent = getParentWindow(); - if (parent != null && parent instanceof MEmbeddedFramePeer) { - MEmbeddedFramePeer embedded = (MEmbeddedFramePeer)parent; - embedded.unregisterAccelerator(stroke); - } - } - - public boolean postProcessKeyEvent(KeyEvent e) { - // Processing events only if we are in the focused window. - MWindowPeer parent = getParentWindow(); - if (parent == null || !((Window)parent.target).isFocused() || target.isFocusOwner()) { - return false; - } - - boolean result = false; - - if (xembedLog.isLoggable(Level.FINER)) xembedLog.finer("Post-processing event " + e); - - // Process ACCELERATORS - AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); - long accel_id = 0; - boolean exists = false; - synchronized(ACCEL_LOCK) { - exists = accel_lookup.containsKey(stroke); - if (exists) { - accel_id = accel_lookup.get(stroke).longValue(); - } - } - if (exists) { - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Activating accelerator " + accel_id); - sendMessage(XEMBED_ACTIVATE_ACCELERATOR, accel_id, 0, 0); // FIXME: How about overloaded? - result = true; - } - - // Process Grabs, unofficial GTK feature - exists = false; - GrabbedKey key = new GrabbedKey(e); - synchronized(GRAB_LOCK) { - exists = grabbed_keys.contains(key); - } - if (exists) { - if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Forwarding grabbed key " + e); - forwardKeyEvent(e); - result = true; - } - - return result; - } - - public void modalityPushed(ModalityEvent ev) { - sendMessage(XEMBED_MODALITY_ON); - } - - public void modalityPopped(ModalityEvent ev) { - sendMessage(XEMBED_MODALITY_OFF); - } - - int getModifiers(int state) { - int mods = 0; - if ((state & XEMBED_MODIFIER_SHIFT) != 0) { - mods |= InputEvent.SHIFT_DOWN_MASK; - } - if ((state & XEMBED_MODIFIER_CONTROL) != 0) { - mods |= InputEvent.CTRL_DOWN_MASK; - } - if ((state & XEMBED_MODIFIER_ALT) != 0) { - mods |= InputEvent.ALT_DOWN_MASK; - } - // FIXME: What is super/hyper? - // FIXME: Experiments show that SUPER is ALT. So what is Alt then? - if ((state & XEMBED_MODIFIER_SUPER) != 0) { - mods |= InputEvent.ALT_DOWN_MASK; - } -// if ((state & XEMBED_MODIFIER_HYPER) != 0) { -// mods |= InputEvent.DOWN_MASK; -// } - return mods; - } - - // Shouldn't be called on Toolkit thread. - AWTKeyStroke getKeyStrokeForKeySym(long keysym, long state) { - - int keycode = getAWTKeyCodeForKeySym((int)keysym); - int modifiers = getModifiers((int)state); - return AWTKeyStroke.getAWTKeyStroke(keycode, modifiers); - } - native int getAWTKeyCodeForKeySym(int keysym); - native void sendMessage(int msg); - native void sendMessage(int msg, long detail, long data1, long data2); - MWindowPeer getParentWindow() { - Component parent = target.getParent(); - synchronized(target.getTreeLock()) { - while (parent != null && !(parent.getPeer() instanceof MWindowPeer)) { - parent = parent.getParent(); - } - return (parent != null)?(MWindowPeer)parent.getPeer():null; - } - } - - private static class XEmbedDropTarget extends DropTarget { - public void addDropTargetListener(DropTargetListener dtl) - throws TooManyListenersException { - // Drop target listeners registered with this target will never be - // notified, since all drag notifications are routed to the XEmbed - // client. To avoid confusion we prohibit listeners registration - // by throwing TooManyListenersException as if there is a listener - // registered with this target already. - throw new TooManyListenersException(); - } - } - - public void setXEmbedDropTarget() { - // Register a drop site on the top level. - Runnable r = new Runnable() { - public void run() { - target.setDropTarget(new XEmbedDropTarget()); - } - }; - SunToolkit.executeOnEventHandlerThread(target, r); - } - - public void removeXEmbedDropTarget() { - // Unregister a drop site on the top level. - Runnable r = new Runnable() { - public void run() { - if (target.getDropTarget() instanceof XEmbedDropTarget) { - target.setDropTarget(null); - } - } - }; - SunToolkit.executeOnEventHandlerThread(target, r); - } - - public boolean processXEmbedDnDEvent(long ctxt, int eventID) { - if (target.getDropTarget() instanceof XEmbedDropTarget) { - forwardEventToEmbedded(ctxt, eventID); - return true; - } else { - return false; - } - } - - native void forwardEventToEmbedded(long ctxt, int eventID); - native void initXEmbedServer(); - native void destroyXEmbedServer(); - public native long getWindow(); -} -class GrabbedKey { - long keysym; - long modifiers; - GrabbedKey(long keysym, long modifiers) { - this.keysym = keysym; - this.modifiers = modifiers; - } - - GrabbedKey(KeyEvent ev) { - init(ev); - } - - native void initKeySymAndModifiers(KeyEvent e); - - private void init(KeyEvent e) { - initKeySymAndModifiers(e); - } - - public int hashCode() { - return (int)keysym & 0xFFFFFFFF; - } - - public boolean equals(Object o) { - if (!(o instanceof GrabbedKey)) { - return false; - } - GrabbedKey key = (GrabbedKey)o; - return (keysym == key.keysym && modifiers == key.modifiers); - } - - public String toString() { - return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]"; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFrame.java --- a/jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFrame.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* - * Copyright 1996-2004 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 sun.awt.motif; - -import java.awt.Component; -import java.awt.peer.FramePeer; -import sun.awt.EmbeddedFrame; -import java.awt.peer.ComponentPeer; -import sun.awt.*; -import java.awt.*; - -public class MEmbeddedFrame extends EmbeddedFrame { - - /** - * Widget id of the shell widget - */ - long handle; - - public enum IDKind { - WIDGET, - WINDOW - }; - - public MEmbeddedFrame() { - } - - /** - * Backward-compatible implementation. This constructor takes widget which represents Frame's - * shell and uses it as top-level to build hierarchy of top-level widgets upon. It assumes that - * no XEmbed support is provided. - * @param widget a valid Xt widget pointer. - */ - public MEmbeddedFrame(long widget) { - this(widget, IDKind.WIDGET, false); - } - - /** - * New constructor, gets X Window id and allows to specify whether XEmbed is supported by parent - * X window. Creates hierarchy of top-level widgets under supplied window ID. - * @param winid a valid X window - * @param supportsXEmbed whether the host application supports XEMBED protocol - */ - public MEmbeddedFrame(long winid, boolean supportsXEmbed) { - this(winid, IDKind.WINDOW, supportsXEmbed); - } - - /** - * Creates embedded frame using ID as parent. - * @param ID parent ID - * @param supportsXEmbed whether the host application supports XEMBED protocol - * @param kind if WIDGET, ID represents a valid Xt widget pointer; if WINDOW, ID is a valid X Window - * ID - */ - public MEmbeddedFrame(long ID, IDKind kind, boolean supportsXEmbed) { - super(supportsXEmbed); - if (kind == IDKind.WIDGET) { - this.handle = ID; - } else { - this.handle = getWidget(ID); - } - MToolkit toolkit = (MToolkit)Toolkit.getDefaultToolkit(); - setPeer(toolkit.createEmbeddedFrame(this)); - /* - * addNotify() creates a LightweightDispatcher that propagates - * SunDropTargetEvents to subcomponents. - * NOTE: show() doesn't call addNotify() for embedded frames. - */ - addNotify(); - show(); - } - - public void synthesizeWindowActivation(boolean b) { - MEmbeddedFramePeer peer = (MEmbeddedFramePeer)getPeer(); - if (peer != null) { - if (peer.supportsXEmbed()) { - if (peer.isXEmbedActive()) { - // If XEmbed is active no synthetic focus events are allowed - everything - // should go through XEmbed - if (b) { - peer.requestXEmbedFocus(); - } - } - } else { - peer.synthesizeFocusInOut(b); - } - } - } - - public void show() { - if (handle != 0) { - mapWidget(handle); - } - super.show(); - } - - protected boolean traverseOut(boolean direction) { - MEmbeddedFramePeer xefp = (MEmbeddedFramePeer) getPeer(); - xefp.traverseOut(direction); - return true; - } - - // Native methods to handle widget <-> X Windows mapping - // - static native long getWidget(long winid); - static native int mapWidget(long widget); - public void registerAccelerator(AWTKeyStroke stroke) { - MEmbeddedFramePeer xefp = (MEmbeddedFramePeer) getPeer(); - if (xefp != null) { - xefp.registerAccelerator(stroke); - } - } - public void unregisterAccelerator(AWTKeyStroke stroke) { - MEmbeddedFramePeer xefp = (MEmbeddedFramePeer) getPeer(); - if (xefp != null) { - xefp.unregisterAccelerator(stroke); - } - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* - * 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 - * 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 sun.awt.motif; - -import sun.awt.EmbeddedFrame; -import java.util.logging.*; -import java.awt.Component; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Window; -import java.awt.AWTKeyStroke; -import java.awt.Component; -import java.awt.Container; -import sun.awt.SunToolkit; -import java.util.LinkedList; -import java.util.Iterator; - -import sun.java2d.SurfaceData; - -public class MEmbeddedFramePeer extends MFramePeer { - private static final Logger xembedLog = Logger.getLogger("sun.awt.motif.xembed.MEmbeddedFramePeer"); - -// A detail code is required for XEMBED_FOCUS_IN. The following values are valid: -/* Details for XEMBED_FOCUS_IN: */ - final static int XEMBED_FOCUS_CURRENT = 0; - final static int XEMBED_FOCUS_FIRST = 1; - final static int XEMBED_FOCUS_LAST = 2; - - LinkedList strokes = new LinkedList(); - - public MEmbeddedFramePeer(EmbeddedFrame target) { - super(target); - xembedLog.fine("Creating XEmbed-enabled motif embedded frame, frame supports XEmbed:" + supportsXEmbed()); - } - - void create(MComponentPeer parent) { - NEFcreate(parent, ((MEmbeddedFrame)target).handle); - } - native void NEFcreate(MComponentPeer parent, long handle); - native void pShowImpl(); - void pShow() { - pShowImpl(); - } - - boolean supportsXEmbed() { - EmbeddedFrame frame = (EmbeddedFrame)target; - if (frame != null) { - return frame.supportsXEmbed(); - } else { - return false; - } - } - - public void setVisible(boolean vis) { - super.setVisible(vis); - xembedLog.fine("Peer made visible"); - if (vis && !supportsXEmbed()) { - xembedLog.fine("Synthesizing FocusIn"); - // Fix for 4878303 - generate WINDOW_GAINED_FOCUS and update if we were focused - // since noone will do it for us(WM does it for regular top-levels) - synthesizeFocusInOut(true); - } - } - public native void synthesizeFocusInOut(boolean b); - - native boolean isXEmbedActive(); - native boolean isXEmbedApplicationActive(); - native void requestXEmbedFocus(); - - public boolean requestWindowFocus() { - xembedLog.fine("In requestWindowFocus"); - // Should check for active state of host application - if (isXEmbedActive()) { - if (isXEmbedApplicationActive()) { - xembedLog.fine("Requesting focus from embedding host"); - requestXEmbedFocus(); - return true; - } else { - xembedLog.fine("Host application is not active"); - return false; - } - } else { - xembedLog.fine("Requesting focus from X"); - return super.requestWindowFocus(); - } - } - - void registerAccelerator(AWTKeyStroke stroke) { -// if (stroke == null) return; -// strokes.add(stroke); -// if (isXEmbedActive()) { -// nativeRegisterAccelerator(stroke, strokes.size()-1); -// } - } - - void unregisterAccelerator(AWTKeyStroke stroke) { -// if (stroke == null) return; -// if (isXEmbedActive()) { -// int index = strokes.indexOf(stroke); -// nativeUnregisterAccelerator(index); -// } - } - - void notifyStarted() { - // Register accelerators -// int i = 0; -// Iterator iter = strokes.iterator(); -// while (iter.hasNext()) { -// nativeRegisterAccelerator(iter.next(), i++); -// } - - updateDropTarget(); - } - - native void traverseOut(boolean direction); - - void handleFocusIn(int detail) { - xembedLog.log(Level.FINE, "handleFocusIn {0}", new Object[]{Integer.valueOf(detail)}); - switch(detail) { - case XEMBED_FOCUS_CURRENT: - // Do nothing - just restore to the current value - break; - case XEMBED_FOCUS_FIRST: - SunToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - Component comp = ((Container)target).getFocusTraversalPolicy().getFirstComponent((Container)target); - if (comp != null) { - comp.requestFocusInWindow(); - } - }}); - break; - case XEMBED_FOCUS_LAST: - SunToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - Component comp = ((Container)target).getFocusTraversalPolicy().getLastComponent((Container)target); - if (comp != null) { - comp.requestFocusInWindow(); - } - }}); - break; - } - } - public void handleWindowFocusIn() { - super.handleWindowFocusIn(); - xembedLog.fine("windowFocusIn"); - } - public void handleWindowFocusOut(Window oppositeWindow) { - super.handleWindowFocusOut(oppositeWindow); - xembedLog.fine("windowFocusOut, opposite is null?:" + (oppositeWindow==null)); - } - - native void pReshapePrivate(int x, int y, int w, int h); - - public void setBoundsPrivate(int x, int y, int width, int height) - { - if (disposed) - { - return; - } - - // Should set paintPending before reshape to prevent - // thread race between PaintEvent and setBounds - // This part of the 4267393 fix proved to be unstable under solaris, - // dissabled due to regressions 4418155, 4486762, 4490079 - paintPending = false; //checkNativePaintOnSetBounds(width, height); - - pReshapePrivate(x, y, width, height); - - if ((width != oldWidth) || (height != oldHeight)) - { - SurfaceData oldData = surfaceData; - if (oldData != null) { - surfaceData = graphicsConfig.createSurfaceData(this); - oldData.invalidate(); - } - oldWidth = width; - oldHeight = height; - } - validateSurface(width, height); - serialNum++; - } - - public native Rectangle getBoundsPrivate(); - - @Override - Rectangle constrainBounds(int x, int y, int width, int height) { - // We don't constrain the bounds of the EmbeddedFrames - return new Rectangle(x, y, width, height); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MFileDialogPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MFileDialogPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,300 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.io.*; -import java.awt.datatransfer.*; -import java.util.ArrayList; -import sun.awt.datatransfer.ToolkitThreadBlockedHandler; - -public class MFileDialogPeer extends MDialogPeer implements FileDialogPeer { - private FilenameFilter filter; - private String[] NativeFilteredFiles; - native void create(MComponentPeer parent); - void create(MComponentPeer parent, Object arg) { - create(parent); - } - public MFileDialogPeer(FileDialog target) { - super(target); - FileDialog fdialog = (FileDialog)target; - String dir = fdialog.getDirectory(); - String file = fdialog.getFile(); - FilenameFilter filter = fdialog.getFilenameFilter(); - - insets = new Insets(0, 0, 0, 0); - setDirectory(dir); - if (file != null) { - setFile(file); - } - setFilenameFilter(filter); - } - native void pReshape(int x, int y, int width, int height); - native void pDispose(); - native void pShow(); - native void pHide(); - native void setFileEntry(String dir, String file, String[] ffiles); - native void insertReplaceFileDialogText(String l); - public native void setFont(Font f); - - String getFilteredFile(String file) { - if (file == null) { - file = ((FileDialog)target).getFile(); - } - String dir = ((FileDialog)target).getDirectory(); - if (dir == null) { - dir = "./"; - } - if (file == null) { - file = ""; - } - if (filter != null && !filter.accept(new File(dir), file)) { - file = ""; - } - return file; - } - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleSelected(final String file) { - final FileDialog fileDialog = (FileDialog)target; - MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() { - public void run() { - int index = file.lastIndexOf(java.io.File.separatorChar);/*2509*//*ibm*/ - String dir; - - if (index == -1) { - dir = "."+java.io.File.separator; - fileDialog.setFile(file); - } else { - dir = file.substring(0, index + 1); - fileDialog.setFile(file.substring(index + 1)); - } - fileDialog.setDirectory(dir); - fileDialog.hide(); - } - }); - } // handleSelected() - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleCancel() { - final FileDialog fileDialog = (FileDialog)target; - MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() { - public void run() { - fileDialog.setFile(null); - fileDialog.hide(); - } - }); - } // handleCancel() - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleQuit() { - final FileDialog fileDialog = (FileDialog)target; - MToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() { - public void run() { - fileDialog.hide(); - } - }); - } // handleQuit() - - public void setDirectory(String dir) { - String file = ((FileDialog)target).getFile(); - setFileEntry((dir != null) ? dir : "./", (file != null) ? file - : "", null); - } - - - public void setFile(String file) { - String dir = ((FileDialog)target).getDirectory(); - if (dir == null) { - dir = "./"; - } - setFileEntry((dir != null) ? dir : "./", getFilteredFile(null), null); - } - class DirectoryFilter implements FilenameFilter { - FilenameFilter userFilter; - DirectoryFilter(FilenameFilter userFilter) { - this.userFilter = userFilter; - } - public boolean accept(File parent, String name) { - File toTest = new File(parent, name); - if (toTest.isDirectory()) { - return false; - } else if (userFilter != null) { - return userFilter.accept(parent, name); - } else { - return true; - } - } - } - public void doFilter(FilenameFilter filter, String dir) { - String d = (dir == null) ? (((FileDialog)target).getDirectory()):(dir); - String f = getFilteredFile(null); - File df = new File((d != null) ? d : "."); - String[] files = df.list(new DirectoryFilter(filter)); - String[] nffiles = NativeFilteredFiles; - - // At this point we have two file lists. - // The first one is a filtered list of files that we retrieve - // by using Java code and Java filter. - // The second one is a filtered list of files that we retrieve - // by using the native code and native pattern. - // We should find an intersection of these two lists. The result - // will be exactly what we expect to see in setFileEntry. - // For more details please see 4784704. - if ( files != null ) { - ArrayList filearr = new ArrayList(); - if (nffiles != null) { - for (int j = 0; j < files.length; j++) { - for (int n = 0; n < nffiles.length; n++) { - if (files[j].equals(nffiles[n])) { - filearr.add(files[j]); - break; - } - } - } - } - files = new String[filearr.size()]; - for (int i = 0; i < files.length; i++) { - files[i] = (String)filearr.get(i); - } - } - if (files == null || files.length == 0) { - files = new String[1]; - files[0] = ""; - } - setFileEntry((d != null) ? d : ".", (f != null) ? f : "", files); - } - private boolean proceedFiltering(final String dir, String[] nffiles, - boolean isPrivileged) - { - // Transfer the native filtered file list to the doFilter method. - NativeFilteredFiles = nffiles; - // If we are not on the Toolkit thread we can call doFilter() directly. - // If the filter is null no user code will be invoked - if (!isPrivileged || filter == null) { - try { - doFilter(filter, dir); - return true; - } catch(Exception e) { - e.printStackTrace(); - return false; - } - } - // Otherwise we have to call user code on EvenDispatchThread - final ToolkitThreadBlockedHandler priveleged_lock = - MToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler(); - final boolean[] finished = new boolean[1]; - final boolean[] result = new boolean[1]; - finished[0] = false; - result[0] = false; - - - // Use the same Toolkit blocking mechanism as in DnD. - priveleged_lock.lock(); - - MToolkit.executeOnEventHandlerThread((FileDialog)target, new Runnable() { - public void run() { - priveleged_lock.lock(); - try { - doFilter(filter, dir); - result[0] = true; - } catch (Exception e) { - e.printStackTrace(); - result[0] = false; - } finally { - finished[0] = true; - priveleged_lock.exit(); - priveleged_lock.unlock(); - } - } - }); - - while (!finished[0]) { - priveleged_lock.enter(); - } - - priveleged_lock.unlock(); - - return result[0]; - } - - public void setFilenameFilter(FilenameFilter filter) { - this.filter = filter; - FileDialog fdialog = (FileDialog)target; - String dir = fdialog.getDirectory(); - String file = fdialog.getFile(); - setFile(file); - doFilter(filter, null); - } - - // Called from native widget when paste key is pressed and we - // already own the selection (prevents Motif from hanging while - // waiting for the selection) - // - public void pasteFromClipboard() { - Clipboard clipboard = target.getToolkit().getSystemClipboard(); - - Transferable content = clipboard.getContents(this); - if (content != null) { - try { - String data = (String)(content.getTransferData(DataFlavor.stringFlavor)); - insertReplaceFileDialogText(data); - } catch (Exception e) { - } - } - } - -// CAVEAT: -// Peer coalescing code turned over the fact that the following functions -// were being inherited from Dialog and were not implemented in awt_FileDialog.c -// Five methods decribed by the peer interface are at fault (setResizable, setTitle, -// toFront, toBack and handleFocusTraversalEvent). Additionally show has to be overridden -// as it was necessary to add a show function in MDialogPeer for modality flag passing. -// As a result we were winding up in awt_Dialog.c (now coalesced into awt_TopLevel). -// As Filedialogs are modal and its unclear to me that any of these functions -// can be called while the FD is on-screen let it go. RJM. - public void show() { - // must have our own show or we wind up in pShow for Window. Bad. Very bad. - setVisible(true); - setFilenameFilter(filter); - } - - /** - * MFileDialogPeer doesn't have native pData so we don't do restack on it - * @see java.awt.peer.ContainerPeer#restack - */ - public void restack() { - } - - /** - * @see java.awt.peer.ContainerPeer#isRestackSupported - */ - public boolean isRestackSupported() { - return false; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MFramePeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,511 +0,0 @@ -/* - * 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 - * 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 sun.awt.motif; - -import java.util.Vector; -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.*; -import sun.awt.motif.MInputMethodControl; -import sun.awt.im.*; -import java.awt.image.ColorModel; -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferInt; -import java.awt.image.DataBufferByte; -import java.awt.image.DataBufferUShort; -import java.awt.image.ImageObserver; -import java.awt.image.WritableRaster; -import sun.awt.image.ImageRepresentation; -import sun.awt.image.ToolkitImage; - -class MFramePeer extends MWindowPeer implements FramePeer, MInputMethodControl { - static Vector allFrames = new Vector(); - - // XXX: Stub out for now. Need to propagate to normal size hints. - public void setMaximizedBounds(Rectangle b) {} - - public void create(MComponentPeer parent, Object arg) { - super.create( parent ); - } - - MFramePeer(Frame target) { - super(); - // set the window attributes for this Frame - winAttr.nativeDecor = !target.isUndecorated(); - winAttr.initialFocus = true; - winAttr.isResizable = target.isResizable(); - winAttr.initialState = target.getState(); - winAttr.title = target.getTitle(); - winAttr.icon = target.getIconImage(); - if (winAttr.nativeDecor) { - winAttr.decorations = winAttr.AWT_DECOR_ALL; - } else { - winAttr.decorations = winAttr.AWT_DECOR_NONE; - } - - // for input method windows, use minimal decorations - if (target instanceof InputMethodWindow) { - winAttr.initialFocus = false; - winAttr.decorations = (winAttr.AWT_DECOR_TITLE | winAttr.AWT_DECOR_BORDER); - } - - // create and init native component - init( target); - if (winAttr.icon != null) { - setIconImage(winAttr.icon); - } - allFrames.addElement(this); - } - - public void setTitle(String title) { - pSetTitle(title); - } - - protected void disposeImpl() { - allFrames.removeElement(this); - super.disposeImpl(); - } - - public void setMenuBar(MenuBar mb) { - MMenuBarPeer mbpeer = (MMenuBarPeer) MToolkit.targetToPeer(mb); - pSetMenuBar(mbpeer); - - Rectangle r = target.bounds(); - - pReshape(r.x, r.y, r.width, r.height); - if (target.isVisible()) { - target.validate(); - } - } - - public void setIconImage(Image im) { - int width; - int height; - GraphicsConfiguration defaultGC; - if (im != null) { // 4633887 Avoid Null pointer exception. - if (im instanceof ToolkitImage) { - ImageRepresentation ir = ((ToolkitImage)im).getImageRep(); - ir.reconstruct(ImageObserver.ALLBITS); - width = ir.getWidth(); - height = ir.getHeight(); - } - else { - width = im.getWidth(null); - height = im.getHeight(null); - } - if (pGetIconSize(width, height)) { - //Icons are displayed using the default visual, so create image - //using default GraphicsConfiguration - defaultGC = getGraphicsConfiguration().getDevice(). - getDefaultConfiguration(); - ColorModel model = defaultGC.getColorModel(); - WritableRaster raster = - model.createCompatibleWritableRaster(iconWidth, iconHeight); - Image image = new BufferedImage(model, raster, - model.isAlphaPremultiplied(), - null); - - // ARGB BufferedImage to hunt for transparent pixels - BufferedImage bimage = - new BufferedImage(iconWidth, iconHeight, - BufferedImage.TYPE_INT_ARGB); - ColorModel alphaCheck = bimage.getColorModel(); - Graphics g = image.getGraphics(); - Graphics big = bimage.getGraphics(); - try { - g.drawImage(im, 0, 0, iconWidth, iconHeight, null); - big.drawImage(im, 0, 0, iconWidth, iconHeight, null); - } finally { - g.dispose(); - big.dispose(); - } - - DataBuffer db = ((BufferedImage)image).getRaster().getDataBuffer(); - DataBuffer bidb = bimage.getRaster().getDataBuffer(); - byte[] bytedata = null; - int[] intdata = null; - int bidbLen = bidb.getSize(); - int imgDataIdx; - //Get native RGB value for window background color - //Should work for byte as well as int - int bgRGB = getNativeColor(SystemColor.window, defaultGC); - - /* My first attempt at a solution to bug 4175560 was to use - * the iconMask and iconPixmap attributes of Windows. - * This worked fine on CDE/dtwm, however olwm displayed only - * single color icons (white on background). Instead, the - * fix gets the default background window color and replaces - * transparent pixels in the icon image with this color. This - * solutions works well with dtwm as well as olwm. - */ - - for (imgDataIdx = 0; imgDataIdx < bidbLen; imgDataIdx++) { - if (alphaCheck.getAlpha(bidb.getElem(imgDataIdx)) == 0 ) { - //Assuming single data bank - db.setElem(imgDataIdx, bgRGB); - } - } - short[] ushortdata = null; - if (db instanceof DataBufferByte) { - // Pseudocolor data - bytedata = ((DataBufferByte)db).getData(); - } - else if (db instanceof DataBufferInt) { - // Truecolor data - intdata = ((DataBufferInt) db).getData(); - } - else if (db instanceof DataBufferUShort) { - // Truecolor data - ushortdata = ((DataBufferUShort) db).getData(); - } - pSetIconImage(bytedata, intdata, ushortdata, - iconWidth, iconHeight); - } - } - } - - native boolean pGetIconSize(int widthHint, int heightHint); - - // [jk] added ushortData for 16-bpp displays - native void pSetIconImage(byte[] byteData, - int[] intData, - short[] ushortData, - int iconWidth, int iconHeight); - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleIconify() { - postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleDeiconify() { - postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); - } - - - /** - * Called to inform the Frame that it has moved. - */ - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleMoved(int x, int y) { - postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); - } - - static final int CROSSHAIR_INSET = 5; - - static final int BUTTON_Y = CROSSHAIR_INSET + 1; - static final int BUTTON_W = 17; - static final int BUTTON_H = 17; - - static final int SYS_MENU_X = CROSSHAIR_INSET + 1; - static final int SYS_MENU_CONTAINED_X = SYS_MENU_X + 5; - static final int SYS_MENU_CONTAINED_Y = BUTTON_Y + 7; - static final int SYS_MENU_CONTAINED_W = 8; - static final int SYS_MENU_CONTAINED_H = 3; - - static final int MAXIMIZE_X_DIFF = CROSSHAIR_INSET + BUTTON_W; - static final int MAXIMIZE_CONTAINED_X_DIFF = MAXIMIZE_X_DIFF - 5; - static final int MAXIMIZE_CONTAINED_Y = BUTTON_Y + 5; - static final int MAXIMIZE_CONTAINED_W = 8; - static final int MAXIMIZE_CONTAINED_H = 8; - - static final int MINIMIZE_X_DIFF = MAXIMIZE_X_DIFF + BUTTON_W; - static final int MINIMIZE_CONTAINED_X_DIFF = MINIMIZE_X_DIFF - 7; - static final int MINIMIZE_CONTAINED_Y = BUTTON_Y + 7; - static final int MINIMIZE_CONTAINED_W = 3; - static final int MINIMIZE_CONTAINED_H = 3; - - static final int TITLE_X = SYS_MENU_X + BUTTON_W; - static final int TITLE_W_DIFF = BUTTON_W * 3 + CROSSHAIR_INSET * 2 - 1; - static final int TITLE_MID_Y = BUTTON_Y + (BUTTON_H / 2); - - static final int MENUBAR_X = CROSSHAIR_INSET + 1; - static final int MENUBAR_Y = BUTTON_Y + BUTTON_H; - - static final int HORIZ_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_H; - static final int VERT_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_W; - - - /* - * Print the native component by rendering the Motif look ourselves. - * We also explicitly print the MenuBar since a MenuBar isn't a subclass - * of Component (and thus it has no "print" method which gets called by - * default). - */ - public void print(Graphics g) { - super.print(g); - - Frame f = (Frame)target; - Insets finsets = f.getInsets(); - Dimension fsize = f.getSize(); - - Color bg = f.getBackground(); - Color fg = f.getForeground(); - Color highlight = bg.brighter(); - Color shadow = bg.darker(); - - // Well, we could query for the currently running window manager - // and base the look on that, or we could just always do dtwm. - // aim, tball, and levenson all agree we'll just do dtwm. - - if (hasDecorations(MWindowAttributes.AWT_DECOR_BORDER)) { - - // top outer -- because we'll most likely be drawing on white paper, - // for aesthetic reasons, don't make any part of the outer border - // pure white - if (highlight.equals(Color.white)) { - g.setColor(new Color(230, 230, 230)); - } - else { - g.setColor(highlight); - } - g.drawLine(0, 0, fsize.width, 0); - g.drawLine(0, 1, fsize.width - 1, 1); - - // left outer - // if (highlight.equals(Color.white)) { - // g.setColor(new Color(230, 230, 230)); - // } - // else { - // g.setColor(highlight); - // } - g.drawLine(0, 0, 0, fsize.height); - g.drawLine(1, 0, 1, fsize.height - 1); - - // bottom cross-hair - g.setColor(highlight); - g.drawLine(CROSSHAIR_INSET + 1, fsize.height - CROSSHAIR_INSET, - fsize.width - CROSSHAIR_INSET, - fsize.height - CROSSHAIR_INSET); - - // right cross-hair - // g.setColor(highlight); - g.drawLine(fsize.width - CROSSHAIR_INSET, CROSSHAIR_INSET + 1, - fsize.width - CROSSHAIR_INSET, - fsize.height - CROSSHAIR_INSET); - - // bottom outer - g.setColor(shadow); - g.drawLine(1, fsize.height, fsize.width, fsize.height); - g.drawLine(2, fsize.height - 1, fsize.width, fsize.height - 1); - - // right outer - // g.setColor(shadow); - g.drawLine(fsize.width, 1, fsize.width, fsize.height); - g.drawLine(fsize.width - 1, 2, fsize.width - 1, fsize.height); - - // top cross-hair - // g.setColor(shadow); - g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET, - fsize.width - CROSSHAIR_INSET, CROSSHAIR_INSET); - - // left cross-hair - // g.setColor(shadow); - g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET, CROSSHAIR_INSET, - fsize.height - CROSSHAIR_INSET); - } - - if (hasDecorations(MWindowAttributes.AWT_DECOR_TITLE)) { - - if (hasDecorations(MWindowAttributes.AWT_DECOR_MENU)) { - - // system menu - g.setColor(bg); - g.fill3DRect(SYS_MENU_X, BUTTON_Y, BUTTON_W, BUTTON_H, true); - g.fill3DRect(SYS_MENU_CONTAINED_X, SYS_MENU_CONTAINED_Y, - SYS_MENU_CONTAINED_W, SYS_MENU_CONTAINED_H, true); - } - - // title bar - // g.setColor(bg); - g.fill3DRect(TITLE_X, BUTTON_Y, fsize.width - TITLE_W_DIFF, BUTTON_H, - true); - - if (hasDecorations(MWindowAttributes.AWT_DECOR_MINIMIZE)) { - - // minimize button - // g.setColor(bg); - g.fill3DRect(fsize.width - MINIMIZE_X_DIFF, BUTTON_Y, BUTTON_W, - BUTTON_H, true); - g.fill3DRect(fsize.width - MINIMIZE_CONTAINED_X_DIFF, - MINIMIZE_CONTAINED_Y, MINIMIZE_CONTAINED_W, - MINIMIZE_CONTAINED_H, true); - } - - if (hasDecorations(MWindowAttributes.AWT_DECOR_MAXIMIZE)) { - - // maximize button - // g.setColor(bg); - g.fill3DRect(fsize.width - MAXIMIZE_X_DIFF, BUTTON_Y, BUTTON_W, - BUTTON_H, true); - g.fill3DRect(fsize.width - MAXIMIZE_CONTAINED_X_DIFF, - MAXIMIZE_CONTAINED_Y, MAXIMIZE_CONTAINED_W, - MAXIMIZE_CONTAINED_H, true); - } - - // title bar text - g.setColor(fg); - Font sysfont = new Font(Font.SANS_SERIF, Font.PLAIN, 10); - g.setFont(sysfont); - FontMetrics sysfm = g.getFontMetrics(); - String ftitle = f.getTitle(); - g.drawString(ftitle, - ((TITLE_X + TITLE_X + fsize.width - TITLE_W_DIFF) / 2) - - (sysfm.stringWidth(ftitle) / 2), - TITLE_MID_Y + sysfm.getMaxDescent()); - } - - if (f.isResizable() && - hasDecorations(MWindowAttributes.AWT_DECOR_RESIZEH)) { - - // add resize cross hairs - - // upper-left horiz (shadow) - g.setColor(shadow); - g.drawLine(1, HORIZ_RESIZE_INSET, CROSSHAIR_INSET, - HORIZ_RESIZE_INSET); - // upper-left vert (shadow) - // g.setColor(shadow); - g.drawLine(VERT_RESIZE_INSET, 1, VERT_RESIZE_INSET, CROSSHAIR_INSET); - // upper-right horiz (shadow) - // g.setColor(shadow); - g.drawLine(fsize.width - CROSSHAIR_INSET + 1, HORIZ_RESIZE_INSET, - fsize.width, HORIZ_RESIZE_INSET); - // upper-right vert (shadow) - // g.setColor(shadow); - g.drawLine(fsize.width - VERT_RESIZE_INSET - 1, 2, - fsize.width - VERT_RESIZE_INSET - 1, CROSSHAIR_INSET + 1); - // lower-left horiz (shadow) - // g.setColor(shadow); - g.drawLine(1, fsize.height - HORIZ_RESIZE_INSET - 1, - CROSSHAIR_INSET, fsize.height - HORIZ_RESIZE_INSET - 1); - // lower-left vert (shadow) - // g.setColor(shadow); - g.drawLine(VERT_RESIZE_INSET, fsize.height - CROSSHAIR_INSET + 1, - VERT_RESIZE_INSET, fsize.height); - // lower-right horiz (shadow) - // g.setColor(shadow); - g.drawLine(fsize.width - CROSSHAIR_INSET + 1, - fsize.height - HORIZ_RESIZE_INSET - 1, fsize.width, - fsize.height - HORIZ_RESIZE_INSET - 1); - // lower-right vert (shadow) - // g.setColor(shadow); - g.drawLine(fsize.width - VERT_RESIZE_INSET - 1, - fsize.height - CROSSHAIR_INSET + 1, - fsize.width - VERT_RESIZE_INSET - 1, fsize.height); - - // upper-left horiz (highlight) - g.setColor(highlight); - g.drawLine(2, HORIZ_RESIZE_INSET + 1, CROSSHAIR_INSET, - HORIZ_RESIZE_INSET + 1); - // upper-left vert (highlight) - // g.setColor(highlight); - g.drawLine(VERT_RESIZE_INSET + 1, 2, VERT_RESIZE_INSET + 1, - CROSSHAIR_INSET); - // upper-right horiz (highlight) - // g.setColor(highlight); - g.drawLine(fsize.width - CROSSHAIR_INSET + 1, - HORIZ_RESIZE_INSET + 1, fsize.width - 1, - HORIZ_RESIZE_INSET + 1); - // upper-right vert (highlight) - // g.setColor(highlight); - g.drawLine(fsize.width - VERT_RESIZE_INSET, 2, - fsize.width - VERT_RESIZE_INSET, CROSSHAIR_INSET); - // lower-left horiz (highlight) - // g.setColor(highlight); - g.drawLine(2, fsize.height - HORIZ_RESIZE_INSET, CROSSHAIR_INSET, - fsize.height - HORIZ_RESIZE_INSET); - // lower-left vert (highlight) - // g.setColor(highlight); - g.drawLine(VERT_RESIZE_INSET + 1, - fsize.height - CROSSHAIR_INSET + 1, - VERT_RESIZE_INSET + 1, fsize.height - 1); - // lower-right horiz (highlight) - // g.setColor(highlight); - g.drawLine(fsize.width - CROSSHAIR_INSET + 1, - fsize.height - HORIZ_RESIZE_INSET, fsize.width - 1, - fsize.height - HORIZ_RESIZE_INSET); - // lower-right vert (highlight) - // g.setColor(highlight); - g.drawLine(fsize.width - VERT_RESIZE_INSET, - fsize.height - CROSSHAIR_INSET + 1, - fsize.width - VERT_RESIZE_INSET, fsize.height - 1); - } - - MenuBar mb = f.getMenuBar(); - if (mb != null) { - MMenuBarPeer peer = (MMenuBarPeer) MToolkit.targetToPeer(mb); - if (peer != null) { - Insets insets = getInsets(); - Graphics ng = g.create(); - int menubarX = 0; - int menubarY = 0; - if (hasDecorations(MWindowAttributes.AWT_DECOR_BORDER)) { - menubarX += CROSSHAIR_INSET + 1; - menubarY += CROSSHAIR_INSET + 1; - } - if (hasDecorations(MWindowAttributes.AWT_DECOR_TITLE)) { - menubarY += BUTTON_H; - } - try { - ng.translate(menubarX, menubarY); - peer.print(ng); - } finally { - ng.dispose(); - } - } - } - } - - // Saveunders are not done by Frame. - void setSaveUnder(boolean state) {} - - /* Returns the native paint should be posted after setting new size - */ - public boolean checkNativePaintOnSetBounds(int width, int height) { - // Fix for 4418155. Undecorated Frame does not repaint - // automticaly if shrinking. Should not wait for Expose - return ((Frame)target).isUndecorated() ? - ((width > oldWidth) || (height > oldHeight)): - ((width != oldWidth) || (height != oldHeight)); - } - - public void setBoundsPrivate(int x, int y, int width, int height) { - setBounds(x, y, width, height); - } - - public Rectangle getBoundsPrivate() { - return getBounds(); - } - - @Override - final boolean isTargetUndecorated() { - return ((Frame)target).isUndecorated(); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MGlobalCursorManager.java --- a/jdk/src/solaris/classes/sun/awt/motif/MGlobalCursorManager.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - * Copyright 1999-2004 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 sun.awt.motif; - -import java.awt.*; -import sun.awt.GlobalCursorManager; -import sun.awt.GlobalCursorManager.*; - -public final class MGlobalCursorManager extends GlobalCursorManager { - - static { - cacheInit(); - } - - private native static void cacheInit(); - - // cached nativeContainer - private Component nativeContainer; - - - /** - * The MGlobalCursorManager is a singleton. - */ - private static MGlobalCursorManager manager; - - - static GlobalCursorManager getCursorManager() { - if (manager == null) { - manager = new MGlobalCursorManager(); - } - return manager; - } - - /** - * Should be called in response to a native mouse enter or native mouse - * button released message. Should not be called during a mouse drag. - */ - static void nativeUpdateCursor(Component heavy) { - MGlobalCursorManager.getCursorManager().updateCursorLater(heavy); - } - - - protected void setCursor(Component comp, Cursor cursor, boolean useCache) { - if (comp == null) { - return; - } - - Cursor cur = useCache ? cursor : getCapableCursor(comp); - - Component nc = useCache ? nativeContainer : getNativeContainer(comp); - - // System.out.println(" set cursor="+cursor+" on "+comp+" new curs="+cur); - if (nc != null && nc.isDisplayable()) { - nativeContainer = nc; - ((MComponentPeer)nc.getPeer()).pSetCursor(cur); - } - } - - private Component getNativeContainer(Component comp) { - while (comp != null && comp.isLightweight()) { - comp = comp.getParent(); - } - return comp; - } - - protected native void getCursorPos(Point p); - protected native Component findHeavyweightUnderCursor(); - - /* - * two native methods to call corresponding methods in Container and - * Component - */ - protected native Component findComponentAt(Container con, int x, int y); - protected native Point getLocationOnScreen(Component com); - - protected Component findHeavyweightUnderCursor(boolean useCache) { - return findHeavyweightUnderCursor(); - } - - private Cursor getCapableCursor(Component comp) { - Component c = comp; - while ((c != null) && !(c instanceof Window) && - c.isEnabled() && c.isVisible() && c.isDisplayable()) { - c = c.getParent(); - } - if (c instanceof Window) { - return (c.isEnabled() && c.isVisible() && c.isDisplayable() && comp.isEnabled()) ? - comp.getCursor() : - Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); - } else if (c == null) { - return null; - } - return getCapableCursor(c.getParent()); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MInputMethod.java --- a/jdk/src/solaris/classes/sun/awt/motif/MInputMethod.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright 2003-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. - */ - -package sun.awt.motif; - -import java.awt.AWTException; -import java.awt.Component; -import java.awt.Container; -import java.awt.Window; -import java.awt.peer.ComponentPeer; -import sun.awt.X11InputMethod; -import sun.awt.SunToolkit; - -/** - * Input Method Adapter for XIM (with Motif) - * - * @author JavaSoft International - */ -public class MInputMethod extends X11InputMethod { - - public MInputMethod() throws AWTException { - super(); - } - - protected boolean openXIM() { - return openXIMNative(); - } - - protected boolean createXIC() { - MComponentPeer peer = (MComponentPeer)getPeer(clientComponentWindow); - if (peer == null) { - return false; - } - MComponentPeer tc = null; - if (peer instanceof MInputMethodControl) { - tc = ((MInputMethodControl)peer).getTextComponent(); - } - if (!createXICNative(peer, tc)) { - return false; - } - if (peer instanceof MInputMethodControl) { - ((MInputMethodControl)peer).addInputMethod(this); - } - return true; - } - - protected void setXICFocus(ComponentPeer peer, - boolean value, boolean active) { - setXICFocusNative((MComponentPeer)peer, value, active); - } - - protected Container getParent(Component client) { - // SECURITY: Use _NoClientCode(), because this thread may - // be privileged - return MComponentPeer.getParent_NoClientCode(client); - } - - /** - * Returns peer of the given client component. If the given client component - * doesn't have peer, peer of the native container of the client is returned. - */ - protected ComponentPeer getPeer(Component client) { - MComponentPeer peer = (MComponentPeer)MToolkit.targetToPeer(client); - if (peer != null) - return peer; - - Container nativeContainer = MToolkit.getNativeContainer(client); - peer = (MComponentPeer)MToolkit.targetToPeer(nativeContainer); - return peer; - } - - /** - * Changes the status area configuration that is to be requested - * by Frame or Dialog. - */ - void configureStatus() { - if (isDisposed()) { - return; - } - - MComponentPeer peer = (MComponentPeer)getPeer((Window) clientComponentWindow); - MComponentPeer tc = ((MInputMethodControl)peer).getTextComponent(); - if (tc != null) { - configureStatusAreaNative(tc); - } - } - - /* - * Subclasses should override disposeImpl() instead of dispose(). Client - * code should always invoke dispose(), never disposeImpl(). - */ - protected synchronized void disposeImpl() { - if (clientComponentWindow != null) { - MComponentPeer peer = (MComponentPeer)getPeer(clientComponentWindow); - if (peer instanceof MInputMethodControl) - ((MInputMethodControl)peer).removeInputMethod(this); - clientComponentWindow = null; - } - - super.disposeImpl(); - } - - /** - * @see java.awt.im.spi.InputMethod#removeNotify - */ - public synchronized void removeNotify() { - if (MToolkit.targetToPeer(getClientComponent()) != null) { - dispose(); - } else { - // We do not have to dispose XICs in case of lightweight component. - resetXIC(); - } - } - - /** - * Changes the internal XIC configurations. This is required the - * case that addition or elimination of text components has - * happened in the containment hierarchy. This method is invoked - * by Frame or Dialog. - */ - synchronized void reconfigureXIC(MInputMethodControl control) { - if (!isDisposed()) { - // Some IM servers require to reset XIC before destroying - // the XIC. I.e., Destroying XIC doesn't reset the internal - // state of the IM server. endComposition() takes care of - // resetting XIC and preedit synchronization. However, - // there is no client at this point. It is assumed that - // the previous client is still available for dispatching - // committed text which maintains client's composition - // context. - endComposition(); - resetXICifneeded(); - reconfigureXICNative((MComponentPeer) control, control.getTextComponent()); - } - } - - protected void awtLock() { - SunToolkit.awtLock(); - } - - protected void awtUnlock() { - SunToolkit.awtUnlock(); - } - - /* - * Native methods - */ - private native boolean openXIMNative(); - private native boolean createXICNative(MComponentPeer peer, MComponentPeer tc); - private native void reconfigureXICNative(MComponentPeer peer, - MComponentPeer tc); - private native void configureStatusAreaNative(MComponentPeer tc); - private native void setXICFocusNative(MComponentPeer peer, - boolean value, boolean active); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MInputMethodControl.java --- a/jdk/src/solaris/classes/sun/awt/motif/MInputMethodControl.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright 1997-2003 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 sun.awt.motif; - -import sun.awt.motif.MComponentPeer; -import sun.awt.motif.MInputMethod; - -/** - * An interface for controlling containment hierarchy configuration to - * keep track of existence of any TextArea or TextField and to manage - * input method status area. - * - * @auther JavaSoft International - */ -interface MInputMethodControl { - - /** - * Informs Frame or Dialog that a text component has been added to - * the hierarchy. - * @param textComponentPeer peer of the text component - */ - void addTextComponent(MComponentPeer textComponentPeer); - - /** - * Informs Frame or Dialog that a text component has been removed - * from the hierarchy. - * @param textComponentPeer peer of the text component - */ - void removeTextComponent(MComponentPeer textComponentPeer); - - /** - * Returns a text component peer in the containment hierarchy - * to obtain the Motif status area information - */ - MComponentPeer getTextComponent(); - - /** - * Inform Frame or Dialog that an MInputMethod has been - * constructed so that Frame and Dialog can invoke the method in - * MInputMethod to reconfigure XICs. - * @param inputMethod an MInputMethod instance - */ - void addInputMethod(MInputMethod inputMethod); - - /** - * Inform Frame or Dialog that an X11InputMethod is being destroyed. - * @param inputMethod an X11InputMethod instance - */ - void removeInputMethod(MInputMethod inputMethod); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MInputMethodDescriptor.java --- a/jdk/src/solaris/classes/sun/awt/motif/MInputMethodDescriptor.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright 2003 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 sun.awt.motif; - -import java.awt.im.spi.InputMethod; -import sun.awt.X11InputMethodDescriptor; - -/** - * Provides sufficient information about an input method - * to enable selection and loading of that input method. - * The input method itself is only loaded when it is actually used. - * - * @since JDK1.3 - */ - -class MInputMethodDescriptor extends X11InputMethodDescriptor { - - /** - * @see java.awt.im.spi.InputMethodDescriptor#createInputMethod - */ - public InputMethod createInputMethod() throws Exception { - return new MInputMethod(); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MLabelPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MLabelPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright 1995-1996 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; - -class MLabelPeer extends MComponentPeer implements LabelPeer { - native void create(MComponentPeer parent); - - public void initialize() { - Label l = (Label)target; - String txt; - int align; - - if ((txt = l.getText()) != null) { - setText(l.getText()); - } - if ((align = l.getAlignment()) != Label.LEFT) { - setAlignment(align); - } - super.initialize(); - } - - MLabelPeer(Label target) { - super(target); - } - - public Dimension getMinimumSize() { - FontMetrics fm = getFontMetrics(target.getFont()); - String label = ((Label)target).getText(); - if (label == null) label = ""; - return new Dimension(fm.stringWidth(label) + 14, - fm.getHeight() + 8); - } - - public native void setText(String label); - public native void setAlignment(int alignment); - - /* - * Print the native component by rendering the Motif look ourselves. - */ - public void print(Graphics g) { - Label l = (Label)target; - Dimension d = l.size(); - Color bg = l.getBackground(); - Color fg = l.getForeground(); - - g.setColor(bg); - g.fillRect(1, 1, d.width - 2, d.height - 2); - - g.setColor(fg); - g.setFont(l.getFont()); - FontMetrics fm = g.getFontMetrics(); - String lbl = l.getText(); - - switch (l.getAlignment()) { - case Label.LEFT: - g.drawString(lbl, 2, - (d.height + fm.getMaxAscent() - fm.getMaxDescent()) / 2); - break; - case Label.RIGHT: - g.drawString(lbl, d.width - (fm.stringWidth(lbl) + 2), - (d.height + fm.getMaxAscent() - fm.getMaxDescent()) / 2); - break; - case Label.CENTER: - g.drawString(lbl, (d.width - fm.stringWidth(lbl)) / 2, - (d.height + fm.getMaxAscent() - fm.getMaxDescent()) / 2); - break; - } - - target.print(g); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MListPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MListPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -/* - * Copyright 1995-2004 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.ActionEvent; -import java.awt.event.ItemEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; - -class MListPeer extends MComponentPeer implements ListPeer { - native void create(MComponentPeer parent); - - void initialize() { - List li = (List)target; - - /* add any items that were already inserted in the target. */ - int nitems = li.countItems(); - for (int i = 0; i < nitems; i++) { - addItem(li.getItem(i), -1); - } - - /* set whether this list should allow multiple selections. */ - setMultipleSelections(li.allowsMultipleSelections()); - - /* make the visible position visible. */ - int index = li.getVisibleIndex(); - if (index >= 0) { - makeVisible(index); - } - - /* select the item if necessary. */ - int sel[] = li.getSelectedIndexes(); - for (int i = 0 ; i < sel.length ; i++) { - select(sel[i]); - } - - /* BugID 4060345 to avoid showing scrollbar in empty List */ - if (nitems == 0) { - addItem(" ", 0); - delItems(0, 0); - } - super.pSetScrollbarBackground(getParent_NoClientCode(li).getBackground()); - - if (!target.isBackgroundSet()) { - target.setBackground(SystemColor.text); - } - if (!target.isForegroundSet()) { - target.setForeground(SystemColor.textText); - } - - super.initialize(); - } - - MListPeer(List target) { - super(target); - } - - /* New method name for 1.1 */ - public void add(String item, int index) { - addItem(item, index); - } - - /* New method name for 1.1 */ - public void removeAll() { - clear(); - } - - /* New method name for 1.1 */ - public void setMultipleMode (boolean b) { - setMultipleSelections(b); - } - - /* New method name for 1.1 */ - public Dimension getPreferredSize(int rows) { - return preferredSize(rows); - } - - /* New method name for 1.1 */ - public Dimension getMinimumSize(int rows) { - return minimumSize(rows); - } - - public void setForeground(Color c) { - pSetInnerForeground(c); - } - - public native void setBackground(Color c); - public native void setMultipleSelections(boolean v); - public native boolean isSelected(int index); - public native void addItem(String item, int index); - public native void delItems(int start, int end); - public native void select(int index); - public native void deselect(int index); - public native void makeVisible(int index); - - public void clear() { - List l = (List)target; - int count = l.countItems(); - if (count > 0) { - delItems(0, count-1); - } - } - - public int[] getSelectedIndexes() { - List l = (List)target; - int len = l.countItems(); - int sel[] = new int[len]; - int nsel = 0; - for (int i = 0 ; i < len ; i++) { - if (isSelected(i)) { - sel[nsel++] = i; - } - } - int selected[] = new int[nsel]; - System.arraycopy(sel, 0, selected, 0, nsel); - return selected; - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void action(int index, final long when, final int modifiers) { - final List list = (List)target; - final int selectIndex = index; - - MToolkit.executeOnEventHandlerThread(list, new Runnable() { - public void run() { - list.select(selectIndex); - postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, - list.getItem(selectIndex), when, - modifiers)); - } - }); - } // action() - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleListChanged(int index) { - final MListPeer listPeer = this; - final List list = (List)target; - final int listIndex = index; - - MToolkit.executeOnEventHandlerThread(list, new Runnable() { - public void run() { - int selected[] = listPeer.getSelectedIndexes(); - boolean isSelected = false; - - for (int i=0; i < selected.length; i++) { - if (listIndex == selected[i]) { - isSelected = true; - break; - } - } - postEvent(new ItemEvent(list, ItemEvent.ITEM_STATE_CHANGED, - Integer.valueOf(listIndex), - isSelected? ItemEvent.SELECTED : ItemEvent.DESELECTED)); - - } - }); - } // handleListChanged() - - public Dimension minimumSize() { - return minimumSize(4); - } - - public Dimension preferredSize(int v) { - return minimumSize(v); - } - - public Dimension minimumSize(int v) { - FontMetrics fm = getFontMetrics(((List)target).getFont()); - return new Dimension(SCROLLBAR + 2*MARGIN + - fm.stringWidth("0123456789abcde"), - ((fm.getHeight()+2*SPACE) * v) + - 2*MARGIN); - } - - public boolean isFocusable() { - return true; - } - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information, selected items, and item offset. - */ - final static int MARGIN = 2; - final static int SPACE = 1; - final static int SCROLLBAR = 16; - int fontHeight; - int fontAscent; - int fontLeading; - int vval; - int hval; - int vmax; - int hmax; - - public void print(Graphics g) { - List l = (List)target; - Dimension d = l.size(); - Color bg = l.getBackground(); - Color fg = l.getForeground(); - int numItems = l.getItemCount(); - FontMetrics fm = getFontMetrics(l.getFont()); - int w, h; - int vvis, hvis, vmin, hmin; - int max = 0; - - for (int i = 0; i < numItems; i++) { - int len = fm.stringWidth(l.getItem(i)); - max = Math.max(max, len); - } - - fontHeight = fm.getHeight(); - fontAscent = fm.getAscent(); - fontLeading = fm.getLeading(); - - hmin = vmin = 0; - - vvis = itemsInWindow(true); - vmax = Math.max(numItems - vvis, 0); - h = d.height - SCROLLBAR; - - if (vmax != 0) { - w = d.width - SCROLLBAR; - hvis = w - ((2 * SPACE) + (2 * MARGIN)); - hmax = Math.max(max - hvis, 0); - } else { - w = d.width; - hvis = w - ((2 * SPACE) + (2 * MARGIN)); - hmax = Math.max(max - hvis, 0); - } - if (hmax == 0) { - h = d.height; - vvis = itemsInWindow(false); - vmax = Math.max(numItems - vvis, 0); - } - if (vmax == 0) { - w = d.width; - hvis = w - ((2 * SPACE) + (2 * MARGIN)); - hmax = Math.max(max - hvis, 0); - } - - hval = 0; - vval = 0; - /* -System.out.println("print List: "+d.width+"x"+d.height+" numItems="+numItems+ -"max="+max+" vsb=("+vmin+".."+vmax+","+vval+","+vvis+ -") hsb=("+hmin+".."+hmax+","+hval+","+hvis+")"); -*/ - - g.setColor(bg); - g.fillRect(0, 0, w, h); - - if (hmax != 0) { - int sbw = d.width - ((vmax == 0) ? 0 : SCROLLBAR); - g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3); - Graphics ng = g.create(); - try { - ng.translate(0, d.height - (SCROLLBAR - 2)); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, - hmin, hmax, hval, hvis, true); - } finally { - ng.dispose(); - } - } - if (vmax != 0) { - int sbh = d.height - ((hmax == 0) ? 0 : SCROLLBAR); - g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1); - Graphics ng = g.create(); - try { - ng.translate(d.width - (SCROLLBAR - 2), 0); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, - vmin, vmax, vval, vvis, false); - } finally { - ng.dispose(); - } - } - - draw3DRect(g, bg, 0, 0, w - 1, h - 1, false); - - if (numItems > 0) { - int n = itemsInWindow(hmax != 0); - int e = Math.min(numItems - 1, (vval + n) - 1); - paintItems(g, bg, fg, vval, e); - } - - target.print(g); - } - - int itemsInWindow(boolean scrollbarVisible) { - Dimension d = target.size(); - int h; - if (scrollbarVisible) { - h = d.height - ((2 * MARGIN) + SCROLLBAR); - } else { - h = d.height - 2*MARGIN; - } - int i = fontHeight - fontLeading; - return h / (i + (2 * SPACE)); - } - - void paintItem(Graphics g, Color bg, Color fg, int index, boolean isSelected) { - List l = (List)target; - Dimension d = l.size(); - int numItems = l.getItemCount(); - Color shadow = bg.darker(); - - if ((index < vval) || (index >= (vval + itemsInWindow(hmax != 0)))) { - return; - } - int w = d.width - ((2 * MARGIN) + ((vmax != 0)? SCROLLBAR : 0)); - int h = (fontHeight - fontLeading); - int htotal = h + (2 * SPACE); - int index2y = MARGIN + (index * htotal) + SPACE; - int y = index2y - (vval * htotal); - int x = MARGIN + SPACE; - Graphics ng = g.create(); - try { - if (index > numItems - 1) { - ng.setColor(bg); - ng.fillRect(x - 2, y - 2, w, h + 4); - return; - } - if (isSelected) { - ng.setColor(shadow); - ng.fillRect(x - 1, y - 1, w - 2, h + 2); - } else { - ng.setColor(bg); - ng.fillRect(x - 1, y - 1, w - 2, h + 2); - } - ng.setColor(bg); - - ng.drawRect(x - 2, y - 2, w - 1, h + 3); - ng.setColor(fg); - String str = (String)l.getItem(index); - ng.clipRect(x, y, w - (2 * SPACE), h); - ng.drawString(str, x - hval, y + fontAscent); - } finally { - ng.dispose(); - } - } - - void paintItems(Graphics g, Color bg, Color fg, int s, int e) { - for (int i = s ; i <= e ; i++) { - paintItem(g, bg, fg, i, false); - } - } - - public boolean handlesWheelScrolling() {return true;} - - public void handleEvent(AWTEvent e) { - if (e.getID() == MouseEvent.MOUSE_WHEEL) { - MouseWheelEvent mwe = (MouseWheelEvent)e; - nativeHandleMouseWheel(mwe.getScrollType(), - mwe.getScrollAmount(), - mwe.getWheelRotation()); - } - else { - super.handleEvent(e); - } - } - - native void nativeHandleMouseWheel(int scrollType, - int scrollAmount, - int wheelRotation); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MMenuBarPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MMenuBarPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import sun.awt.*; - -public class MMenuBarPeer implements MenuBarPeer { - long pData; - MenuBar target; - private X11GraphicsConfig graphicsConfig=null; - - private boolean disposed = false; - - static { - initIDs(); - } - - /** - * Initialize JNI field and method IDs for fields that may be accessed - from C. - */ - private static native void initIDs(); - - native void create(MFramePeer f); - - public MMenuBarPeer(MenuBar target) { - this.target = target; - MFramePeer parent = (MFramePeer) MToolkit.targetToPeer(MMenuItemPeer.getParent_NoClientCode(target)); - create(parent); - } - - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } - - /* - * Subclasses should override disposeImpl() instead of dispose(). Client - * code should always invoke dispose(), never disposeImpl(). - */ - private native void pDispose(); - protected void disposeImpl() { - MToolkit.targetDisposedPeer(target, this); - pDispose(); - } - public final void dispose() { - boolean call_disposeImpl = false; - - if (!disposed) { - synchronized (this) { - if (!disposed) { - disposed = call_disposeImpl = true; - } - } - } - - if (call_disposeImpl) { - disposeImpl(); - } - } - public void addMenu(Menu m) { - } - public void delMenu(int index) { - } - public void addHelpMenu(Menu m) { - } - - static final int GAP = 10; - static final int W_DIFF = (MFramePeer.CROSSHAIR_INSET + 1) * 2; - static final int H_DIFF = MFramePeer.BUTTON_Y + MFramePeer.BUTTON_H; - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more appropriate size and - * color information. - */ - void print(Graphics g) { - MenuBar mb = (MenuBar)target; - Frame f = (Frame)MMenuItemPeer.getParent_NoClientCode(target); - Dimension fd = f.size(); - Insets insets = f.insets(); - - /* Calculate menubar dimension. */ - int width = fd.width; - int height = insets.top; - if (f.getPeer() instanceof MFramePeer) { - MFramePeer fpeer = (MFramePeer)f.getPeer(); - if (fpeer.hasDecorations(MWindowAttributes.AWT_DECOR_BORDER)) { - width -= W_DIFF; - height -= MFramePeer.BUTTON_Y; - } - if (fpeer.hasDecorations(MWindowAttributes.AWT_DECOR_MENU)) { - height -= MFramePeer.BUTTON_H; - } - } - Dimension d = new Dimension(width, height); - - Shape oldClipArea = g.getClip(); - g.clipRect(0, 0, d.width, d.height); - - Color bg = f.getBackground(); - Color fg = f.getForeground(); - Color highlight = bg.brighter(); - Color shadow = bg.darker(); - - // because we'll most likely be drawing on white paper, - // for aesthetic reasons, don't make any part of the outer border - // pure white - if (highlight.equals(Color.white)) { - g.setColor(new Color(230, 230, 230)); - } - else { - g.setColor(highlight); - } - g.drawLine(0, 0, d.width, 0); - g.drawLine(1, 1, d.width - 1, 1); - g.drawLine(0, 0, 0, d.height); - g.drawLine(1, 1, 1, d.height - 1); - g.setColor(shadow); - g.drawLine(d.width, 1, d.width, d.height); - g.drawLine(d.width - 1, 2, d.width - 1, d.height); - g.drawLine(1, d.height, d.width, d.height); - g.drawLine(2, d.height - 1, d.width, d.height - 1); - - int x = GAP; - int nitems = mb.countMenus(); - - Menu helpMenu = target.getHelpMenu(); - - for (int i = 0 ; i < nitems ; i++) { - Menu mn = target.getMenu(i); - String item = mn.getLabel(); - if (item == null) { - item = ""; - } - Font menuFont = mn.getFont(); - g.setFont(menuFont); - FontMetrics menuMetrics = g.getFontMetrics(); - int y = (d.height / 2) + menuMetrics.getMaxDescent(); - int w = menuMetrics.stringWidth(item) + GAP * 2; - - if (x >= d.width) { - break; - } - if (mn.isEnabled()) { - g.setColor(fg); - } - else { - // draw text as grayed out - g.setColor(shadow); - } - - if (helpMenu == mn) { - g.drawString(item, d.width - w + GAP, y); - } - else { - g.drawString(item, x, y); - x += w; - } - } - - g.setClip(oldClipArea); - } - - // Needed for MenuComponentPeer. - public void setFont(Font f) { - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MMenuItemPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MMenuItemPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.ActionEvent; -import sun.awt.AppContext; - -class MMenuItemPeer implements MenuItemPeer { - long pData; - long jniGlobalRef; - boolean isCheckbox = false; - MenuItem target; - boolean nativeCreated = false; - - private boolean disposed = false; - - static { - initIDs(); - } - - /** - * Initialize JNI field and method IDs - */ - private static native void initIDs(); - - native void createMenuItem(MMenuPeer parent); - - void create(MMenuPeer parent) { - if (parent.nativeCreated) { - createMenuItem(parent); - nativeCreated = true; - setEnabled(target.isEnabled()); - } - } - - protected MMenuItemPeer() { - } - - MMenuItemPeer(MenuItem target) { - this.target = target; - MMenuPeer parent = (MMenuPeer) MToolkit.targetToPeer(getParent_NoClientCode(target)); - create(parent); - } - - static native MenuContainer getParent_NoClientCode(MenuComponent menuComponent); - - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } - - public void setEnabled(boolean b) { - if (b) { - enable(); - } else { - disable(); - } - } - - public void setLabel(String label) { - if (!nativeCreated) { - return; - } - pSetLabel(label); - // Fix for bug 4234266 AWT component : MenuItem throw NullPointer exception. - MenuShortcut sc = target.getShortcut(); - setShortcut(sc != null ? sc.toString() : null ); - } - - public void setShortcut(String shortCut) { - if (!nativeCreated) { - return; - } - pSetShortcut(shortCut); - } - - native void pSetLabel(String label); - native void pSetShortcut(String shortCut); - - /** - * DEPRECATED but, for now, called by setEnabled(boolean). - */ - public void enable() { - if (!nativeCreated) { - return; - } - pEnable(); - } - native void pEnable(); - - /** - * DEPRECATED but, for now, called by setEnabled(boolean). - */ - public void disable() { - if (!nativeCreated) { - return; - } - pDisable(); - } - native void pDisable(); - - private void destroyNativeWidgetImpl() { - if (nativeCreated) { - pDispose(); - nativeCreated = false; - } - } - - void destroyNativeWidget() { - // We do not need to synchronize this method because the caller - // always holds the tree lock - - destroyNativeWidgetImpl(); - } - - /* - * Subclasses should override disposeImpl() instead of dispose(). Client - * code should always invoke dispose(), never disposeImpl(). - */ - protected void disposeImpl() { - // Don't call destroyNativeWidget() because on a Menu, this will - // cause a traversal of all the menu's MenuItems. This traversal was - // already done once by java.awt.Menu.removeNotify(). - - destroyNativeWidgetImpl(); - MToolkit.targetDisposedPeer(target, this); - } - public final void dispose() { - boolean call_disposeImpl = false; - - if (!disposed) { - synchronized (this) { - if (!disposed) { - disposed = call_disposeImpl = true; - } - } - } - - if (call_disposeImpl) { - disposeImpl(); - } - } - - native void pDispose(); - - void postEvent(AWTEvent event) { - MToolkit.postEvent(MToolkit.targetToAppContext(target), event); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void action(final long when, final int modifiers) { - - MToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, - target.getActionCommand(), when, - modifiers)); - } - }); - } - - // Needed for MenuComponentPeer. - public void setFont(Font f) { - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MMenuPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MMenuPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright 1995-1999 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; - -public class MMenuPeer extends MMenuItemPeer implements MenuPeer { - native void createMenu(MMenuBarPeer parent); - native void createSubMenu(MMenuPeer parent); - - void create(MMenuPeer parent) { - if (parent.nativeCreated) { - createSubMenu(parent); - nativeCreated = true; - } - } - - protected MMenuPeer() { - } - - public MMenuPeer(Menu target) { - this.target = target; - MenuContainer parent = getParent_NoClientCode(target); - - if (parent instanceof MenuBar) { - MMenuBarPeer mb = (MMenuBarPeer) MToolkit.targetToPeer(parent); - createMenu(mb); - nativeCreated = true; - } else if (parent instanceof Menu) { - MMenuPeer m = (MMenuPeer) MToolkit.targetToPeer(parent); - create(m); - } else { - throw new IllegalArgumentException("unknown menu container class"); - } - } - - public void addSeparator() { - } - public void addItem(MenuItem item) { - } - public void delItem(int index) { - } - - void destroyNativeWidget() { - // We do not need to synchronize this method because the caller - // always holds the tree lock - - if (nativeCreated) { - Menu menu = (Menu) target; - int nitems = menu.getItemCount(); - for (int i = 0 ; i < nitems ; i++) { - MMenuItemPeer mipeer = - (MMenuItemPeer) MToolkit.targetToPeer(menu.getItem(i)); - mipeer.destroyNativeWidget(); - } - super.destroyNativeWidget(); - } - } - native void pDispose(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MMouseDragGestureRecognizer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MMouseDragGestureRecognizer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,233 +0,0 @@ -/* - * Copyright 1998-2003 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 sun.awt.motif; - -import java.awt.Toolkit; -import java.awt.Component; - -import java.awt.Point; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragSource; -import java.awt.dnd.MouseDragGestureRecognizer; -import java.awt.dnd.DragGestureListener; - -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; - -import java.lang.reflect.*; - -import sun.awt.dnd.SunDragSourceContextPeer; - -/** - *

    - * This subclass of MouseDragGestureRecognizer defines a DragGestureRecognizer - * for Mouse based gestures on OSF/Motif. - *

    - * - * @author Laurence P. G. Cable - * - * @see java.awt.dnd.DragGestureListener - * @see java.awt.dnd.DragGestureEvent - * @see java.awt.dnd.DragSource - */ - -class MMouseDragGestureRecognizer extends MouseDragGestureRecognizer { - - private static final long serialVersionUID = -841711780352520383L; - - /* - * constant for number of pixels hysterisis before drag is determined - * to have started - */ - - protected static int motionThreshold; - - - protected static final int ButtonMask = InputEvent.BUTTON1_DOWN_MASK | - InputEvent.BUTTON2_DOWN_MASK | - InputEvent.BUTTON3_DOWN_MASK; - - /** - * construct a new MMouseDragGestureRecognizer - * - * @param ds The DragSource for the Component c - * @param c The Component to observe - * @param act The actions permitted for this Drag - * @param dgl The DragGestureRecognizer to notify when a gesture is detected - * - */ - - protected MMouseDragGestureRecognizer(DragSource ds, Component c, int act, DragGestureListener dgl) { - super(ds, c, act, dgl); - } - - /** - * construct a new MMouseDragGestureRecognizer - * - * @param ds The DragSource for the Component c - * @param c The Component to observe - * @param act The actions permitted for this Drag - */ - - protected MMouseDragGestureRecognizer(DragSource ds, Component c, int act) { - this(ds, c, act, null); - } - - /** - * construct a new MMouseDragGestureRecognizer - * - * @param ds The DragSource for the Component c - * @param c The Component to observe - */ - - protected MMouseDragGestureRecognizer(DragSource ds, Component c) { - this(ds, c, DnDConstants.ACTION_NONE); - } - - /** - * construct a new MMouseDragGestureRecognizer - * - * @param ds The DragSource for the Component c - */ - - protected MMouseDragGestureRecognizer(DragSource ds) { - this(ds, null); - } - - /** - * determine the drop action from the event - */ - - protected int mapDragOperationFromModifiers(MouseEvent e) { - int mods = e.getModifiersEx(); - int btns = mods & ButtonMask; - - // Do not allow right mouse button drag since Motif DnD does not - // terminate drag operation on right mouse button release. - if (!(btns == InputEvent.BUTTON1_DOWN_MASK || - btns == InputEvent.BUTTON2_DOWN_MASK)) { - return DnDConstants.ACTION_NONE; - } - - return - SunDragSourceContextPeer.convertModifiersToDropAction(mods, - getSourceActions()); - } - - /** - * Invoked when the mouse has been clicked on a component. - */ - - public void mouseClicked(MouseEvent e) { - // do nothing - } - - /** - * Invoked when a mouse button has been pressed on a component. - */ - - public void mousePressed(MouseEvent e) { - events.clear(); - - if (mapDragOperationFromModifiers(e) != DnDConstants.ACTION_NONE) { - try { - motionThreshold = DragSource.getDragThreshold(); - } catch (Exception exc) { - motionThreshold = 5; - } - appendEvent(e); - } - } - - /** - * Invoked when a mouse button has been released on a component. - */ - - public void mouseReleased(MouseEvent e) { - events.clear(); - } - - /** - * Invoked when the mouse enters a component. - */ - - public void mouseEntered(MouseEvent e) { - events.clear(); - } - - /** - * Invoked when the mouse exits a component. - */ - - public void mouseExited(MouseEvent e) { - if (!events.isEmpty()) { // gesture pending - int dragAction = mapDragOperationFromModifiers(e); - - if (dragAction == DnDConstants.ACTION_NONE) { - events.clear(); - } - } - } - - /** - * Invoked when a mouse button is pressed on a component. - */ - - public void mouseDragged(MouseEvent e) { - if (!events.isEmpty()) { // gesture pending - int dop = mapDragOperationFromModifiers(e); - - - if (dop == DnDConstants.ACTION_NONE) { - return; - } - - MouseEvent trigger = (MouseEvent)events.get(0); - - Point origin = trigger.getPoint(); - Point current = e.getPoint(); - - int dx = Math.abs(origin.x - current.x); - int dy = Math.abs(origin.y - current.y); - - if (dx > motionThreshold || dy > motionThreshold) { - fireDragGestureRecognized(dop, ((MouseEvent)getTriggerEvent()).getPoint()); - } else - appendEvent(e); - } - } - - /** - * Invoked when the mouse button has been moved on a component - * (with no buttons no down). - */ - - public void mouseMoved(MouseEvent e) { - // do nothing - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MPanelPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MPanelPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; - -import sun.awt.SunGraphicsCallback; - -class MPanelPeer extends MCanvasPeer implements PanelPeer { - - MPanelPeer() {} - - MPanelPeer(Component target) { - super(target); - } - - MPanelPeer(Component target, Object arg) { - super(target, arg); - } - - public Insets getInsets() { - return new Insets(0, 0, 0, 0); - } - - public void paint(Graphics g) { - super.paint(g); - SunGraphicsCallback.PaintHeavyweightComponentsCallback.getInstance(). - runComponents(((Container)target).getComponents(), g, - SunGraphicsCallback.LIGHTWEIGHTS | - SunGraphicsCallback.HEAVYWEIGHTS); - } - public void print(Graphics g) { - super.print(g); - SunGraphicsCallback.PrintHeavyweightComponentsCallback.getInstance(). - runComponents(((Container)target).getComponents(), g, - SunGraphicsCallback.LIGHTWEIGHTS | - SunGraphicsCallback.HEAVYWEIGHTS); - } - - public void setBackground(Color c) { - Component comp; - int i; - - Container cont = (Container) target; - synchronized(target.getTreeLock()) { - int n = cont.getComponentCount(); - for(i=0; i < n; i++) { - comp = cont.getComponent(i); - MComponentPeer peer = (MComponentPeer) MToolkit.targetToPeer(comp); - if (peer != null) { - Color color = comp.getBackground(); - if (color == null || color.equals(c)) { - peer.setBackground(c); - peer.pSetBackground(c); - } - if ((comp instanceof java.awt.List) || - (comp instanceof java.awt.TextArea) || - (comp instanceof java.awt.ScrollPane)) { - peer.pSetScrollbarBackground(c); - } - } - } - } - pSetBackground(c); - } - - public void setForeground(Color c) { - Component comp; - int i; - - Container cont = (Container) target; - synchronized(target.getTreeLock()) { - int n = cont.getComponentCount(); - for(i=0; i < n; i++) { - comp = cont.getComponent(i); - MComponentPeer peer = (MComponentPeer) MToolkit.targetToPeer(comp); - if (peer != null) { - Color color = comp.getForeground(); - if (color == null || color.equals(c)) { - peer.setForeground(c); - peer.pSetForeground(c); - } - if ((comp instanceof java.awt.List) || - (comp instanceof java.awt.TextArea) || - (comp instanceof java.awt.ScrollPane)) { - peer.pSetInnerForeground(c); - } - } - } - } - pSetForeground(c); - } - - /** - * DEPRECATED: Replaced by getInsets(). - */ - public Insets insets() { - return getInsets(); - } - - /** - * Recursive method that handles the propagation of the displayChanged - * event into the entire hierarchy of peers. - * Unlike on win32, on X we don't worry about handling on-the-fly - * display settings changes, only windows being dragged across Xinerama - * screens. Thus, we only need to tell MCanvasPeers, not all - * MComponentPeers. - */ - private void recursiveDisplayChanged(Component c, int screenNum) { - if (c instanceof Container) { - Component children[] = ((Container)c).getComponents(); - for (int i = 0; i < children.length; ++i) { - recursiveDisplayChanged(children[i], screenNum); - } - } - ComponentPeer peer = c.getPeer(); - if (peer != null && peer instanceof MCanvasPeer) { - MCanvasPeer mPeer = (MCanvasPeer)peer; - mPeer.displayChanged(screenNum); - } - } - - /* - * Often up-called from a MWindowPeer instance. - * Calls displayChanged() on all child canvas' peers. - * Recurses into Container children to ensure all canvases - * get the message. - */ - public void displayChanged(int screenNum) { - // Don't do super call because MWindowPeer has already updated its GC - - Component children[] = ((Container)target).getComponents(); - - for (int i = 0; i < children.length; i++) { - recursiveDisplayChanged(children[i], screenNum); - } - } - - protected boolean shouldFocusOnClick() { - // Return false if this container has children so in that case it won't - // be focused. Return true otherwise. - return ((Container)target).getComponentCount() == 0; - } - - private native void pEnsureIndex(ComponentPeer child, int index); - private native void pRestack(); - - private int restack(Container cont, int ind) { - for (int i = 0; i < cont.getComponentCount(); i++) { - Component comp = cont.getComponent(i); - if (!comp.isLightweight()) { - if (comp.getPeer() != null) { - pEnsureIndex(comp.getPeer(), ind++); - } - } - if (comp.isLightweight() && comp instanceof Container) { - ind = restack((Container)comp, ind); - } - } - return ind; - } - - /** - * @see java.awt.peer.ContainerPeer#restack - */ - public void restack() { - Container cont = (Container)target; - restack(cont, 0); - pRestack(); - } - - /** - * @see java.awt.peer.ContainerPeer#isRestackSupported - */ - public boolean isRestackSupported() { - return true; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MPopupMenuPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MPopupMenuPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 1996-1998 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; - -public class MPopupMenuPeer extends MMenuPeer implements PopupMenuPeer { - - static { - initIDs(); - } - - /* initialize the methodIDs of methods that may be accessed from C */ - private native static void initIDs(); - - native void createMenu(MComponentPeer parent); - - void createPopupMenu() { - if (MMenuItemPeer.getParent_NoClientCode(target) instanceof Component) { - Component parent = (Component)getParent_NoClientCode(target); - MComponentPeer parentPeer = (MComponentPeer) MToolkit.targetToPeer(parent); - if (parentPeer == null) { - // because the menu isn't a component (sigh) we first have to wait - // for a failure to map the peer which should only happen for a - // lightweight container, then find the actual native parent from - // that component. - parent = MToolkit.getNativeContainer(parent); - parentPeer = (MComponentPeer) MToolkit.targetToPeer(parent); - } - createMenu(parentPeer); - nativeCreated = true; - createItems((Menu)target); - - } else { - throw new IllegalArgumentException("illegal popup menu container class"); - } - } - - void createItems(Menu target) { - int nitems = target.getItemCount(); - MMenuPeer parent = (MMenuPeer)MToolkit.targetToPeer(target); - for (int i = 0 ; i < nitems ; i++) { - MenuItem mitem = target.getItem(i); - MMenuItemPeer mipeer = (MMenuItemPeer)MToolkit.targetToPeer(mitem); - mipeer.create(parent); - if (mitem instanceof Menu) { - createItems((Menu)mitem); - } - } - } - - public MPopupMenuPeer(PopupMenu target) { - // Do NOT instantiate native widget until just before showing the - // menu, else right mouse click will cause display to lock up - // (because of passive grab in Motif) - // - this.target = target; - } - - native void pShow(Event evt, int x, int y, MComponentPeer origin); - - public void show(Event evt) { - - if (!nativeCreated) - createPopupMenu(); - - Component origin = (Component)evt.target; - MComponentPeer peer = (MComponentPeer) MToolkit.targetToPeer(origin); - int x = evt.x; - int y = evt.y; - if (peer == null) { - // A failure to map the peer should only happen for a - // lightweight component, then find the actual native parent from - // that component. The event coorinates are going to have to be - Component nativeOrigin = MToolkit.getNativeContainer(origin); - peer = (MComponentPeer) MToolkit.targetToPeer(nativeOrigin); - - // remove the event coordinates - for (Component c = origin; c != nativeOrigin; - c = MComponentPeer.getParent_NoClientCode(c)) { - Point p = c.getLocation(); - x += p.x; - y += p.y; - } - } - pShow(evt, x, y, peer); - } - - /** - * This is the callback function called on the Motif thread by - * Popup_popdownCB(Widget, XtPointer, XtPointer) in awt_PopupMenu.c. - */ - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - private void destroyNativeWidgetAfterGettingTreeLock() { - - MToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - - Object treeLock = new Button().getTreeLock(); - synchronized (treeLock) { - destroyNativeWidget(); - } - } - }); - } - - native void pDispose(); -} // class MPopupMenuPeer diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MRobotPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MRobotPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright 1999-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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.security.*; -import sun.awt.X11GraphicsConfig; - -class MRobotPeer implements RobotPeer { - private X11GraphicsConfig xgc = null; - /* - * native implementation uses some static shared data (pipes, processes) - * so use a class lock to synchronize native method calls - */ - static Object robotLock = new Object(); - - MRobotPeer(GraphicsConfiguration gc) { - this.xgc = (X11GraphicsConfig)gc; - setup(); - } - - public void dispose() { - // does nothing - } - - public void mouseMove(int x, int y) { - mouseMoveImpl(xgc, x, y); - } - - public void mousePress(int buttons) { - mousePressImpl(buttons); - } - - public void mouseRelease(int buttons) { - mouseReleaseImpl(buttons); - } - - public void mouseWheel(int wheelAmt) { - mouseWheelImpl(wheelAmt); - } - - public void keyPress(int keycode) { - keyPressImpl(keycode); - } - - public void keyRelease(int keycode) { - keyReleaseImpl(keycode); - } - - public int getRGBPixel(int x, int y) { - int pixelArray[] = new int[1]; - getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray); - return pixelArray[0]; - } - - public int [] getRGBPixels(Rectangle bounds) { - int pixelArray[] = new int[bounds.width*bounds.height]; - getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height, pixelArray); - return pixelArray; - } - - private static native synchronized void setup(); - - private static native synchronized void mouseMoveImpl(X11GraphicsConfig xgc, int x, int y); - private static native synchronized void mousePressImpl(int buttons); - private static native synchronized void mouseReleaseImpl(int buttons); - private static native synchronized void mouseWheelImpl(int wheelAmt); - - private static native synchronized void keyPressImpl(int keycode); - private static native synchronized void keyReleaseImpl(int keycode); - - private static native synchronized void getRGBPixelsImpl(X11GraphicsConfig xgc, int x, int y, int width, int height, int pixelArray[]); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,411 +0,0 @@ -/* - * Copyright 1996-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.event.AdjustmentEvent; -import java.awt.peer.ScrollPanePeer; - -import java.util.logging.*; - -import sun.awt.PeerEvent; - -class MScrollPanePeer extends MPanelPeer implements ScrollPanePeer { - - private static final Logger log = Logger.getLogger("sun.awt.motif.MScrollPanePeer"); - - final static int UNIT_INCREMENT = 0; - final static int BLOCK_INCREMENT = 1; - - boolean ignore; - - native void create(MComponentPeer parent); - - static { - initIDs(); - } - - /** - * Initialize JNI field and method IDs - */ - private static native void initIDs(); - - MScrollPanePeer(Component target) { - init(target); - scrollPaneInit(); - } - - MScrollPanePeer(Component target, Object arg) { - init(target, arg); - scrollPaneInit(); - } - - void scrollPaneInit() { - ignore = false; - ScrollPane sp = (ScrollPane)target; - Adjustable vadj, hadj; - if ((vadj = sp.getVAdjustable()) != null) { - pSetIncrement(Adjustable.VERTICAL, UNIT_INCREMENT, vadj.getUnitIncrement()); - } - if ((hadj = sp.getHAdjustable()) != null) { - pSetIncrement(Adjustable.HORIZONTAL, UNIT_INCREMENT, hadj.getUnitIncrement()); - } - super.pSetScrollbarBackground(sp.getBackground()); - } - - public void setScrollChild(MComponentPeer child) { - pSetScrollChild(child); - } - - public void setBackground(Color c) { - super.setBackground(c); - pSetScrollbarBackground(c); - } - - public void setForeground(Color c) { - super.setForeground(c); - pSetInnerForeground(c); - } - - native void pSetScrollChild(MComponentPeer child); - native void pSetIncrement(int orient, int type, int incr); - native int pGetScrollbarSpace(int orient); - native int pGetBlockIncrement(int orient); - native Insets pInsets(int w, int h, int childw, int childh); - native int pGetShadow(); - - public int getHScrollbarHeight() { - ScrollPane sp = (ScrollPane)target; - if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) { - return 0; - } else { - return pGetScrollbarSpace(Adjustable.HORIZONTAL); - } - } - - public int getVScrollbarWidth() { - ScrollPane sp = (ScrollPane)target; - if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) { - return 0; - } else { - return pGetScrollbarSpace(Adjustable.VERTICAL); - } - } - - public Insets insets() { - ScrollPane sp = (ScrollPane)target; - Dimension d = sp.size(); - Dimension cd; - Component c = getScrollChild(); - if (c != null) { - cd = c.size(); - } else { - cd = new Dimension(0, 0); - } - return pInsets(d.width, d.height, cd.width, cd.height); - } - - public void setUnitIncrement(Adjustable adj, int u) { - ScrollPane sp = (ScrollPane)target; - if (sp.getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) { - pSetIncrement(adj.getOrientation(), UNIT_INCREMENT, u); - } - } - - public void setValue(Adjustable adj, int v) { - if (! ignore) { - Point p; - Component c = getScrollChild(); - if (c == null) { - return; - } - p = c.getLocation(); - switch(adj.getOrientation()) { - case Adjustable.VERTICAL: - setScrollPosition(-(p.x), v); - break; - case Adjustable.HORIZONTAL: - setScrollPosition(v, -(p.y)); - break; - } - } - } - - public native void setScrollPosition(int x, int y); - - public void childResized(int w, int h) { - // REMIND AIM: May need to revisit this... - if (((ScrollPane)target).getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) { - ScrollPane sp = (ScrollPane)target; - Adjustable vAdj = sp.getVAdjustable(); - Adjustable hAdj = sp.getHAdjustable(); - pSetIncrement(Scrollbar.VERTICAL, UNIT_INCREMENT, vAdj.getUnitIncrement()); - pSetIncrement(Scrollbar.HORIZONTAL, UNIT_INCREMENT, hAdj.getUnitIncrement()); - pSetIncrement(Scrollbar.VERTICAL, BLOCK_INCREMENT, vAdj.getBlockIncrement()); - pSetIncrement(Scrollbar.HORIZONTAL, BLOCK_INCREMENT, hAdj.getBlockIncrement()); - } - - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - private void postScrollEvent(int orient, int type, - int pos, boolean isAdjusting) - { - Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting); - MToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor)); - } - - /** - * This is used to change the adjustable on dispatch thread to - * represent a change made in the native scrollbar. Since the - * change was reflected immediately at the native level, - * notification from the adjustable is temporarily ignored. - */ - class ScrollEvent extends PeerEvent { - ScrollEvent(Object source, Runnable runnable) { - super(source, runnable, 0L); - } - - public PeerEvent coalesceEvents(PeerEvent newEvent) { - if (log.isLoggable(Level.FINEST)) { - log.log(Level.FINEST, "ScrollEvent coalesced " + newEvent); - } - if (newEvent instanceof ScrollEvent) { - return newEvent; - } - return null; - } - } - - native void setTypedValue(ScrollPaneAdjustable adjustable, int value, int type); - - /** - * Runnable for the ScrollEvent that performs the adjustment. - */ - class Adjustor implements Runnable { - int orient; // selects scrollbar - int type; // adjustment type - int pos; // new position (only used for absolute) - boolean isAdjusting; // isAdjusting status - - Adjustor(int orient, int type, int pos, boolean isAdjusting) { - this.orient = orient; - this.type = type; - this.pos = pos; - this.isAdjusting = isAdjusting; - } - - public void run() { - ScrollPane sp = (ScrollPane)MScrollPanePeer.this.target; - ScrollPaneAdjustable adj = null; - - // ScrollPaneAdjustable made public in 1.4, but - // get[HV]Adjustable can't be declared to return - // ScrollPaneAdjustable because it would break backward - // compatibility -- hence the cast - - if (orient == Adjustable.VERTICAL) { - adj = (ScrollPaneAdjustable)sp.getVAdjustable(); - } else if (orient == Adjustable.HORIZONTAL) { - adj = (ScrollPaneAdjustable)sp.getHAdjustable(); - } else { - if (log.isLoggable(Level.FINE)) { - log.log(Level.FINE, "Assertion failed: unknown orient"); - } - } - - if (adj == null) { - return; - } - - int newpos = adj.getValue(); - switch (type) { - case AdjustmentEvent.UNIT_DECREMENT: - newpos -= adj.getUnitIncrement(); - break; - case AdjustmentEvent.UNIT_INCREMENT: - newpos += adj.getUnitIncrement(); - break; - case AdjustmentEvent.BLOCK_DECREMENT: - newpos -= adj.getBlockIncrement(); - break; - case AdjustmentEvent.BLOCK_INCREMENT: - newpos += adj.getBlockIncrement(); - break; - case AdjustmentEvent.TRACK: - newpos = this.pos; - break; - default: - if (log.isLoggable(Level.FINE)) { - log.log(Level.FINE, "Assertion failed: unknown type"); - } - return; - } - - // keep scroll position in acceptable range - newpos = Math.max(adj.getMinimum(), newpos); - newpos = Math.min(adj.getMaximum(), newpos); - - // set value; this will synchronously fire an AdjustmentEvent - try { - MScrollPanePeer.this.ignore = true; - adj.setValueIsAdjusting(isAdjusting); - - // Fix for 4075484 - consider type information when creating AdjustmentEvent - // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK - // Instead, we call private method setTypedValue of ScrollPaneAdjustable. - // Because ScrollPaneAdjustable is in another package we should call it through native code. - setTypedValue(adj, newpos, type); - } finally { - MScrollPanePeer.this.ignore = false; - } - } - } // class Adjustor - - - private Component getScrollChild() { - ScrollPane sp = (ScrollPane)target; - Component child = null; - try { - child = sp.getComponent(0); - } catch (ArrayIndexOutOfBoundsException e) { - // do nothing. in this case we return null - } - return child; - } - - final static int MARGIN = 1; - final static int SCROLLBAR = 16; - int hsbSpace; - int vsbSpace; - int vval; - int hval; - int vmax; - int hmax; - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information. - */ - public void print(Graphics g) { - ScrollPane sp = (ScrollPane)target; - Dimension d = sp.size(); - Color bg = sp.getBackground(); - Color fg = sp.getForeground(); - Point p = sp.getScrollPosition(); - Component c = getScrollChild(); - Dimension cd; - if (c != null) { - cd = c.size(); - } else { - cd = new Dimension(0, 0); - } - int sbDisplay = sp.getScrollbarDisplayPolicy(); - int vvis, hvis, vmin, hmin, vmax, hmax, vval, hval; - - switch (sbDisplay) { - case ScrollPane.SCROLLBARS_NEVER: - hsbSpace = vsbSpace = 0; - break; - case ScrollPane.SCROLLBARS_ALWAYS: - hsbSpace = vsbSpace = SCROLLBAR; - break; - case ScrollPane.SCROLLBARS_AS_NEEDED: - hsbSpace = (cd.width <= (d.width - 2*MARGIN)? 0 : SCROLLBAR); - vsbSpace = (cd.height <= (d.height - 2*MARGIN)? 0 : SCROLLBAR); - - if (hsbSpace == 0 && vsbSpace != 0) { - hsbSpace = (cd.width <= (d.width - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR); - } - if (vsbSpace == 0 && hsbSpace != 0) { - vsbSpace = (cd.height <= (d.height - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR); - } - } - - vvis = hvis = vmin = hmin = vmax = hmax = vval = hval = 0; - - if (vsbSpace > 0) { - vmin = 0; - vvis = d.height - (2*MARGIN) - hsbSpace; - vmax = Math.max(cd.height - vvis, 0); - vval = p.y; - } - if (hsbSpace > 0) { - hmin = 0; - hvis = d.width - (2*MARGIN) - vsbSpace; - hmax = Math.max(cd.width - hvis, 0); - hval = p.x; - } - - // need to be careful to add the margins back in here because - // we're drawing the margin border, after all! - int w = d.width - vsbSpace; - int h = d.height - hsbSpace; - - g.setColor(bg); - g.fillRect(0, 0, d.width, d.height); - - if (hsbSpace > 0) { - int sbw = d.width - vsbSpace; - g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3); - Graphics ng = g.create(); - try { - ng.translate(0, d.height - (SCROLLBAR - 2)); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, - hmin, hmax, hval, hvis, true); - } finally { - ng.dispose(); - } - } - if (vsbSpace > 0) { - int sbh = d.height - hsbSpace; - g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1); - Graphics ng = g.create(); - try { - ng.translate(d.width - (SCROLLBAR - 2), 0); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, - vmin, vmax, vval, vvis, false); - } finally { - ng.dispose(); - } - } - - draw3DRect(g, bg, 0, 0, w - 1, h - 1, false); - - target.print(g); - sp.printComponents(g); - } - - /** - * @see ContainerPeer#restack - */ - public void restack() { - // Since ScrollPane can only have one child its restacking does nothing. - // Also, it is dangerous, since SP child is actually not a child of SP widget - // but the child of SP content widget. - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MScrollbarPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MScrollbarPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - * Copyright 1995-2002 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.AdjustmentEvent; - -class MScrollbarPeer extends MComponentPeer implements ScrollbarPeer { - static { - initIDs(); - } - - private boolean inUpCall = false; - - native void create(MComponentPeer parent); - - MScrollbarPeer(Scrollbar target) { - super(target); - } - - // Initialize JNI field and method IDs - private static native void initIDs(); - - public native void pSetValues(int value, int visible, int minimum, int maximum); - public native void setLineIncrement(int l); - public native void setPageIncrement(int l); - - /** - * Returns default size of Motif scrollbar on the platform - * Currently uses hardcoded values - */ - int getDefaultDimension() { - if (System.getProperty("os.name").equals("Linux")) { - return 15; - } else { - return 19; - } - } - - public Dimension getMinimumSize() { - if (((Scrollbar)target).getOrientation() == Scrollbar.VERTICAL) { - return new Dimension(getDefaultDimension(), 50); - } else { - return new Dimension(50, getDefaultDimension()); - } - } - - // NOTE: Callback methods are called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - - private void postAdjustmentEvent(final int type, final int value, - final boolean isAdjusting) - { - final Scrollbar sb = (Scrollbar)target; - MToolkit.executeOnEventHandlerThread(sb, new Runnable() { - public void run() { - inUpCall = true; - sb.setValueIsAdjusting(isAdjusting); - sb.setValue(value); - postEvent(new AdjustmentEvent(sb, - AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, - type, value, isAdjusting)); - inUpCall = false; - } - }); - } - - void lineUp(int value) { - postAdjustmentEvent(AdjustmentEvent.UNIT_DECREMENT, value, false); - } - - void lineDown(int value) { - postAdjustmentEvent(AdjustmentEvent.UNIT_INCREMENT, value, false); - } - - void pageUp(int value) { - postAdjustmentEvent(AdjustmentEvent.BLOCK_DECREMENT, value, false); - } - - void pageDown(int value) { - postAdjustmentEvent(AdjustmentEvent.BLOCK_INCREMENT, value, false); - } - - // SB_TOP/BOTTOM are mapped to tracking - void warp(int value) { - postAdjustmentEvent(AdjustmentEvent.TRACK, value, false); - } - - private boolean dragInProgress = false; - - void drag(final int value) { - if (!dragInProgress) { - dragInProgress = true; - } - postAdjustmentEvent(AdjustmentEvent.TRACK, value, true); - } - - void dragEnd(final int value) { - final Scrollbar sb = (Scrollbar)target; - - if (!dragInProgress) { - return; - } - - dragInProgress = false; - MToolkit.executeOnEventHandlerThread(sb, new Runnable() { - public void run() { - // NB: notification only, no sb.setValue() - // last TRACK event will have done it already - inUpCall = true; - sb.setValueIsAdjusting(false); - postEvent(new AdjustmentEvent(sb, - AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, - AdjustmentEvent.TRACK, value, false)); - inUpCall = false; - } - }); - } - - /** - * Set the value of the slider in the ScrollBar. - */ - public void setValues(int value, int visible, int minimum, int maximum) { - // Fix for BugTraq ID 4048060. Prevent unnecessary redrawing - // of the slider, when the slider is already in the correct - // position. Since the ScrollBar widget now receives the - // ButtonRelease X event before the Java Adjustor event is - // handled, the slider is already in the correct position and - // does not need to be set again and redrawn, when processing - // the Adjustor event. - if (!inUpCall) { - pSetValues(value, visible, minimum, maximum); - } - } - - public void print(Graphics g) { - Scrollbar sb = (Scrollbar)target; - Dimension d = sb.size(); - Color bg = sb.getBackground(); - - boolean horiz = (sb.getOrientation() == Scrollbar.HORIZONTAL); - - drawScrollbar(g, bg, horiz? d.height : d.width, - horiz? d.width : d.height, - sb.getMinimum(), sb.getMaximum(), - sb.getValue(), sb.getVisible(), - horiz); - - target.print(g); - } - - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - - protected boolean shouldFocusOnClick() { - // Changed in 1.4 - scroll bars are made focusable by mouse clicks. - return true; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MTextAreaPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MTextAreaPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,555 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.TextEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.datatransfer.*; -import java.io.BufferedReader; -import java.io.StringReader; -import java.io.IOException; -import java.util.Vector; -import java.awt.im.InputMethodRequests; - - -public class MTextAreaPeer extends MComponentPeer implements TextAreaPeer { - native void pCreate(MComponentPeer parent); - - private boolean firstChangeSkipped; - - /** - * Initialize JNI field and method IDs - */ - private static native void initIDs(); - - static { - initIDs(); - } - - void create(MComponentPeer parent) { - firstChangeSkipped = false; - pCreate(parent); - } - - void initialize() { - int start, end; - - TextArea txt = (TextArea)target; - String text; - - if ((text = txt.getText()) != null) { - setText(text); - } - - start = txt.getSelectionStart(); - end = txt.getSelectionEnd(); - - if (end > start) { - select(start, end); - } else { - setCaretPosition(start); - } - - super.pSetScrollbarBackground(getParent_NoClientCode(target).getBackground()); - - if (!target.isBackgroundSet()) { - // This is a way to set the background color of the TextArea - // without calling setBackground - go through native C code - setTargetBackground(SystemColor.text); - } - if (!target.isForegroundSet()) { - target.setForeground(SystemColor.textText); - } - - setEditable(txt.isEditable()); - -// oldSelectionStart = -1; // accessibility support -// oldSelectionEnd = -1; // accessibility support - - super.initialize(); - } - - public MTextAreaPeer(TextArea target) { - super(target); - } - - public void setEditable(boolean editable) { - pSetEditable(editable); - - /* 4136955 - Calling setBackground() here works around an Xt - * bug by forcing Xt to flush an internal widget cache - */ - setBackground(target.getBackground()); - } - public void setBackground(Color c) { - setTextBackground(c); - } - public void setForeground(Color c) { - pSetInnerForeground(c); - } - - native int getExtraWidth(); - native int getExtraHeight(); - public native void setTextBackground(Color c); - public native void pSetEditable(boolean e); - public native void select(int selStart, int selEnd); - public native int getSelectionStart(); - public native int getSelectionEnd(); - public native void setText(String txt); - public native String getText(); - public native void insert(String txt, int pos); - public native void replaceRange(String txt, int start, int end); - public native void setFont(Font f); - public native void setCaretPosition(int pos); - public native int getCaretPosition(); - public native void pSetCursor(Cursor c); - native void pShow2(); - native void pMakeCursorVisible(); - - - public Dimension getMinimumSize() { - return getMinimumSize(10, 60); - } - public Dimension getPreferredSize(int rows, int cols) { - return getMinimumSize(rows, cols); - } - public Dimension getMinimumSize(int rows, int cols) { - FontMetrics fm = getFontMetrics(target.getFont()); - - /* Calculate proper size for text area plus scrollbars. - * - Motif allows NO leading in its text areas ... - * - extra width and height counts everything outside the - * usable text space. - * (bug 4103248, 4120310): - * - Motif uses maxAscent + maxDescent, not ascent + descent. - */ - int colWidth = fm.charWidth('0'); - int rowHeight = fm.getMaxAscent() + fm.getMaxDescent(); - return new Dimension(cols * colWidth + getExtraWidth(), - rows * rowHeight + getExtraHeight()); - } - public boolean isFocusable() { - return true; - } - - // Called from native widget when paste key is pressed and we - // already own the selection (prevents Motif from hanging while - // waiting for the selection) - // - public void pasteFromClipboard() { - Clipboard clipboard = target.getToolkit().getSystemClipboard(); - - Transferable content = clipboard.getContents(this); - if (content != null) { - try { - String data = (String)(content.getTransferData(DataFlavor.stringFlavor)); - // fix for 4401853: to clear TextArea selection if null is pasted - data = (data == null ? "" : data); - replaceRange(data, getSelectionStart(), getSelectionEnd()); - - } catch (Exception e) { - } - } - } - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information, the top/left text offsets, and selected text. - */ - static final int MARGIN = 2; - static final int BORDER = 1; - static final int SCROLLBAR = 16; - int fontHeight; - int fontAscent; - int fontLeading; - int topLine = 0; - int numLines = 0; - int textLength = 0; - Vector lines; - int selStart = 0; - int selEnd = 0; - int movedRight = 0; - - // the following vars are assigned in print() method - transient boolean hscrollbar; - transient boolean vscrollbar; - - public void print(Graphics g) { - TextArea area = (TextArea)target; - Dimension d = area.size(); - Color bg = area.getBackground(); - Color fg = area.getForeground(); - FontMetrics fm = getFontMetrics(area.getFont()); - int vmin, vmax, vval, vvis; - int hmin, hmax, hval, hvis; - int max = 0; - - /* - Doesn't work right yet. - selStart = area.getSelectionStart(); - selEnd = area.getSelectionEnd(); - */ - - // Figure out number of lines and max line length - String text = area.getText(); - textLength = text.length(); - BufferedReader is = new BufferedReader(new StringReader(text)); - String line; - int pos = 0; - lines = new Vector(); - int sv = ((TextArea)target).getScrollbarVisibility(); - vscrollbar = (sv == TextArea.SCROLLBARS_BOTH || - sv == TextArea.SCROLLBARS_VERTICAL_ONLY); - hscrollbar = (sv == TextArea.SCROLLBARS_BOTH || - sv == TextArea.SCROLLBARS_HORIZONTAL_ONLY); - boolean wrap = !hscrollbar; - int w = d.width - (vscrollbar ? SCROLLBAR : 0); - int h = d.height - (hscrollbar ? SCROLLBAR : 0); - - try { - numLines = 0; - while((line = is.readLine()) != null) { - int len = fm.stringWidth(line); - if (len > w && wrap) { - // need to do line wrapping - int start = 0; - int end = 0; - int string_length = line.length(); - while (true) { - int line_width = 0; - end = start + 1; // at least one character per line - while (end < string_length) { - char c = line.charAt(end); - int cw = fm.charWidth(c); - if (line_width + cw + 10 > w) // +10? - break; - line_width += cw; - end++; - } - // form a line from start to end (not including end) - String substr = line.substring(start, end); - // System.out.println("wrap line: " + substr); - TextLine tline = new TextLine(); - tline.text = substr; - tline.pos = pos + start; - lines.addElement(tline); - start = end; - max = Math.max(max, len); - numLines ++; - if (end == string_length) { - // we have processed the whole string - pos += line.length() + 1; // +1 for the ending \n ? - break; - } - } - } else { - TextLine tline = new TextLine(); - tline.text = line; - tline.pos = pos; - lines.addElement(tline); - pos += line.length() + 1; - - max = Math.max(max, len); - numLines++; - } - } - is.close(); - - } catch (IOException e) { - } - - - fontHeight = fm.getHeight(); - fontAscent = fm.getAscent(); - fontLeading = fm.getLeading(); - - hmin = vmin = 0; - - vvis = linesInWindow(true); - vmax = Math.max(numLines - vvis, 0); - vval = 0; - - hvis = w - (2 * MARGIN); - hmax = Math.max(max - hvis, 0); - hval = 0; - - g.setColor(bg); - g.fillRect(BORDER, BORDER, w, h); - if (vscrollbar) - { - int sbh = d.height - (hscrollbar ? SCROLLBAR : 0); - g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1); - Graphics ng = g.create(); - try { - ng.translate(d.width - (SCROLLBAR - 2), 0); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, - vmin, vmax, vval, vvis, false); - } finally { - ng.dispose(); - } - } - if (hscrollbar) - { - int sbw = d.width - (vscrollbar ? SCROLLBAR : 0); - g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3); - Graphics ng = g.create(); - try { - ng.translate(0, d.height - (SCROLLBAR - 2)); - drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, - hmin, hmax, hval, hvis, true); - } finally { - ng.dispose(); - } - } - - draw3DRect(g, bg, 0, 0, w - 1, h - 1, false); - - if (text != null) { - int l = linesInWindow(true); - h = d.height - ((2 * MARGIN) + SCROLLBAR); - int e = Math.min(numLines - 1, (topLine + l) - 1); - paintLines(g, bg, fg, topLine, e); - } - - - target.print(g); - } - - int linesInWindow(boolean horizScrollbar) { - Dimension d = target.size(); - int htotal = d.height - ((2 * MARGIN) + (horizScrollbar? SCROLLBAR : 0)); - return htotal / fontHeight; - } - - void paintLines(Graphics g, Color bg, Color fg, int s, int e) { - Dimension d = target.size(); - int w = d.width - ((2 * BORDER) + (vscrollbar ? SCROLLBAR : 0)); - int h = d.height - ((2 * BORDER) + (hscrollbar ? SCROLLBAR : 0)); - int lm = linesInWindow(true) + topLine; - s = Math.max(topLine, s); - e = Math.min(e, lm - 1); - Graphics ng = g.create(); - try { - ng.clipRect(BORDER + MARGIN, MARGIN + BORDER, w - (2*MARGIN), - h - (2*MARGIN)); - ng.setFont(target.getFont()); - for (int i = s ; i <= e; i++) { - paintLine(ng, bg, fg, i); - } - } finally { - ng.dispose(); - } - } - - void paintLine(Graphics g, Color bg, Color fg, int lnr) { - Dimension d = target.size(); - int l = linesInWindow(true); - - if((lnr < topLine) || (lnr >= l + topLine)) { - return; - } - int w = d.width - ((2 * BORDER) + (hscrollbar ? SCROLLBAR : 0)); - int y = MARGIN + fontLeading + ((lnr - topLine) * fontHeight); - String text = ((TextLine)lines.elementAt(lnr)).text; - int len = text.length(); - - if (lnr > numLines - 1) { - g.setColor(bg); - g.fillRect(BORDER, y - fontLeading, w, fontHeight); - return; - } - int s = 0; - int e = (lnr < numLines - 1) ? len : textLength; - int xs = pos2x(selStart) - movedRight; - int xe = pos2x(selEnd) - movedRight; - - Color highlight = bg.brighter(); - if ((selStart < s) && (selEnd > e)) { - g.setColor(highlight); - g.fillRect(BORDER, y - fontLeading, w, fontHeight); - } else { - g.setColor(bg); - g.fillRect(BORDER, y - fontLeading, w, fontHeight); - - if ((selStart >= s) && (selStart <= e)) { - g.setColor(highlight); - - if (selEnd > e) { - g.fillRect(xs, y - fontLeading, (w + BORDER) - xs, fontHeight); - } else if (selStart == selEnd) { - //g.fillRect(xs, y - fontLeading, 1, fontHeight); - } else { - g.fillRect(xs, y - fontLeading, xe - xs, fontHeight); - } - } else if ((selEnd >= s) && (selEnd <= e)) { - g.setColor(highlight); - g.fillRect(BORDER, y - fontLeading, xe - BORDER, fontHeight); - } - } - g.setColor(fg); - g.drawString(text, MARGIN - movedRight, y + fontAscent); - } - - int pos2x(int pos) { - FontMetrics fm = getFontMetrics(target.getFont()); - int widths[] = fm.getWidths(); - TextLine tl1 = (TextLine)lines.elementAt(0); - TextLine tl2; - int l = 0; - for (int i = 0; i < lines.size() - 1; i++) { - tl2 = (TextLine)lines.elementAt(i+1); - if (pos >= tl1.pos && pos < tl2.pos) { - l = i; - break; - } - tl1 = tl2; - } - int x = MARGIN; - for (int i = 0 ; i < (pos - tl1.pos - 1) ; i++) { - x += widths[tl1.text.charAt(i)]; - } - return x; - } - - /** - * DEPRECATED - */ - public void insertText(String txt, int pos) { - insert(txt, pos); - } - - /** - * DEPRECATED - */ - public void replaceText(String txt, int start, int end) { - replaceRange(txt, start, end); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - - /** - * DEPRECATED - */ - public Dimension preferredSize(int rows, int cols) { - return getPreferredSize(rows, cols); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize(int rows, int cols) { - return getMinimumSize(rows, cols); - } - - /* - * Post a new TextEvent when the value of a text component changes. - */ - public void valueChanged() { - postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); - } - - void pShow(){ - pShow2(); - notifyTextComponentChange(true); - } - - void pHide(){ - notifyTextComponentChange(false); - super.pHide(); - } - - void pDispose(){ - notifyTextComponentChange(false); - super.pDispose(); - } - - public boolean handlesWheelScrolling() {return true;} - - public void handleEvent(AWTEvent e) { - if (e.getID() == MouseEvent.MOUSE_WHEEL) { - MouseWheelEvent mwe = (MouseWheelEvent)e; - nativeHandleMouseWheel(mwe.getScrollType(), - mwe.getScrollAmount(), - mwe.getWheelRotation()); - } - else { - super.handleEvent(e); - } - } - - public InputMethodRequests getInputMethodRequests() { - return null; - } - - - - native void nativeHandleMouseWheel(int scrollType, - int scrollAmount, - int wheelRotation); - - // - // Accessibility support - // - - - // stub functions: to be fully implemented in a future release - public int getIndexAtPoint(int x, int y) { return -1; } - public Rectangle getCharacterBounds(int i) { return null; } - public long filterEvents(long mask) { return 0; } - -/* To be fully implemented in a future release - - int oldSelectionStart; - int oldSelectionEnd; - - public native int getIndexAtPoint(int x, int y); - public native Rectangle getCharacterBounds(int i); - public native long filterEvents(long mask); - - /** - * Handle a change in the text selection endpoints - * (Note: could be simply a change in the caret location) - * - public void selectionValuesChanged(int start, int end) { - return; // Need to write implementation of this. - } -*/ -} - - -class TextLine { - String text; - int pos; -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MTextFieldPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MTextFieldPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -/* - * Copyright 1995-2003 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 sun.awt.motif; - -import java.awt.*; -import java.awt.peer.*; -import java.awt.datatransfer.*; -import java.awt.event.ActionEvent; -import java.awt.event.TextEvent; -import java.awt.im.InputMethodRequests; - - -public class MTextFieldPeer extends MComponentPeer implements TextFieldPeer { - native void pCreate(MComponentPeer parent); - - private boolean firstChangeSkipped; - - /** - * Initialize JNI field and method IDs - */ - private static native void initIDs(); - - static { - initIDs(); - } - - void create(MComponentPeer parent) { - firstChangeSkipped = false; - pCreate(parent); - } - - void initialize() { - int start, end; - - TextField txt = (TextField)target; - - setText(txt.getText()); - if (txt.echoCharIsSet()) { - setEchoChar(txt.getEchoChar()); - } - - start = txt.getSelectionStart(); - end = txt.getSelectionEnd(); - - if (end > start) { - select(start, end); - } else { - setCaretPosition(start); - } - - if (!target.isBackgroundSet()) { - // This is a way to set the background color of the TextArea - // without calling setBackground - go through native C code - setTargetBackground(SystemColor.text); - } - if (!target.isForegroundSet()) { - target.setForeground(SystemColor.textText); - } - - setEditable(txt.isEditable()); - -// oldSelectionStart = -1; // accessibility support -// oldSelectionEnd = -1; // accessibility support - - super.initialize(); - } - - public MTextFieldPeer(TextField target) { - super(target); - } - - public void setEditable(boolean editable) { - pSetEditable(editable); - - /* 4136955 - Calling setBackground() here works around an Xt - * bug by forcing Xt to flush an internal widget cache - */ - setBackground(target.getBackground()); - } - - public native void pSetEditable(boolean editable); - public native void select(int selStart, int selEnd); - public native int getSelectionStart(); - public native int getSelectionEnd(); - public native void setText(String l); - public native void insertReplaceText(String l); - public native void preDispose(); - public native String getText(); - public native void setEchoChar(char c); - public native void setFont(Font f); - public native void setCaretPosition(int pos); - public native int getCaretPosition(); - - // CDE/Motif defaults: margin=5, shadow=2, highlight=1 -- times 2. - // Should have asked the widgets for correct values (see MTextAreaPeer). - private static final int padding = 16; - - public Dimension getMinimumSize() { - FontMetrics fm = getFontMetrics(target.getFont()); - return new Dimension(fm.stringWidth(((TextField)target).getText())+20, - fm.getMaxDescent() + fm.getMaxAscent() + padding); - } - - public Dimension getPreferredSize(int cols) { - return getMinimumSize(cols); - } - - public Dimension getMinimumSize(int cols) { - FontMetrics fm = getFontMetrics(target.getFont()); - return new Dimension(fm.charWidth('0') * cols + 20, - fm.getMaxDescent() + fm.getMaxAscent() + padding); - } - - public boolean isFocusable() { - return true; - } - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void action(final long when, final int modifiers) { - MToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, - ((TextField)target).getText(), when, - modifiers)); - } - }); - } - - protected void disposeImpl() { - preDispose(); - super.disposeImpl(); - } - - /* - * Post a new TextEvent when the value of a text component changes. - */ - public void valueChanged() { - postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); - } - - // Called from native widget when paste key is pressed and we - // already own the selection (prevents Motif from hanging while - // waiting for the selection) - // - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void pasteFromClipboard() { - Clipboard clipboard = target.getToolkit().getSystemClipboard(); - - Transferable content = clipboard.getContents(this); - if (content != null) { - try { - String data = (String)(content.getTransferData(DataFlavor.stringFlavor)); - insertReplaceText(data); - - } catch (Exception e) { - } - } - } - - /* - * Print the native component by rendering the Motif look ourselves. - * ToDo(aim): needs to query native motif for more accurate size and - * color information, left text offset, and selected text. - */ - public final static int BORDER = 2; - public final static int MARGIN = 4; - - public void print(Graphics g) { - TextField txt = (TextField)target; - Dimension d = txt.size(); - int w = d.width - (2 * BORDER); - int h = d.height - (2 * BORDER); - Color bg = txt.getBackground(); - Color fg = txt.getForeground(); - Color highlight = bg.brighter(); - String text = txt.getText(); - int moved = 0; - int selStart = 0; - int selEnd = 0; - - g.setFont(txt.getFont()); - g.setColor(txt.isEditable() ? highlight : bg); - g.fillRect(BORDER, BORDER, w, h); - - g.setColor(bg); - //g.drawRect(0, 0, d.width-1, d.height-1); - draw3DRect(g, bg, 1, 1, d.width-3, d.height-3, false); - - if (text != null) { - g.clipRect(BORDER, MARGIN, w, d.height - (2 * MARGIN)); - FontMetrics fm = g.getFontMetrics(); - - w = d.width - BORDER; - h = d.height - (2 * MARGIN); - int xs = pos2x(selStart) - moved; - int xe = pos2x(selEnd) - moved; - - if ((xs < MARGIN) && (xe > w)) { - g.setColor(highlight); - g.fillRect(BORDER, MARGIN, w - BORDER, h); - } else { - g.setColor(bg); - //g.fillRect(BORDER, MARGIN, w - BORDER, h); - - if ((xs >= MARGIN) && (xs <= w)) { - g.setColor(highlight); // selected text - - if (xe > w) { - g.fillRect(xs, MARGIN, w - xs, h); - } else if (xs == xe) { - //g.fillRect(xs, MARGIN, 1, h); - } else { - g.fillRect(xs, MARGIN, xe - xs, h); - } - } else if ((xe >= MARGIN) && (xe <= w)) { - g.setColor(highlight); - g.fillRect(BORDER, MARGIN, xe - BORDER, h); - } - } - g.setColor(fg); - int x = MARGIN - moved; - char echoChar = txt.getEchoChar(); - if (echoChar == 0) { - g.drawString(text, x, BORDER + MARGIN + fm.getMaxAscent()); - } else { - char data[] = new char[text.length()]; - for (int i = 0 ; i < data.length ; i++) { - data[i] = echoChar; - } - g.drawChars(data, 0, data.length, x, - BORDER + MARGIN + fm.getMaxAscent()); - - } - } - - target.print(g); - } - - int pos2x(int pos) { - TextField txt = (TextField)target; - FontMetrics fm = getFontMetrics(txt.getFont()); - int x = MARGIN, widths[] = fm.getWidths(); - String text = txt.getText(); - char echoChar = txt.getEchoChar(); - if (echoChar == 0) { - for (int i = 0 ; i < pos ; i++) { - x += widths[text.charAt(i)]; - } - } else { - x += widths[echoChar] * pos; - } - return x; - } - - /** - * DEPRECATED - */ - public void setEchoCharacter(char c) { - setEchoChar(c); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize() { - return getMinimumSize(); - } - - /** - * DEPRECATED - */ - public Dimension minimumSize(int cols) { - return getMinimumSize(cols); - } - - /** - * DEPRECATED - */ - public Dimension preferredSize(int cols) { - return getPreferredSize(cols); - } - void pShow(){ - super.pShow(); - notifyTextComponentChange(true); - } - - void pHide(){ - notifyTextComponentChange(false); - super.pHide(); - } - - void pDispose(){ - notifyTextComponentChange(false); - super.pDispose(); - } - - public InputMethodRequests getInputMethodRequests() { - return null; - } - - - - // - // Accessibility support - // - - // stub functions: to be fully implemented in a future release - public int getIndexAtPoint(int x, int y) { return -1; } - public Rectangle getCharacterBounds(int i) { return null; } - public long filterEvents(long mask) { return 0; } - - -/* To be fully implemented in a future release - - int oldSelectionStart; - int oldSelectionEnd; - - public native int getIndexAtPoint(int x, int y); - public native Rectangle getCharacterBounds(int i); - public native long filterEvents(long mask); - - /** - * Handle a change in the text selection endpoints - * (Note: could be simply a change in the caret location) - * - public void selectionValuesChanged(int start, int end) { - return; // Need to write implemetation of this. - } -*/ - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MToolkit.java --- a/jdk/src/solaris/classes/sun/awt/motif/MToolkit.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/motif/MToolkit.java Wed Jul 05 16:41:30 2017 +0200 @@ -60,12 +60,12 @@ import java.awt.dnd.InvalidDnDOperationException; import java.awt.dnd.peer.DragSourceContextPeer; -import sun.awt.motif.MInputMethod; +//import sun.awt.motif.MInputMethod; import sun.awt.X11GraphicsConfig; import sun.awt.X11GraphicsEnvironment; import sun.awt.XSettings; -import sun.awt.motif.MDragSourceContextPeer; +//import sun.awt.motif.MDragSourceContextPeer; import sun.print.PrintJob2D; @@ -79,9 +79,9 @@ private static final Logger log = Logger.getLogger("sun.awt.motif.MToolkit"); // the system clipboard - CLIPBOARD selection - X11Clipboard clipboard; + //X11Clipboard clipboard; // the system selection - PRIMARY selection - X11Clipboard selection; + //X11Clipboard selection; // Dynamic Layout Resize client code setting protected static boolean dynamicLayoutSetting = false; @@ -130,7 +130,7 @@ new GetBooleanAction("awt.dnd.motifdnd"))).booleanValue(); } - public static final String DATA_TRANSFERER_CLASS_NAME = "sun.awt.motif.MDataTransferer"; + //public static final String DATA_TRANSFERER_CLASS_NAME = "sun.awt.motif.MDataTransferer"; public MToolkit() { super(); @@ -150,7 +150,7 @@ } init(mainClassName); - SunToolkit.setDataTransfererClassName(DATA_TRANSFERER_CLASS_NAME); + //SunToolkit.setDataTransfererClassName(DATA_TRANSFERER_CLASS_NAME); Thread toolkitThread = new Thread(this, "AWT-Motif"); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); @@ -197,131 +197,152 @@ */ public ButtonPeer createButton(Button target) { - ButtonPeer peer = new MButtonPeer(target); - targetCreatedPeer(target, peer); - return peer; + //ButtonPeer peer = new MButtonPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public TextFieldPeer createTextField(TextField target) { - TextFieldPeer peer = new MTextFieldPeer(target); - targetCreatedPeer(target, peer); - return peer; + //TextFieldPeer peer = new MTextFieldPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public LabelPeer createLabel(Label target) { - LabelPeer peer = new MLabelPeer(target); - targetCreatedPeer(target, peer); - return peer; + //LabelPeer peer = new MLabelPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public ListPeer createList(List target) { - ListPeer peer = new MListPeer(target); - targetCreatedPeer(target, peer); - return peer; + //ListPeer peer = new MListPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public CheckboxPeer createCheckbox(Checkbox target) { - CheckboxPeer peer = new MCheckboxPeer(target); - targetCreatedPeer(target, peer); - return peer; + //CheckboxPeer peer = new MCheckboxPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public ScrollbarPeer createScrollbar(Scrollbar target) { - ScrollbarPeer peer = new MScrollbarPeer(target); - targetCreatedPeer(target, peer); - return peer; + //ScrollbarPeer peer = new MScrollbarPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public ScrollPanePeer createScrollPane(ScrollPane target) { - ScrollPanePeer peer = new MScrollPanePeer(target); - targetCreatedPeer(target, peer); - return peer; + //ScrollPanePeer peer = new MScrollPanePeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public TextAreaPeer createTextArea(TextArea target) { - TextAreaPeer peer = new MTextAreaPeer(target); - targetCreatedPeer(target, peer); - return peer; + //TextAreaPeer peer = new MTextAreaPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public ChoicePeer createChoice(Choice target) { - ChoicePeer peer = new MChoicePeer(target); - targetCreatedPeer(target, peer); - return peer; + //ChoicePeer peer = new MChoicePeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public FramePeer createFrame(Frame target) { - FramePeer peer = new MFramePeer(target); - targetCreatedPeer(target, peer); - return peer; + //FramePeer peer = new MFramePeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public CanvasPeer createCanvas(Canvas target) { - CanvasPeer peer = (isXEmbedServerRequested() ? new MEmbedCanvasPeer(target) : new MCanvasPeer(target)); - targetCreatedPeer(target, peer); - return peer; + //CanvasPeer peer = (isXEmbedServerRequested() ? new MEmbedCanvasPeer(target) : new MCanvasPeer(target)); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public PanelPeer createPanel(Panel target) { - PanelPeer peer = new MPanelPeer(target); - targetCreatedPeer(target, peer); - return peer; + //PanelPeer peer = new MPanelPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public WindowPeer createWindow(Window target) { - WindowPeer peer = new MWindowPeer(target); - targetCreatedPeer(target, peer); - return peer; + //WindowPeer peer = new MWindowPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public DialogPeer createDialog(Dialog target) { - DialogPeer peer = new MDialogPeer(target); - targetCreatedPeer(target, peer); - return peer; + //DialogPeer peer = new MDialogPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public FileDialogPeer createFileDialog(FileDialog target) { - FileDialogPeer peer = new MFileDialogPeer(target); - targetCreatedPeer(target, peer); - return peer; + //FileDialogPeer peer = new MFileDialogPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public MenuBarPeer createMenuBar(MenuBar target) { - MenuBarPeer peer = new MMenuBarPeer(target); - targetCreatedPeer(target, peer); - return peer; + //MenuBarPeer peer = new MMenuBarPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public MenuPeer createMenu(Menu target) { - MenuPeer peer = new MMenuPeer(target); - targetCreatedPeer(target, peer); - return peer; + //MenuPeer peer = new MMenuPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public PopupMenuPeer createPopupMenu(PopupMenu target) { - PopupMenuPeer peer = new MPopupMenuPeer(target); - targetCreatedPeer(target, peer); - return peer; + //PopupMenuPeer peer = new MPopupMenuPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public MenuItemPeer createMenuItem(MenuItem target) { - MenuItemPeer peer = new MMenuItemPeer(target); - targetCreatedPeer(target, peer); - return peer; + //MenuItemPeer peer = new MMenuItemPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) { - CheckboxMenuItemPeer peer = new MCheckboxMenuItemPeer(target); - targetCreatedPeer(target, peer); - return peer; + //CheckboxMenuItemPeer peer = new MCheckboxMenuItemPeer(target); + //targetCreatedPeer(target, peer); + //return peer; + return null; } - public MEmbeddedFramePeer createEmbeddedFrame(MEmbeddedFrame target) - { - MEmbeddedFramePeer peer = new MEmbeddedFramePeer(target); - targetCreatedPeer(target, peer); - return peer; - } + //public MEmbeddedFramePeer createEmbeddedFrame(MEmbeddedFrame target) + //{ + //MEmbeddedFramePeer peer = new MEmbeddedFramePeer(target); + //targetCreatedPeer(target, peer); + //return peer; + // return null; + //} public FontPeer getFontPeer(String name, int style){ @@ -438,29 +459,31 @@ public native void beep(); public Clipboard getSystemClipboard() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkSystemClipboardAccess(); - } - synchronized (this) { - if (clipboard == null) { - clipboard = new X11Clipboard("System", "CLIPBOARD"); - } - } - return clipboard; + //SecurityManager security = System.getSecurityManager(); + //if (security != null) { + // security.checkSystemClipboardAccess(); + //} + //synchronized (this) { + // if (clipboard == null) { + // clipboard = new X11Clipboard("System", "CLIPBOARD"); + // } + //} + //return clipboard; + return null; } public Clipboard getSystemSelection() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkSystemClipboardAccess(); - } - synchronized (this) { - if (selection == null) { - selection = new X11Clipboard("Selection", "PRIMARY"); - } - } - return selection; + //SecurityManager security = System.getSecurityManager(); + //if (security != null) { + // security.checkSystemClipboardAccess(); + //} + //synchronized (this) { + // if (selection == null) { + // selection = new X11Clipboard("Selection", "PRIMARY"); + // } + //} + //return selection; + return null; } public boolean getLockingKeyState(int key) { @@ -492,11 +515,12 @@ } public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { - if (MToolkit.useMotifDnD()) { - return MDragSourceContextPeer.createDragSourceContextPeer(dge); - } else { - return X11DragSourceContextPeer.createDragSourceContextPeer(dge); - } + //if (MToolkit.useMotifDnD()) { + // return MDragSourceContextPeer.createDragSourceContextPeer(dge); + //} else { + // return X11DragSourceContextPeer.createDragSourceContextPeer(dge); + //} + return null; } public T @@ -504,9 +528,9 @@ DragSource ds, Component c, int srcActions, DragGestureListener dgl) { - if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) - return (T)new MMouseDragGestureRecognizer(ds, c, srcActions, dgl); - else + //if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass)) + // return (T)new MMouseDragGestureRecognizer(ds, c, srcActions, dgl); + //else return null; } @@ -514,14 +538,14 @@ * Returns a new input method adapter descriptor for native input methods. */ public InputMethodDescriptor getInputMethodAdapterDescriptor() throws AWTException { - return new MInputMethodDescriptor(); + return null; // return new MInputMethodDescriptor(); } /** * Returns a style map for the input method highlight. */ public Map mapInputMethodHighlight(InputMethodHighlight highlight) { - return MInputMethod.mapInputMethodHighlight(highlight); + return null; //return MInputMethod.mapInputMethodHighlight(highlight); } /** @@ -529,15 +553,15 @@ */ public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) throws IndexOutOfBoundsException { - return new MCustomCursor(cursor, hotSpot, name); + return null; //return new MCustomCursor(cursor, hotSpot, name); } /** * Returns the supported cursor size */ public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) { - return MCustomCursor.getBestCursorSize( - java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight)); + return null; //MCustomCursor.getBestCursorSize( + //java.lang.Math.max(1,preferredWidth), java.lang.Math.max(1,preferredHeight)); } public int getMaximumCursorColors() { @@ -621,7 +645,8 @@ public RobotPeer createRobot(Robot target, GraphicsDevice screen) { /* 'target' is unused for now... */ - return new MRobotPeer(screen.getDefaultConfiguration()); + //return new MRobotPeer(screen.getDefaultConfiguration()); + return null; } static boolean useMotifDnD() { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/MWindowPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MWindowPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,602 +0,0 @@ -/* - * 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 - * 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 sun.awt.motif; - -import java.util.Vector; -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.*; -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferByte; -import java.awt.image.DataBufferInt; -import java.awt.image.ImageObserver; -import sun.awt.image.ImageRepresentation; -import sun.awt.motif.MInputMethod; -import sun.awt.motif.MInputMethodControl; -import sun.awt.im.*; -import sun.awt.DisplayChangedListener; -import sun.awt.SunToolkit; -import sun.awt.X11GraphicsDevice; - -class MWindowPeer extends MPanelPeer implements WindowPeer, -DisplayChangedListener { - - Insets insets = new Insets( 0, 0, 0, 0 ); - MWindowAttributes winAttr; - static Vector allWindows = new Vector(); - int iconWidth = -1; - int iconHeight = -1; - - int dropTargetCount = 0; - boolean alwaysOnTop; - - native void pCreate(MComponentPeer parent, String targetClassName, boolean isFocusableWindow); - native void pShow(); - native void pToFront(); - native void pShowModal(boolean isModal); - native void pHide(); - native void pReshape(int x, int y, int width, int height); - native void pDispose(); - native void pSetTitle(String title); - public native void setState(int state); - public native int getState(); - - public native void setResizable(boolean resizable); - native void addTextComponentNative(MComponentPeer tc); - native void removeTextComponentNative(); - native void pSetIMMOption(String option); - native void pSetMenuBar(MMenuBarPeer mbpeer); - native void setSaveUnder(boolean state); - - native void registerX11DropTarget(Component target); - native void unregisterX11DropTarget(Component target); - native void updateAlwaysOnTop(boolean isAlwaysOnTop); - - private static native void initIDs(); - - static { - initIDs(); - } - - // this function is privileged! do not change it to public! - private static int getInset(final String name, final int def) { - Integer tmp = (Integer) java.security.AccessController.doPrivileged( - new sun.security.action.GetIntegerAction(name, def)); - return tmp.intValue(); - } - - MWindowPeer() { - insets = new Insets(0,0,0,0); - winAttr = new MWindowAttributes(); - } - - MWindowPeer(Window target) { - - this(); - init(target); - - allWindows.addElement(this); - } - - void create(MComponentPeer parent) { - pCreate(parent, target.getClass().getName(), ((Window)target).isFocusableWindow()); - } - - void init( Window target ) { - if ( winAttr.nativeDecor == true ) { - insets.top = getInset("awt.frame.topInset", -1); - insets.left = getInset("awt.frame.leftInset", -1); - insets.bottom = getInset("awt.frame.bottomInset", -1); - insets.right = getInset("awt.frame.rightInset", -1); - } - - Rectangle bounds = target.getBounds(); - sysX = bounds.x; - sysY = bounds.y; - sysW = bounds.width; - sysH = bounds.height; - - super.init(target); - InputMethodManager imm = InputMethodManager.getInstance(); - String menuString = imm.getTriggerMenuString(); - if (menuString != null) - { - pSetIMMOption(menuString); - } - pSetTitle(winAttr.title); - - /* - * For Windows and undecorated Frames and Dialogs this just - * disables/enables resizing functions in the system menu. - */ - setResizable(winAttr.isResizable); - - setSaveUnder(true); - - Font f = target.getFont(); - if (f == null) { - f = defaultFont; - target.setFont(f); - setFont(f); - } - Color c = target.getBackground(); - if (c == null) { - target.setBackground(SystemColor.window); - setBackground(SystemColor.window); - } - c = target.getForeground(); - if (c == null) { - target.setForeground(SystemColor.windowText); - setForeground(SystemColor.windowText); - } - alwaysOnTop = ((Window)target).isAlwaysOnTop() && ((Window)target).isAlwaysOnTopSupported(); - - GraphicsConfiguration gc = getGraphicsConfiguration(); - ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this); - - } - - /* Support for multiple icons is not implemented in MAWT */ - public void updateIconImages() { - if (this instanceof MFramePeer) { - ((MFramePeer)this).setIconImage(((Frame)target).getIconImage()); - } - } - - - /* Not implemented in MAWT */ - public void updateMinimumSize() { - } - - protected void disposeImpl() { - allWindows.removeElement(this); - super.disposeImpl(); - } - - public native void toBack(); - - public void setAlwaysOnTop(boolean alwaysOnTop) { - this.alwaysOnTop = alwaysOnTop; - updateAlwaysOnTop(alwaysOnTop); - } - - public void toFront() { - if (target.isVisible()) { - updateFocusableWindowState(); - pToFront(); - } - } - - public void updateFocusableWindowState() { - setFocusableWindow(((Window)target).isFocusableWindow()); - } - native void setFocusableWindow(boolean value); - - public void setVisible( boolean b ) { - if (b) { - updateFocusableWindowState(); - } - super.setVisible(b); - updateAlwaysOnTop(alwaysOnTop); - } - - public Insets getInsets() { - return insets; - } - - public void handleQuit() { - postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); - } - - // XXX: nasty WM, foul play. spank WM author. - public void handleDestroy() { - final Window target = (Window)this.target; - SunToolkit.executeOnEventHandlerThread(target, - new Runnable() { - public void run() { - // This seems like the only reasonable thing we - // could do in this situation as the native window - // is already dead. - target.dispose(); - } - }); - } - - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleIconify() { - postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleDeiconify() { - postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleStateChange(int oldState, int newState) { - postEvent(new WindowEvent((Window)target, - WindowEvent.WINDOW_STATE_CHANGED, - oldState, newState)); - } - - /** - * Called to inform the Window that its size has changed and it - * should layout its children. - */ - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleResize(int width, int height) { - sysW = width; - sysH = height; - - // REMIND: Is this secure? Can client code subclass input method? - if (!tcList.isEmpty() && - !imList.isEmpty()){ - int i; - for (i = 0; i < imList.size(); i++){ - ((MInputMethod)imList.elementAt(i)).configureStatus(); - } - } - validateSurface(width, height); - postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED)); - } - - - /** - * DEPRECATED: Replaced by getInsets(). - */ - public Insets insets() { - return getInsets(); - } - - public void handleMoved(int x, int y) { - sysX = x; - sysY = y; - postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); - } - - private native AWTEvent wrapInSequenced(AWTEvent event); - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleWindowFocusIn() { - WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS); - /* wrap in Sequenced, then post*/ - postEvent(wrapInSequenced((AWTEvent) we)); - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void handleWindowFocusOut(Window oppositeWindow) { - WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, - oppositeWindow); - /* wrap in Sequenced, then post*/ - postEvent(wrapInSequenced((AWTEvent) we)); - } - - -// relocation of Imm stuff - private Vector imList = new Vector(); - private Vector tcList = new Vector(); - - // NOTE: This method is called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - void notifyIMMOptionChange(){ - - // REMIND: IS THIS SECURE??? CAN USER CODE SUBCLASS INPUTMETHODMGR??? - InputMethodManager.getInstance().notifyChangeRequest(target); - } - - public void addInputMethod(MInputMethod im) { - if (!imList.contains(im)) - imList.addElement(im); - } - - public void removeInputMethod(MInputMethod im) { - if (imList.contains(im)) - imList.removeElement(im); - } - - public void addTextComponent(MComponentPeer tc) { - if (tcList.contains(tc)) - return; - if (tcList.isEmpty()){ - addTextComponentNative(tc); - if (!imList.isEmpty()) { - for (int i = 0; i < imList.size(); i++) { - ((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this); - } - } - MToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - synchronized(target.getTreeLock()) { - target.doLayout(); - } - } - }); - } - tcList.addElement(tc); - - } - - public void removeTextComponent(MComponentPeer tc) { - if (!tcList.contains(tc)) - return; - tcList.removeElement(tc); - if (tcList.isEmpty()){ - removeTextComponentNative(); - if (!imList.isEmpty()) { - for (int i = 0; i < imList.size(); i++) { - ((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this); - } - } - target.doLayout(); - } - } - - public MComponentPeer getTextComponent() { - if (!tcList.isEmpty()) { - return (MComponentPeer)tcList.firstElement(); - } else { - return null; - } - } - - boolean hasDecorations(int decor) { - if (!winAttr.nativeDecor) { - return false; - } - else { - int myDecor = winAttr.decorations; - boolean hasBits = ((myDecor & decor) == decor); - if ((myDecor & MWindowAttributes.AWT_DECOR_ALL) != 0) - return !hasBits; - else - return hasBits; - } - } - - /* Returns the native paint should be posted after setting new size - */ - public boolean checkNativePaintOnSetBounds(int width, int height) { - // Fix for 4418155. Window does not repaint - // automticaly if shrinking. Should not wait for Expose - return (width > oldWidth) || (height > oldHeight); - } - -/* --- DisplayChangedListener Stuff --- */ - - native void resetTargetGC(Component target); - - /* Xinerama - * called to update our GC when dragged onto another screen - */ - public void draggedToNewScreen(int screenNum) { - final int finalScreenNum = screenNum; - - SunToolkit.executeOnEventHandlerThread((Component)target, new Runnable() - { - public void run() { - displayChanged(finalScreenNum); - } - }); - } - - /* Xinerama - * called to update our GC when dragged onto another screen - */ - public void displayChanged(int screenNum) { - // update our GC - resetLocalGC(screenNum); /* upcall to MCanvasPeer */ - resetTargetGC(target); /* call Window.resetGC() via native */ - - //propagate to children - super.displayChanged(screenNum); /* upcall to MPanelPeer */ - } - - /** - * Helper method that executes the displayChanged(screen) method on - * the event dispatch thread. This method is used in the Xinerama case - * and after display mode change events. - */ - private void executeDisplayChangedOnEDT(int screenNum) { - final int finalScreenNum = screenNum; - Runnable dc = new Runnable() { - public void run() { - displayChanged(finalScreenNum); - } - }; - SunToolkit.executeOnEventHandlerThread((Component)target, dc); - } - - /** - * From the DisplayChangedListener interface; called from - * X11GraphicsDevice when the display mode has been changed. - */ - public void displayChanged() { - GraphicsConfiguration gc = getGraphicsConfiguration(); - int curScreenNum = ((X11GraphicsDevice)gc.getDevice()).getScreen(); - executeDisplayChangedOnEDT(curScreenNum); - } - - /** - * From the DisplayChangedListener interface; top-levels do not need - * to react to this event. - */ - public void paletteChanged() { - } - - public synchronized void addDropTarget() { - if (dropTargetCount == 0) { - registerX11DropTarget(target); - } - dropTargetCount++; - } - - public synchronized void removeDropTarget() { - dropTargetCount--; - if (dropTargetCount == 0) { - unregisterX11DropTarget(target); - } - } - - protected synchronized void updateDropTarget() { - if (dropTargetCount > 0) { - unregisterX11DropTarget(target); - registerX11DropTarget(target); - } - } - - public boolean requestWindowFocus() { - return false; - } - - public void setModalBlocked(Dialog blocker, boolean blocked) { - // do nothing - } - - public void postUngrabEvent() { - postEvent(new sun.awt.UngrabEvent((Window)target)); - } - - boolean isOwnerOf(MComponentPeer child) { - if (child == null) return false; - - Component comp = child.target; - while (comp != null && !(comp instanceof Window)) { - comp = getParent_NoClientCode(comp); - } - if (!(comp instanceof Window)) { - return false; - } - - while (comp != null && !(comp == target) && !(comp instanceof Dialog)) { - comp = getParent_NoClientCode(comp); - } - return (comp == target); - } - - boolean processUngrabMouseEvent(MComponentPeer compPeer, int x_root, int y_root, int type) { - switch (type) { - case 4: // ButtonPress - // Check that the target is the child of the grabbed - // window or the child of one of the owned windows of - // the grabbed window - if (!isOwnerOf(compPeer)) { - postUngrabEvent(); - return true; - } - } - return false; - } - - private final boolean hasWarningWindow() { - return ((Window)target).getWarningString() != null; - } - - // This method is overriden at Dialog and Frame peers. - boolean isTargetUndecorated() { - return true; - } - - private volatile int sysX = 0; - private volatile int sysY = 0; - private volatile int sysW = 0; - private volatile int sysH = 0; - - Rectangle constrainBounds(int x, int y, int width, int height) { - // We don't restrict the setBounds() operation if the code is trusted. - if (!hasWarningWindow()) { - return new Rectangle(x, y, width, height); - } - - int newX = x; - int newY = y; - int newW = width; - int newH = height; - - GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); - Rectangle sB = gc.getBounds(); - Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); - - int screenW = sB.width - sIn.left - sIn.right; - int screenH = sB.height - sIn.top - sIn.bottom; - - // If it's undecorated or is not currently visible, - // then check each point is within the visible part of the screen - if (!target.isVisible() || isTargetUndecorated()) { - int screenX = sB.x + sIn.left; - int screenY = sB.y + sIn.top; - - // First make sure the size is withing the visible part of the screen - if (newW > screenW) { - newW = screenW; - } - - if (newH > screenH) { - newH = screenH; - } - - // Tweak the location if needed - if (newX < screenX) { - newX = screenX; - } else if (newX + newW > screenX + screenW) { - newX = screenX + screenW - newW; - } - - if (newY < screenY) { - newY = screenY; - } else if (newY + newH > screenY + screenH) { - newY = screenY + screenH - newH; - } - } else { - int maxW = Math.max(screenW, sysW); - int maxH = Math.max(screenH, sysH); - - // Make sure the size is withing the visible part of the screen - // OR is less that the current size of the window. - if (newW > maxW) { - newW = maxW; - } - - if (newH > maxH) { - newH = maxH; - } - } - - return new Rectangle(newX, newY, newW, newH); - } - - public void setBounds(int x, int y, int width, int height, int op) { - Rectangle newBounds = constrainBounds(x, y, width, height); - super.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height, op); - } - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/X11Clipboard.java --- a/jdk/src/solaris/classes/sun/awt/motif/X11Clipboard.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright 1996-2003 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 sun.awt.motif; - -import java.awt.datatransfer.ClipboardOwner; -import java.awt.datatransfer.Transferable; - -import java.io.IOException; - -import java.security.AccessController; - -import sun.awt.datatransfer.SunClipboard; -import sun.awt.datatransfer.TransferableProxy; -import sun.awt.datatransfer.DataTransferer; - -import sun.security.action.GetIntegerAction; - - -/** - * A class which interfaces with the X11 selection service in order to support - * data transfer via Clipboard operations. Most of the work is provided by - * sun.awt.datatransfer.DataTransferer. - * - * @author Amy Fowler - * @author Roger Brinkley - * @author Danila Sinopalnikov - * @author Alexander Gerasimov - * - * @since JDK1.1 - */ -public class X11Clipboard extends SunClipboard implements X11SelectionHolder { - - private final X11Selection clipboardSelection; - - private static final Object classLock = new Object(); - - private static final int defaultPollInterval = 200; - - private static int pollInterval; - - private static int listenedClipboardsCount; - - /** - * Creates a system clipboard object. - */ - public X11Clipboard(String name, String selectionName) { - super(name); - clipboardSelection = new X11Selection(selectionName, this); - } - - protected void setContentsNative(Transferable contents) { - if (!clipboardSelection.getSelectionOwnership(contents, this)) { - // Need to figure out how to inform owner the request failed... - this.owner = null; - this.contents = null; - } - } - - public long getID() { - return clipboardSelection.atom; - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void lostSelectionOwnership() { - lostOwnershipImpl(); - } - - protected void clearNativeContext() { - clipboardSelection.clearNativeContext(); - } - - protected long[] getClipboardFormats() { - return getClipboardFormats(getID()); - } - private static native long[] getClipboardFormats(long clipboardID); - - protected byte[] getClipboardData(long format) - throws IOException { - return getClipboardData(getID(), format); - } - private static native byte[] getClipboardData(long clipboardID, long format) - throws IOException; - - - // Called on the toolkit thread under awtLock. - public void checkChange(long[] formats) { - if (!clipboardSelection.isOwner()) { - super.checkChange(formats); - } - } - - void checkChangeHere(Transferable contents) { - if (areFlavorListenersRegistered()) { - super.checkChange(DataTransferer.getInstance(). - getFormatsForTransferableAsArray(contents, flavorMap)); - } - } - - protected void registerClipboardViewerChecked() { - if (pollInterval <= 0) { - pollInterval = ((Integer)AccessController.doPrivileged( - new GetIntegerAction("awt.datatransfer.clipboard.poll.interval", - defaultPollInterval))).intValue(); - if (pollInterval <= 0) { - pollInterval = defaultPollInterval; - } - } - synchronized (X11Clipboard.classLock) { - if (listenedClipboardsCount++ == 0) { - registerClipboardViewer(pollInterval); - } - } - } - - private native void registerClipboardViewer(int pollInterval); - - protected void unregisterClipboardViewerChecked() { - synchronized (X11Clipboard.classLock) { - if (--listenedClipboardsCount == 0) { - unregisterClipboardViewer(); - } - } - } - - private native void unregisterClipboardViewer(); - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/X11DragSourceContextPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/X11DragSourceContextPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright 2003-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. - */ - -package sun.awt.motif; - -import java.awt.Component; -import java.awt.Cursor; -import java.awt.Window; - -import java.awt.datatransfer.Transferable; - -import java.awt.dnd.DragSourceContext; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceEvent; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.InvalidDnDOperationException; - -import java.awt.event.InputEvent; - -import java.util.Map; - -import sun.awt.SunToolkit; - -import sun.awt.dnd.SunDragSourceContextPeer; -import sun.awt.dnd.SunDropTargetContextPeer; - -/** - * The X11DragSourceContextPeer class is the class responsible for handling - * the interaction between the XDnD/Motif DnD subsystem and Java drag sources. - * - * @since 1.5 - */ -final class X11DragSourceContextPeer extends SunDragSourceContextPeer { - - private static final X11DragSourceContextPeer theInstance = - new X11DragSourceContextPeer(null); - - /** - * construct a new X11DragSourceContextPeer - */ - - private X11DragSourceContextPeer(DragGestureEvent dge) { - super(dge); - } - - static X11DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException { - theInstance.setTrigger(dge); - return theInstance; - } - - protected void startDrag(Transferable transferable, - long[] formats, Map formatMap) { - Component component = getTrigger().getComponent(); - Component c = null; - MWindowPeer wpeer = null; - - for (c = component; c != null && !(c instanceof java.awt.Window); - c = MComponentPeer.getParent_NoClientCode(c)); - - if (c instanceof Window) { - wpeer = (MWindowPeer)c.getPeer(); - } - - if (wpeer == null) { - throw new InvalidDnDOperationException( - "Cannot find top-level for the drag source component"); - } - - startDrag(component, - wpeer, - transferable, - getTrigger().getTriggerEvent(), - getCursor(), - getCursor() == null ? 0 : getCursor().getType(), - getDragSourceContext().getSourceActions(), - formats, - formatMap); - - /* This implementation doesn't use native context */ - setNativeContext(0); - - SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(transferable); - } - - /** - * downcall into native code - */ - - private native long startDrag(Component component, - MWindowPeer wpeer, - Transferable transferable, - InputEvent nativeTrigger, - Cursor c, int ctype, int actions, - long[] formats, Map formatMap); - - /** - * set cursor - */ - - public void setCursor(Cursor c) throws InvalidDnDOperationException { - SunToolkit.awtLock(); - super.setCursor(c); - SunToolkit.awtUnlock(); - } - - protected native void setNativeCursor(long nativeCtxt, Cursor c, int cType); - -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/X11DropTargetContextPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/X11DropTargetContextPeer.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright 2003-2004 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 sun.awt.motif; - -import java.awt.Component; -import java.awt.peer.ComponentPeer; - -import sun.awt.AppContext; -import sun.awt.SunToolkit; - -import sun.awt.dnd.SunDropTargetContextPeer; -import sun.awt.dnd.SunDropTargetEvent; - -/** - * The X11DropTargetContextPeer class is the class responsible for handling - * the interaction between the XDnD/Motif DnD subsystem and Java drop targets. - * - * @since 1.5 - */ -final class X11DropTargetContextPeer extends SunDropTargetContextPeer { - - /* - * A key to store a peer instance for an AppContext. - */ - private static final Object DTCP_KEY = "DropTargetContextPeer"; - - private X11DropTargetContextPeer() {} - - public static X11DropTargetContextPeer getPeer(AppContext appContext) { - synchronized (_globalLock) { - X11DropTargetContextPeer peer = - (X11DropTargetContextPeer)appContext.get(DTCP_KEY); - if (peer == null) { - peer = new X11DropTargetContextPeer(); - appContext.put(DTCP_KEY, peer); - } - - return peer; - } - } - - /* - * Note: - * the method can be called on the toolkit thread while holding AWT_LOCK. - */ - private static void postDropTargetEventToPeer(final Component component, - final int x, final int y, - final int dropAction, - final int actions, - final long[] formats, - final long nativeCtxt, - final int eventID) { - - AppContext appContext = SunToolkit.targetToAppContext(component); - X11DropTargetContextPeer peer = getPeer(appContext); - - peer.postDropTargetEvent(component, x, y, dropAction, actions, formats, - nativeCtxt, eventID, - !SunDropTargetContextPeer.DISPATCH_SYNC); - } - - protected void eventProcessed(SunDropTargetEvent e, int returnValue, - boolean dispatcherDone) { - /* If the event was not consumed, send a response to the source. */ - long ctxt = getNativeDragContext(); - if (ctxt != 0) { - sendResponse(e.getID(), returnValue, ctxt, dispatcherDone, - e.isConsumed()); - } - } - - protected void doDropDone(boolean success, int dropAction, - boolean isLocal) { - dropDone(getNativeDragContext(), success, dropAction); - } - - protected Object getNativeData(long format) { - return getData(getNativeDragContext(), format); - } - - protected void processEnterMessage(SunDropTargetEvent event) { - if (!processSunDropTargetEvent(event)) { - super.processEnterMessage(event); - } - } - - protected void processExitMessage(SunDropTargetEvent event) { - if (!processSunDropTargetEvent(event)) { - super.processExitMessage(event); - } - } - - protected void processMotionMessage(SunDropTargetEvent event, - boolean operationChanged) { - if (!processSunDropTargetEvent(event)) { - super.processMotionMessage(event, operationChanged); - } - } - - protected void processDropMessage(SunDropTargetEvent event) { - if (!processSunDropTargetEvent(event)) { - super.processDropMessage(event); - } - } - - // If source is an XEmbedCanvasPeer, passes the event to it for processing and - // return true if the event is forwarded to the XEmbed child. - // Otherwise, does nothing and return false. - private boolean processSunDropTargetEvent(SunDropTargetEvent event) { - Object source = event.getSource(); - - if (source instanceof Component) { - ComponentPeer peer = ((Component)source).getPeer(); - if (peer instanceof MEmbedCanvasPeer) { - MEmbedCanvasPeer mEmbedCanvasPeer = (MEmbedCanvasPeer)peer; - /* The native context is the pointer to the XClientMessageEvent - structure. */ - long ctxt = getNativeDragContext(); - - /* If the event is not consumed, pass it to the - MEmbedCanvasPeer for processing. */ - if (!event.isConsumed()) { - // NOTE: ctxt can be zero at this point. - if (mEmbedCanvasPeer.processXEmbedDnDEvent(ctxt, - event.getID())) { - event.consume(); - return true; - } - } - } - } - - return false; - } - - private native void sendResponse(int eventID, int returnValue, - long nativeCtxt, boolean dispatcherDone, - boolean consumed); - - private native void dropDone(long nativeCtxt, boolean success, - int dropAction); - - private native Object getData(long nativeCtxt, long format); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/X11Selection.java --- a/jdk/src/solaris/classes/sun/awt/motif/X11Selection.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * Copyright 1996-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. - */ - -package sun.awt.motif; - -import java.awt.Toolkit; - -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.FlavorMap; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.SystemFlavorMap; - -import java.util.Map; -import java.util.SortedMap; -import java.util.Vector; - -import sun.awt.AppContext; -import sun.awt.SunToolkit; - -import sun.awt.datatransfer.DataTransferer; - -/* - * Implements a general interface to the X11 selection mechanism. - * - * @author Amy Fowler - * @author Roger Brinkley - * @author Danila Sinopalnikov - * @author Alexander Gerasimov - * - * @since JDK1.1 - */ -public class X11Selection { - - static FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap(); - - static Vector selections; - - long atom; - - private X11Clipboard clipboard; - private X11SelectionHolder holder; - private Transferable contents; - - private boolean disposed = false; - private byte[] data = null; - private boolean dataAvailable = false; - private static final Object source = new Object(); - - static { - // 4154170: Need to ensure the the toolkit is initialized prior - // to executing this initializer - Toolkit toolkit = Toolkit.getDefaultToolkit(); - - selections = new Vector(); - - initIDs(); - init(); - - } - - private static native void initIDs(); - static native void init(); - - public X11Selection(String name, X11Clipboard clipboard) { - atom = ((MDataTransferer)DataTransferer.getInstance()).getAtomForTarget(name); - selections.addElement(this); - this.clipboard = clipboard; - } - - private static Object[] getSelectionsArray() { - return selections.toArray(); - } - - /* - * methods for acting as selection provider - */ - native boolean pGetSelectionOwnership(Object source, - Transferable transferable, - long[] formats, - Map formatMap, - X11SelectionHolder holder); - - boolean getSelectionOwnership(Transferable contents, - X11SelectionHolder holder) { - SortedMap formatMap = - DataTransferer.getInstance().getFormatsForTransferable - (contents, DataTransferer.adaptFlavorMap(flavorMap)); - long[] formats = - DataTransferer.getInstance().keysToLongArray(formatMap); - SunToolkit.insertTargetMapping(source, AppContext.getAppContext()); - - /* - * Update 'contents' and 'holder' fields in the native code under - * AWTLock protection to prevent race with lostSelectionOwnership(). - */ - SunToolkit.awtLock(); - try { - boolean isOwnerSet = pGetSelectionOwnership(source, contents, formats, formatMap, - holder); - if (isOwnerSet) { - clipboard.checkChangeHere(contents); - } - return isOwnerSet; - } finally { - SunToolkit.awtUnlock(); - } - } - - // To be MT-safe this method should be called under awtLock. - boolean isOwner() { - return holder != null; - } - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - private void lostSelectionOwnership() { - if (holder != null) { - holder.lostSelectionOwnership(); - holder = null; - } - contents = null; - } - - native void clearNativeContext(); - - /* - * Subclasses should override disposeImpl() instead of dispose(). Client - * code should always invoke dispose(), never disposeImpl(). - */ - protected void disposeImpl() { - selections.removeElement(this); - } - - public final void dispose() { - boolean call_disposeImpl = false; - - if (!disposed) { - synchronized (this) { - if (!disposed) { - disposed = call_disposeImpl = true; - } - } - } - - if (call_disposeImpl) { - disposeImpl(); - } - } - - /** - * Finds out all selections that have flavor listeners registered - * and returns their atoms. - * Upcall from native code. - * - * @return an array of selection atoms - */ - private static long[] getSelectionAtomsToCheckChange() { - Object[] sels = getSelectionsArray(); - long[] idArray = new long[sels.length]; - int count = 0; - - for (int i = 0; i < sels.length; i++) { - X11Clipboard clipboard = ((X11Selection)sels[i]).clipboard; - if (clipboard.areFlavorListenersRegistered()) { - idArray[count++] = clipboard.getID(); - } - } - - long[] atomArray = new long[count]; - System.arraycopy(idArray, 0, atomArray, 0, atomArray.length); - - return atomArray; - } - - /** - * Upcall from native code. - */ - private void checkChange(long[] formats) { - clipboard.checkChange(formats); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/awt/motif/X11SelectionHolder.java --- a/jdk/src/solaris/classes/sun/awt/motif/X11SelectionHolder.java Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright 1996-1998 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 sun.awt.motif; - -interface X11SelectionHolder { - - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void lostSelectionOwnership(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java --- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Wed Jul 05 16:41:30 2017 +0200 @@ -69,11 +69,11 @@ static final int EPOLL_CTL_MOD = 3; // Miscellaneous constants - static final short SIZE_EPOLLEVENT = 12; - static final short EVENT_OFFSET = 0; - static final short DATA_OFFSET = 4; - static final short FD_OFFSET = 4; - static final int NUM_EPOLLEVENTS = Math.min(fdLimit(), 8192); + static final int SIZE_EPOLLEVENT = sizeofEPollEvent(); + static final int EVENT_OFFSET = 0; + static final int DATA_OFFSET = offsetofData(); + static final int FD_OFFSET = DATA_OFFSET; + static final int NUM_EPOLLEVENTS = Math.min(fdLimit(), 8192); // Base address of the native pollArray private final long pollArrayAddress; @@ -280,6 +280,8 @@ private native void epollCtl(int epfd, int opcode, int fd, int events); private native int epollWait(long pollAddress, int numfds, long timeout, int epfd) throws IOException; + private static native int sizeofEPollEvent(); + private static native int offsetofData(); private static native int fdLimit(); private static native void interrupt(int fd); private static native void init(); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h --- a/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h Wed Jul 05 16:41:30 2017 +0200 @@ -31,7 +31,9 @@ #include #include #include +#ifndef __linux__ #include +#endif #include #include #include diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/java/net/net_util_md.c --- a/jdk/src/solaris/native/java/net/net_util_md.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/java/net/net_util_md.c Wed Jul 05 16:41:30 2017 +0200 @@ -791,7 +791,7 @@ #endif /* AF_INET6 */ } -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { #ifdef AF_INET6 if (him->sa_family == AF_INET6) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Button.c --- a/jdk/src/solaris/native/sun/awt/awt_Button.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -/* - * Copyright 1995-2001 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" - -#include -#include -#include "multi_font.h" - -#include "awt_Component.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* - * When the -jni switch is thrown, these headers can be deleted. - */ -#include "java_awt_Button.h" -#include "sun_awt_motif_MButtonPeer.h" -#include "sun_awt_motif_MComponentPeer.h" - -/* fieldIDs for Button fields that may be accessed from C */ -static struct ButtonIDs { - jfieldID label; -} buttonIDs; - -static char emptyString[] = ""; - - -/* - * Class: java_awt_Button - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for Button.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_Button_initIDs - (JNIEnv *env, jclass cls) -{ - buttonIDs.label = - (*env)->GetFieldID(env, cls, "label", "Ljava/lang/String;"); -} - -/* - * client_data is MButtonPeer instance - */ -static void -Button_callback (Widget w, - XtPointer client_data, - XmPushButtonCallbackStruct * call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - ConvertEventTimeAndModifiers converted; - - awt_util_convertEventTimeAndModifiers(call_data->event, &converted); - - JNU_CallMethodByName(env, NULL, (jobject)client_data, "action", "(JI)V", - converted.when, converted.modifiers); - if ((*env)->ExceptionOccurred (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -/* - * Class: sun_awt_motif_MButtonPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MButtonPeer_create - (JNIEnv * env, jobject this, jobject parent) -{ - jobject target; - jobject label; - struct ComponentData *cdata; - struct ComponentData *wdata; - char *clabel; - Pixel bg; - XmString mfstr = NULL; - jobject globalRef = awtJNI_CreateAndSetGlobalRef (env, this); - jobject font = awtJNI_GetFont (env, this); - jboolean IsMultiFont = awtJNI_IsMultiFont (env, font); - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK (); - - if (JNU_IsNull (env, parent)) { - JNU_ThrowNullPointerException (env, "NullPointerException"); - AWT_UNLOCK (); - - return; - } - target = (*env)->GetObjectField (env, this, mComponentPeerIDs.target); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - - if (JNU_IsNull (env, target) || wdata == NULL) { - JNU_ThrowNullPointerException (env, "NullPointerException"); - AWT_UNLOCK (); - - return; - } - cdata = ZALLOC (ComponentData); - if (cdata == NULL) { - JNU_ThrowOutOfMemoryError (env, "OutOfMemoryError"); - AWT_UNLOCK (); - return; - } - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, cdata); - - adata = copyGraphicsConfigToPeer(env, this); - - XtVaGetValues (wdata->widget, XmNbackground, &bg, NULL); - - label = - (*env)->GetObjectField (env, target, buttonIDs.label); - - if (IsMultiFont) { - /* - * We don't use makeCString() function here. - * We create Motif multi-font compound string to display - * unicode on the platform which is not spporting unicode. - */ - if (JNU_IsNull (env, label) || ((*env)->GetStringLength (env, label) == 0)) { - mfstr = XmStringCreateLocalized (""); - } else { - mfstr = awtJNI_MakeMultiFontString (env, label, font); - } - - cdata->widget = XtVaCreateManagedWidget - ("", xmPushButtonWidgetClass, - wdata->widget, - XmNlabelString, mfstr, - XmNrecomputeSize, False, - XmNbackground, bg, - XmNhighlightOnEnter, False, - XmNshowAsDefault, 0, - XmNdefaultButtonShadowThickness, 0, - XmNmarginTop, 0, - XmNmarginBottom, 0, - XmNmarginLeft, 0, - XmNmarginRight, 0, - XmNuserData, (XtPointer) globalRef, - XmNscreen, ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen), - NULL); - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - - } else { - if (JNU_IsNull (env, label)) { - clabel = emptyString; - } else { - clabel = (char *) JNU_GetStringPlatformChars (env, label, NULL); - if (clabel == NULL) { /* Exception? */ - AWT_UNLOCK (); - return; - } - } - - cdata->widget = XtVaCreateManagedWidget - (clabel, xmPushButtonWidgetClass, - wdata->widget, - XmNrecomputeSize, False, - XmNbackground, bg, - XmNhighlightOnEnter, False, - XmNshowAsDefault, 0, - XmNdefaultButtonShadowThickness, 0, - XmNmarginTop, 0, - XmNmarginBottom, 0, - XmNmarginLeft, 0, - XmNmarginRight, 0, - XmNuserData, (XtPointer) globalRef, - XmNscreen, ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen), - NULL); - - if (clabel != emptyString) { - JNU_ReleaseStringPlatformChars (env, label, (const char *) clabel);; - } - } - - XtSetMappedWhenManaged (cdata->widget, False); - XtAddCallback (cdata->widget, - XmNactivateCallback, - (XtCallbackProc) Button_callback, - (XtPointer) globalRef); - - AWT_UNLOCK (); -} - -/* - * Class: sun_awt_motif_MButtonPeer - * Method: setLabel - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MButtonPeer_setLabel - (JNIEnv * env, jobject this, jstring label) -{ - struct ComponentData *wdata; - char *clabel; - XmString xim; - - AWT_LOCK (); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL) { - JNU_ThrowNullPointerException (env, "NullPointerException"); - AWT_UNLOCK (); - return; - } - if (JNU_IsNull (env, label) || ((*env)->GetStringLength (env, label) == 0)) { - xim = XmStringCreateLocalized (""); - } else { - jobject font = awtJNI_GetFont (env, this); - - if (awtJNI_IsMultiFont (env, font)) { - xim = awtJNI_MakeMultiFontString (env, label, font); - } else { - if (JNU_IsNull (env, label)) { - clabel = emptyString; - } else { - clabel = (char *) JNU_GetStringPlatformChars (env, label, NULL); - - if (clabel == NULL) { /* Exception? */ - AWT_UNLOCK (); - return; - } - } - - xim = XmStringCreate (clabel, "labelFont"); - - if (clabel != emptyString) { - JNU_ReleaseStringPlatformChars (env, label, (const char *) clabel);; - } - } - } - - XtVaSetValues (wdata->widget, XmNlabelString, xim, NULL); - XmStringFree (xim); - AWT_FLUSH_UNLOCK (); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Canvas.c --- a/jdk/src/solaris/native/sun/awt/awt_Canvas.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright 1995-2002 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. - */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_Canvas.h" -#include "sun_awt_motif_MCanvasPeer.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "color.h" -#include "canvas.h" -#include "awt_util.h" - -#include "awt_Component.h" -#include "awt_GraphicsEnv.h" - -#include -#include -#include "multi_font.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); -struct CanvasIDs mCanvasIDs; - -/* - * Class: sun_awt_motif_MCanvasPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCanvasPeer_create - (JNIEnv * env, jobject this, jobject parent) -{ - AwtGraphicsConfigDataPtr awtData; - - struct CanvasData *wdata; - struct CanvasData *cdata; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - - AWT_LOCK(); - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - cdata = (struct CanvasData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - if (cdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - wdata = ZALLOC(CanvasData); - if (wdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, wdata); - - awtData = copyGraphicsConfigToPeer(env, this); - - wdata->comp.widget = awt_canvas_create((XtPointer) globalRef, - cdata->comp.widget, - "", - 1, 1, False, NULL, awtData); - XtVaSetValues(wdata->comp.widget, - XmNinsertPosition, awt_util_insertCallback, - NULL); - - /* Add an event handler so that we can track focus change requests - which will be initiated by Motif in response to ButtonPress events */ - - wdata->flags = 0; - wdata->shell = cdata->shell; - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCanvasPeer - * Method: resetTargetGC - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCanvasPeer_resetTargetGC -(JNIEnv * env, jobject this, jobject target) -{ - (*env)->CallVoidMethod(env, target, mCanvasIDs.setGCFromPeerMID); -} - -/* - * Class: sun_awt_motif_MCanvasPeer - * Method: initIDs - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCanvasPeer_initIDs -(JNIEnv * env, jclass cls) -{ - jclass canvasCls = (*env)->FindClass(env, "java/awt/Canvas"); - mCanvasIDs.setGCFromPeerMID = - (*env)->GetMethodID(env, canvasCls, "setGCFromPeer","()V"); - - DASSERT(mCanvasIDs.setGCFromPeerMID); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Checkbox.c --- a/jdk/src/solaris/native/sun/awt/awt_Checkbox.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* - * Copyright 1995-2002 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MCheckboxPeer.h" -#include "java_awt_Checkbox.h" -#include "java_awt_CheckboxGroup.h" - -#include "awt_Component.h" - -#include "multi_font.h" -#include -#include - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* fieldIDs for Checkbox fields that may be accessed from C */ -static struct CheckboxIDs { - jfieldID label; -} checkboxIDs; - -static char emptyString[] = ""; - - -/* - * Class: java_awt_Checkbox - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for Checkbox.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_Checkbox_initIDs - (JNIEnv *env, jclass cls) -{ - checkboxIDs.label = - (*env)->GetFieldID(env, cls, "label", "Ljava/lang/String;"); -} - -/* - * client_data is MCheckboxPeer instance pointer - */ -static void -Toggle_callback(Widget w, - XtPointer client_data, - XmAnyCallbackStruct * call_data) -{ - Boolean state; - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - XtVaGetValues(w, XmNset, &state, NULL); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, "action", "(Z)V", state); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCheckboxPeer_create - (JNIEnv * env, jobject this, jobject parent) -{ - jobject target; - struct ComponentData *bdata; - struct ComponentData *wdata; - char *clabel; -#define MAX_ARGC 10 - Arg args[MAX_ARGC]; - Cardinal argc; - jobject label; - XmString mfstr = NULL; - jobject font = awtJNI_GetFont(env, this); - jboolean isMultiFont = awtJNI_IsMultiFont(env, font); - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - XmFontList fontlist = NULL; - Dimension height; - Boolean labelIsEmpty = FALSE; - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - - if (JNU_IsNull(env, target) || wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - bdata = ZALLOC(ComponentData); - if (bdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - - return; - } - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, bdata); - - adata = copyGraphicsConfigToPeer(env, this); - - argc = 0; - XtSetArg(args[argc], XmNrecomputeSize, False); - argc++; - XtSetArg(args[argc], XmNvisibleWhenOff, True); - argc++; - XtSetArg(args[argc], XmNtraversalOn, True); - argc++; - XtSetArg(args[argc], XmNspacing, 0); - argc++; - XtSetArg(args[argc], XmNuserData, (XtPointer) globalRef); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - - label = (*env)->GetObjectField(env, target, checkboxIDs.label); - - // fix for 4383735. - // If the label is empty we need to set the indicator size - // proportional to the size of the font. - // kdm@sparc.spb.su - if (JNU_IsNull(env, label) || ((*env)->GetStringLength(env, label) == 0)) { - labelIsEmpty = TRUE; - if (!JNU_IsNull(env, font)) { - mfstr = XmStringCreateLocalized(" "); - if (mfstr != NULL) { - fontlist = awtJNI_GetFontList(env, font); - if (fontlist != NULL) { - height = XmStringHeight(fontlist, mfstr); - XtSetArg(args[argc], XmNindicatorSize, height); - argc++; - XmFontListFree(fontlist); - fontlist = NULL; - } - XmStringFree(mfstr); - mfstr = NULL; - } - } - } - - if (isMultiFont) { - /* - * We don't use makeCString() function here. - * We create Motif multi-font compound string to display - * unicode on the platform which is not spporting unicode. - */ - if (labelIsEmpty) { - mfstr = XmStringCreateLocalized(""); - } else { - mfstr = awtJNI_MakeMultiFontString(env, label, font); - } - - XtSetArg(args[argc], XmNlabelString, mfstr); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - bdata->widget = XmCreateToggleButton(wdata->widget, "", args, argc); - - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - } else { - if (labelIsEmpty) { - clabel = emptyString; - } else { - clabel = (char *) JNU_GetStringPlatformChars(env, label, NULL); - - if (clabel == NULL) { /* Exception? */ - AWT_UNLOCK(); - return; - } - } - - DASSERT(!(argc > MAX_ARGC)); - bdata->widget = XmCreateToggleButton(wdata->widget, clabel, args, argc); - - if (clabel != emptyString) { - JNU_ReleaseStringPlatformChars(env, label, (const char *) clabel);; - } - } - - XtAddCallback(bdata->widget, - XmNvalueChangedCallback, - (XtCallbackProc) Toggle_callback, - (XtPointer) globalRef); - - XtSetMappedWhenManaged(bdata->widget, False); - XtManageChild(bdata->widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: setLabel - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCheckboxPeer_setLabel - (JNIEnv * env, jobject this, jstring label) -{ - struct ComponentData *wdata; - char *clabel; - XmString xim; - jobject font; - - AWT_LOCK(); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, label) || ((*env)->GetStringLength(env, label) == 0)) { - xim = XmStringCreateLocalized(""); - } else { - font = awtJNI_GetFont(env, this); - - if (awtJNI_IsMultiFont(env, font)) { - xim = awtJNI_MakeMultiFontString(env, label, font); - } else { - clabel = (char *) JNU_GetStringPlatformChars(env, label, NULL); - - if (clabel == NULL) { - AWT_UNLOCK(); - return; - } - xim = XmStringCreate(clabel, "labelFont"); - - JNU_ReleaseStringPlatformChars(env, label, (const char *) clabel);; - } - } - - XtVaSetValues(wdata->widget, XmNlabelString, xim, NULL); - XmStringFree(xim); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: pSetState - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCheckboxPeer_pSetState - (JNIEnv * env, jobject this, jboolean state) -{ - struct ComponentData *bdata; - - AWT_LOCK(); - - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(bdata->widget, XmNset, (Boolean) state, NULL); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: pGetState - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL Java_sun_awt_motif_MCheckboxPeer_pGetState - (JNIEnv * env, jobject this) -{ - struct ComponentData *bdata; - Boolean state; - - AWT_LOCK(); - - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return JNI_FALSE; - } - XtVaGetValues(bdata->widget, XmNset, &state, NULL); - AWT_FLUSH_UNLOCK(); - return ((state) ? JNI_TRUE : JNI_FALSE); -} - - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: setCheckboxGroup - * Signature: (Ljava/awt/CheckboxGroup;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCheckboxPeer_setCheckboxGroup - (JNIEnv * env, jobject this, jobject group) -{ - struct ComponentData *bdata; - - AWT_LOCK(); - - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, group)) { - XtVaSetValues(bdata->widget, - XmNindicatorType, XmN_OF_MANY, - NULL); - } else { - XtVaSetValues(bdata->widget, - XmNindicatorType, XmONE_OF_MANY, - NULL); - } - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: getIndicatorSize - * Signature: (V)I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MCheckboxPeer_getIndicatorSize - (JNIEnv * env, jobject this) -{ - struct ComponentData *wdata; - Dimension size; - - AWT_LOCK(); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "Null pData"); - AWT_UNLOCK(); - return 0; - } - XtVaGetValues(wdata->widget, - XmNindicatorSize, &size, - NULL); - - AWT_FLUSH_UNLOCK(); - - return size; -} - -/* - * Class: sun_awt_motif_MCheckboxPeer - * Method: getSpacing - * Signature: (V)I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MCheckboxPeer_getSpacing - (JNIEnv * env, jobject this) -{ - struct ComponentData *wdata; - Dimension dim; - - AWT_LOCK(); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "Null pData"); - AWT_UNLOCK(); - return 0; - } - XtVaGetValues(wdata->widget, - XmNspacing, &dim, - NULL); - - AWT_FLUSH_UNLOCK(); - - return dim; -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Choice12.c --- a/jdk/src/solaris/native/sun/awt/awt_Choice12.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,843 +0,0 @@ -/* - * Copyright 1995-2001 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_Component.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MChoicePeer.h" - -#include "awt_Component.h" -#include "awt_MToolkit.h" - -#include "multi_font.h" -#include -#include -#include - -extern struct ComponentIDs componentIDs; -extern struct ContainerIDs containerIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -static void geometry_hook(Widget wid, Widget hooked_widget, XtGeometryHookData call_data) { - XtWidgetGeometry *request; - JNIEnv *env; - struct ChoiceData *cdata; - struct WidgetInfo *winfo = NULL; - - jobject target; - jobject parent; - jint y, height; - - if ((call_data->widget == hooked_widget) && - (call_data->type == XtHpostGeometry) && - (call_data->result == XtGeometryYes)) { - - request = call_data->request; - - env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - DASSERT(env != NULL); - - winfo=findWidgetInfo(hooked_widget); - - if (winfo != NULL && XmIsRowColumn(hooked_widget)) { - target = (*env)->GetObjectField(env, (jobject)winfo->peer, mComponentPeerIDs.target); - cdata = (struct ChoiceData *) JNU_GetLongFieldAsPtr(env, (jobject)winfo->peer, mComponentPeerIDs.pData); - DASSERT(target != NULL); - DASSERT(cdata != NULL && cdata->comp.widget != NULL) - if (request->request_mode & CWHeight) { - height = (*env)->GetIntField(env, target, componentIDs.height); - if (request->height > 0 && request->height != height) { - parent = (*env)->CallObjectMethod(env, target, componentIDs.getParent); - if ((parent != NULL) && ((*env)->GetObjectField(env, parent, containerIDs.layoutMgr) != NULL)) { - y = cdata->bounds_y; - if (request->height < cdata->bounds_height) { - y += (cdata->bounds_height - request->height) / 2; - } - XtVaSetValues(hooked_widget, XmNy, y, NULL); - (*env)->SetIntField(env, target, componentIDs.y, y); - } - if (parent != NULL) { - (*env)->DeleteLocalRef(env, parent); - } - } - (*env)->SetIntField(env, target, componentIDs.height, request->height); - } - if (request->request_mode & CWWidth) { - (*env)->SetIntField(env, target, componentIDs.width, request->width); - } - (*env)->DeleteLocalRef(env, target); - } - } -} - -static void -Choice_callback(Widget menu_item, - jobject this, - XmAnyCallbackStruct * cbs) -{ - intptr_t index; - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - XtVaGetValues(menu_item, XmNuserData, &index, NULL); - /* index stored in user-data is 1-based instead of 0-based because */ - /* of a bug in XmNuserData */ - index--; - - JNU_CallMethodByName(env, NULL, this, "action", "(I)V", (jint)index); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -static void addItems - (JNIEnv *env, jobject this, jstring *items, jsize nItems, jint index) -{ - char *citem = NULL; - struct ChoiceData *odata; - Widget bw; -#define MAX_ARGC 10 - Arg args[MAX_ARGC]; - Cardinal argc, argc1; - jsize i; - Pixel bg; - Pixel fg; - short cols; - int32_t sheight; - Dimension height; - Widget *firstNewItem = NULL; - - XmString mfstr = NULL; - XmFontList fontlist = NULL; - jobject font = awtJNI_GetFont(env, this); - Boolean IsMultiFont = awtJNI_IsMultiFont(env, font); - - if ((items == NULL) || (nItems == 0)) { - return; - } - - AWT_LOCK(); - - odata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (odata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - if (odata->maxitems == 0 || (index + nItems) > odata->maxitems) { - odata->maxitems = index + nItems + 20; - if (odata->n_items > 0) { - /* grow the list of items */ - odata->items = (Widget *) - realloc((void *) (odata->items) - ,sizeof(Widget) * odata->maxitems); - } else { - odata->items = (Widget *) malloc(sizeof(Widget) * odata->maxitems); - } - if (odata->items == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - } - XtVaGetValues(odata->comp.widget, XmNbackground, &bg, NULL); - XtVaGetValues(odata->comp.widget, XmNforeground, &fg, NULL); - - argc = 0; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - - firstNewItem = &(odata->items[index]); - for (i = 0; i < nItems; i++) { - argc1 = argc; - if (IsMultiFont) { - mfstr = awtJNI_MakeMultiFontString(env, items[i], font); - fontlist = awtJNI_GetFontList(env, font); - /* XXX: XmNuserData doesn't seem to work when passing in zero */ - /* so we increment the index before passing it in. */ - XtSetArg(args[argc1], XmNuserData, (XtPointer)((intptr_t)(index + i + 1))); - argc1++; - XtSetArg(args[argc1], XmNfontList, fontlist); - argc1++; - XtSetArg(args[argc1], XmNlabelString, mfstr); - argc1++; - - DASSERT(!(argc1 > MAX_ARGC)); - - bw = XmCreatePushButton(odata->menu, "", args, argc1); - - /* Free resurces */ - if ( fontlist != NULL ) - { - XmFontListFree(fontlist); - fontlist = NULL; - } - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - } else { - citem = (char *) JNU_GetStringPlatformChars(env, items[i], NULL); - /* XXX: XmNuserData doesn't seem to work when passing in zero */ - /* so we increment the index before passing it in. */ - XtSetArg(args[argc1], XmNuserData, (XtPointer)((intptr_t)(index + i + 1))); - argc1++; - DASSERT(!(argc1> MAX_ARGC)); - bw = XmCreatePushButton(odata->menu, citem, args, argc1); - JNU_ReleaseStringPlatformChars(env, items[i], (const char *) citem); - citem = NULL; - } - - XtAddCallback(bw, - XmNactivateCallback, - (XtCallbackProc) Choice_callback, - (XtPointer) JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.jniGlobalRef)); - odata->items[index + i] = bw; - odata->n_items++; - } - - XtManageChildren(firstNewItem, nItems); - - sheight = DisplayHeight(awt_display, DefaultScreen(awt_display)); - - XtVaGetValues(odata->menu, XmNheight, &height, NULL); - - while ( height > sheight ) { - cols = ++odata->n_columns; - XtVaSetValues(odata->menu, XmNnumColumns, cols, NULL); - XtVaGetValues(odata->menu, XmNheight, &height, NULL); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_create - (JNIEnv * env, jobject this, jobject parent) -{ - struct ChoiceData *odata; - struct ComponentData *wdata; -#undef MAX_ARGC -#define MAX_ARGC 30 - Arg args[MAX_ARGC]; - Cardinal argc; - Pixel bg; - Pixel fg; - Widget label; - Widget button; - Widget hookobj; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - jobject target; - Dimension width = 0, height = 0; - jclass clsDimension; - jobject dimension; - jobject peer; - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - adata = copyGraphicsConfigToPeer(env, this); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - - odata = ZALLOC(ChoiceData); - if (odata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,odata); - - odata->items = NULL; - odata->maxitems = 0; - odata->n_items = 0; - odata->n_columns = 1; - - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - XtVaGetValues(wdata->widget, XmNforeground, &fg, NULL); - - argc = 0; - XtSetArg(args[argc], XmNx, 0); - argc++; - XtSetArg(args[argc], XmNy, 0); - argc++; - XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - - XtSetArg(args[argc], XmNorientation, XmVERTICAL); - argc++; - XtSetArg(args[argc], XmNpacking, XmPACK_COLUMN); - argc++; - XtSetArg(args[argc], XmNnumColumns, (short)1); - argc++; - /* Fix for 4303064 by ibd@sparc.spb.su: pop-up shells will have - * ancestor_sensitive False if the parent was insensitive when the shell - * was created. Since XtSetSensitive on the parent will not modify the - * resource of the pop-up child, clients are advised to include a resource - * specification of the form '*TransientShell.ancestorSensitive: True' in - * the application defaults resource file or to otherwise ensure that the - * parent is sensitive when creating pop-up shells. - */ - XtSetArg(args[argc], XmNancestorSensitive, True); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - odata->menu = XmCreatePulldownMenu(wdata->widget, "pulldown", args, argc); - - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - clsDimension = (*env)->FindClass(env, "java/awt/Dimension"); - dimension = JNU_CallMethodByName(env, - NULL, - this, - "getPreferredSize", - "()Ljava/awt/Dimension;").l; - DASSERT(clsDimension != NULL); - width = (Dimension)((*env)->GetIntField(env, dimension, (*env)->GetFieldID(env, clsDimension, "width" , "I"))); - height = (Dimension)((*env)->GetIntField(env, dimension, (*env)->GetFieldID(env, clsDimension, "height", "I"))); - - argc = 0; - XtSetArg(args[argc], XmNx, 0); - argc++; - XtSetArg(args[argc], XmNy, 0); - argc++; - XtSetArg(args[argc], XmNwidth, width); - argc++; - XtSetArg(args[argc], XmNheight, height); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNrecomputeSize, False); - argc++; - XtSetArg(args[argc], XmNresizeHeight, False); - argc++; - XtSetArg(args[argc], XmNresizeWidth, False); - argc++; - XtSetArg(args[argc], XmNspacing, False); - argc++; - XtSetArg(args[argc], XmNborderWidth, 0); - argc++; - XtSetArg(args[argc], XmNnavigationType, XmTAB_GROUP); - argc++; - XtSetArg(args[argc], XmNtraversalOn, True); - argc++; - XtSetArg(args[argc], XmNorientation, XmVERTICAL); - argc++; - XtSetArg(args[argc], XmNadjustMargin, False); - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - XtSetArg(args[argc], XmNsubMenuId, odata->menu); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, adata->awt_visInfo.screen)); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - odata->comp.widget = XmCreateOptionMenu(wdata->widget, "", args, argc); - - hookobj = XtHooksOfDisplay(XtDisplayOfObject(odata->comp.widget)); - XtAddCallback(hookobj, - XtNgeometryHook, - (XtCallbackProc) geometry_hook, - (XtPointer) odata->comp.widget); - - label = XmOptionLabelGadget(odata->comp.widget); - if (label != NULL) { - XtUnmanageChild(label); - } - XtSetMappedWhenManaged(odata->comp.widget, False); - XtManageChild(odata->comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: addItem - * Signature: (Ljava/lang/String;I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_addItem - (JNIEnv *env, jobject this, jstring item, jint index) -{ - if (JNU_IsNull(env, item)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - addItems(env, this, &item, 1, index); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: pSelect - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_pSelect - (JNIEnv *env, jobject this, jint index, jboolean init) -{ - struct ChoiceData *odata; - - AWT_LOCK(); - - odata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (odata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (index > odata->n_items || index < 0) { - JNU_ThrowIllegalArgumentException(env, "IllegalArgumentException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(odata->comp.widget, - XmNmenuHistory, odata->items[index], - NULL); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_setFont - (JNIEnv *env, jobject this, jobject f) -{ - struct ChoiceData *cdata; - struct FontData *fdata; - XmFontList fontlist; - char *err; - - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - fdata = awtJNI_GetFontData(env, f, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(env, err); - AWT_UNLOCK(); - return; - } - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (awtJNI_IsMultiFont(env, f)) { - fontlist = awtJNI_GetFontList(env, f); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - - if (fontlist != NULL) { - jint i; - - XtVaSetValues(cdata->comp.widget, - XmNfontList, fontlist, - NULL); - XtVaSetValues(cdata->menu, - XmNfontList, fontlist, - NULL); - for (i = 0; i < cdata->n_items; i++) { - XtVaSetValues(cdata->items[i], - XmNfontList, fontlist, - NULL); - } - - XmFontListFree(fontlist); - } else { - JNU_ThrowNullPointerException(env, "NullPointerException"); - } - AWT_UNLOCK(); -} - -/* Fix for bug 4326619 */ -/* - * Class: sun_awt_motif_MChoicePeer - * Method: freeNativeData - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_freeNativeData - (JNIEnv *env, jobject this) -{ - struct ChoiceData *cdata; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - cdata->n_items = 0; - free((void *)cdata->items); - cdata->items = NULL; - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_setBackground - (JNIEnv *env, jobject this, jobject c) -{ - struct ChoiceData *bdata; - Pixel bg; - Pixel fg; - WidgetList children; - Cardinal numChildren; - int32_t i; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException: null color"); - return; - } - AWT_LOCK(); - - bdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* Get background color */ - bg = awtJNI_GetColor(env, c); - - /* - XmChangeColor(), in addtion to changing the background and - selection colors, also changes the foreground color to be - what it thinks should be. However, we want to use the color - that gets set by setForeground() instead. We therefore need to - save the current foreground color here, and then set it again - after the XmChangeColor() occurs. - */ - XtVaGetValues(bdata->comp.widget, XmNforeground, &fg, NULL); - - /* Set color */ - XmChangeColor(bdata->comp.widget, bg); - XtVaSetValues(bdata->comp.widget, XmNforeground, fg, NULL); - - /* - * The following recursion fixes a bug in Motif 2.1 that caused - * black colored choice buttons (change has no effect on Motif 1.2). - */ - XtVaGetValues(bdata->comp.widget, - XmNchildren, &children, - XmNnumChildren, &numChildren, - NULL); - for (i = 0; i < numChildren; i++) { - XmChangeColor(children[i], bg); - XtVaSetValues(children[i], XmNforeground, fg, NULL); - } - - - XmChangeColor(bdata->menu, bg); - XtVaSetValues(bdata->menu, XmNforeground, fg, NULL); - - for (i = 0; i < bdata->n_items; i++) { - XmChangeColor(bdata->items[i], bg); - XtVaSetValues(bdata->items[i], XmNforeground, fg, NULL); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setForeground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_setForeground - (JNIEnv *env, jobject this, jobject c) -{ - struct ChoiceData *bdata; - Pixel color; - int32_t i; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException: null color"); - return; - } - AWT_LOCK(); - - bdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - color = awtJNI_GetColor(env, c); - - XtVaSetValues(bdata->comp.widget, XmNforeground, color, NULL); - - XtVaSetValues(bdata->menu, XmNforeground, color, NULL); - for (i = 0; i < bdata->n_items; i++) { - XtVaSetValues(bdata->items[i], XmNforeground, color, NULL); - } - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: pReshape - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_pReshape - (JNIEnv *env, jobject this, jint x, jint y, jint w, jint h) -{ - struct ChoiceData *cdata; - Widget button; - jobject target; - Dimension width=0, height=0; - Position new_y = 0; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - button = XmOptionButtonGadget(cdata->comp.widget); - cdata->bounds_y = y; - cdata->bounds_height = h; - awt_util_reshape(cdata->comp.widget, x, y, w, h); - awt_util_reshape(button, x, y, w, h); - - /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match - * actual size - */ - XtVaGetValues(cdata->comp.widget, XmNy, &new_y, NULL); - XtVaGetValues(button, XmNwidth, &width, XmNheight, &height , NULL); - awt_util_reshape(cdata->comp.widget, x, new_y, width, height); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: remove - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_remove - (JNIEnv *env, jobject this, jint index) -{ - struct ChoiceData *cdata; - Widget selected; - jint i; - short cols; - int32_t sheight; - Dimension height; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (index < 0 || index > cdata->n_items) { - JNU_ThrowIllegalArgumentException(env, "IllegalArgumentException"); - AWT_UNLOCK(); - return; - } - XtUnmanageChild(cdata->items[index]); - awt_util_consumeAllXEvents(cdata->items[index]); - awt_util_cleanupBeforeDestroyWidget(cdata->items[index]); - XtDestroyWidget(cdata->items[index]); - for (i = index; i < cdata->n_items-1; i++) { - cdata->items[i] = cdata->items[i + 1]; - /* need to reset stored index value, (adding 1 to disambiguate it */ - /* from an arg list terminator) */ - /* bug fix 4079027 robi.khan@eng */ - XtVaSetValues(cdata->items[i], XmNuserData, (XtPointer)((intptr_t)(i+1)), NULL); - } - cdata->items[cdata->n_items-1] = NULL; - cdata->n_items--; - - XtVaGetValues(cdata->menu, XmNheight, &height, NULL); - - sheight = DisplayHeight(awt_display, DefaultScreen(awt_display)); - cols = cdata->n_columns; - - if (cols >1) { - /* first try to remove a column */ - cols = --cdata->n_columns; - XtVaSetValues(cdata->menu, XmNnumColumns, cols, NULL); - - /* then see if it fits, if not add it back */ - XtVaGetValues(cdata->menu, XmNheight, &height, NULL); - if ( height > sheight ) { - cols = ++cdata->n_columns; - XtVaSetValues(cdata->menu, XmNnumColumns, cols, NULL); - } - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: removeAll - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_removeAll - (JNIEnv *env, jobject this) -{ - struct ChoiceData *cdata; - Widget selected; - jint i; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - XtUnmanageChildren(cdata->items, cdata->n_items); - - for (i = cdata->n_items-1; i >= 0; i--) { - awt_util_consumeAllXEvents(cdata->items[i]); - awt_util_cleanupBeforeDestroyWidget(cdata->items[i]); - XtDestroyWidget(cdata->items[i]); - cdata->items[i] = NULL; - } - - cdata->n_items = 0; - - if (cdata->n_columns > 1) { - cdata->n_columns = 1; - XtVaSetValues(cdata->menu, XmNnumColumns, cdata->n_columns, NULL); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: appendItems - * Signature: ([Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MChoicePeer_appendItems - (JNIEnv *env, jobject this, jarray items) -{ - struct ChoiceData *odata = NULL; - jstring *strItems = NULL; - jsize nItems, i; // MP - - if (JNU_IsNull(env, items)) { - return; - } - nItems = (*env)->GetArrayLength(env, items); - if (nItems == 0) { - return; - } - - AWT_LOCK(); - - odata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (odata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - - strItems = (jstring *) malloc(sizeof(jstring) * nItems); - if (strItems == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - - for (i = 0; i < nItems; i++) { - strItems[i] = (jstring)(*env)->GetObjectArrayElement(env, items, i); - if (JNU_IsNull(env, strItems[i])) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - } - - addItems(env, this, strItems, nItems, odata->n_items); - -cleanup: - if (strItems != NULL) { - free(strItems); - } - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Choice21.c --- a/jdk/src/solaris/native/sun/awt/awt_Choice21.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,764 +0,0 @@ -/* - * Copyright 2001-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#if MOTIF_VERSION!=2 - #error This file should only be compiled with motif 2.1 -#endif - -#include "awt_p.h" -#include "java_awt_Component.h" -#include "java_awt_AWTEvent.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MChoicePeer.h" - -#include "awt_Component.h" -#include "canvas.h" - -#include "multi_font.h" - -#include -#include -#include - -#define MAX_VISIBLE 10 - -extern struct ComponentIDs componentIDs; -extern struct ContainerIDs containerIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; - -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* - setSelection - Set the selected text on the XmTextField of the XmComboBox. -*/ -static void -setSelection(JNIEnv *env, - jobject this, - Widget comboBox, - jint index) -{ - jstring item = NULL; - jobject target; - Widget text=NULL; - - AWT_LOCK(); - /* Get the java Choice component. */ - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - if (target == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* Get the XmTextField widget in the XmComboBox. */ - text = XtNameToWidget(comboBox, "*Text"); - /* Get the selected Unicode string from the java Choice component. */ - item = (jstring) JNU_CallMethodByName(env, NULL, - target, "getItem", "(I)Ljava/lang/String;", index).l; - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (!JNU_IsNull(env, item)) { - /* Convert the Unicode string to a multibyte string. */ - char *temp = (char *)JNU_GetStringPlatformChars(env, item, NULL); - /* Assign the multibyte string to the XmTextField of the XmComboBox. */ - XmTextSetString(text, temp); - JNU_ReleaseStringPlatformChars(env, item, (const char *)temp); - } - AWT_UNLOCK(); -} - -extern Boolean skipNextNotifyWhileGrabbed; -extern Boolean skipNextFocusIn; - -static void -GrabShellPopup(Widget grab_shell, - jobject this, - XmAnyCallbackStruct * call_data) -{ - skipNextNotifyWhileGrabbed = True; -} -static void -GrabShellPopdown(Widget grab_shell, - jobject this, - XmAnyCallbackStruct * call_data) -{ - skipNextNotifyWhileGrabbed = True; - skipNextFocusIn = True; -} - -static void -Choice_callback(Widget list, - jobject this, - XmAnyCallbackStruct * call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data; - struct ChoiceData *cdata; - - - AWT_LOCK(); - /* Get the Choice data. */ - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - setSelection(env, this, cdata->comp.widget, cbs->item_position - 1); - /* Get the Choice data. */ - JNU_CallMethodByName(env, NULL, - this, "action", "(I)V", cbs->item_position - 1); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - AWT_UNLOCK(); -} - -static void -addItems(JNIEnv *env, jobject this, - jstring *items, int32_t nItems, jint index) -{ - struct ChoiceData *cdata; - int32_t i; - Widget list; - XmString mfstr = NULL; - XmFontList fontlist = NULL; - jobject font = awtJNI_GetFont(env, this); - Boolean IsMultiFont = awtJNI_IsMultiFont(env, font); - - if ((items == NULL) || (nItems == 0)) { - return; - } - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (cdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - for (i = 0; i < nItems; ++i) { - char *temp = (char *)JNU_GetStringPlatformChars(env, items[i], NULL); - mfstr = XmStringCreateLocalized(temp); - JNU_ReleaseStringPlatformChars(env, items[i], (const char *)temp); - XmComboBoxAddItem(cdata->comp.widget, mfstr, index + i + 1, FALSE); - - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - } - - cdata->n_items += nItems; - - list = XtNameToWidget(cdata->comp.widget, "*List"); - XtVaSetValues(list, - XmNvisibleItemCount, min(MAX_VISIBLE, cdata->n_items), - NULL); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_create(JNIEnv * env, jobject this, - jobject parent) -{ - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - - struct ComponentData *wdata; /* parent's peer data */ - struct ChoiceData *cdata; /* our own peer data */ - Widget list, text, list_shell; /* components of drop dowwn list widget */ - - AwtGraphicsConfigDataPtr adata; - Pixel fg, bg; /* colors inherited from parent */ - Dimension width = 0, height = 0; - jclass clsDimension; - jobject dimension; - -#undef MAX_ARGC -#define MAX_ARGC 30 - Arg args[MAX_ARGC]; - int32_t argc; - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - /* get parent's peer data */ - wdata = (struct ComponentData *)JNU_GetLongFieldAsPtr(env, - parent, mComponentPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - /* create our own peer data */ - cdata = ZALLOC(ChoiceData); - if (cdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, cdata); - - /* get desired size */ - clsDimension = (*env)->FindClass(env, "java/awt/Dimension"); - DASSERT(clsDimension != NULL); - - dimension = JNU_CallMethodByName(env, NULL, - this, "getPreferredSize", "()Ljava/awt/Dimension;").l; - width = (Dimension)((*env)->GetIntField(env, dimension, - (*env)->GetFieldID(env, clsDimension, - "width" , "I"))); - height = (Dimension)((*env)->GetIntField(env, dimension, - (*env)->GetFieldID(env, clsDimension, - "height", "I"))); - - /* Inherit visual/colors from parent component */ - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - XtVaGetValues(wdata->widget, XmNforeground, &fg, NULL); - adata = copyGraphicsConfigToPeer(env, this); - - argc = 0; - XtSetArg(args[argc], XmNuserData, (XtPointer)globalRef); ++argc; - XtSetArg(args[argc], XmNx, 0); ++argc; - XtSetArg(args[argc], XmNy, 0); ++argc; - XtSetArg(args[argc], XmNmarginHeight, 2); ++argc; - XtSetArg(args[argc], XmNmarginWidth, 1); ++argc; - XtSetArg(args[argc], XmNvisibleItemCount, 0); ++argc; - XtSetArg(args[argc], XmNancestorSensitive, True); ++argc; - /* Don't ding on key press */ - XtSetArg(args[argc], XmNverifyBell, False); ++argc; - XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); ++argc; - XtSetArg(args[argc], XmNscreen, - ScreenOfDisplay(awt_display, adata->awt_visInfo.screen)); ++argc; - XtSetArg(args[argc], XmNbackground, bg); ++argc; - XtSetArg(args[argc], XmNforeground, fg); ++argc; - - DASSERT(!(argc > MAX_ARGC)); - cdata->comp.widget = XmCreateDropDownList(wdata->widget, - "combobox", args, argc); - cdata->n_items = 0; - - list = XtNameToWidget(cdata->comp.widget, "*List"); - text = XtNameToWidget(cdata->comp.widget, "*Text"); - list_shell = XtNameToWidget(cdata->comp.widget, "*GrabShell"); - XtAddCallback(list_shell, - XmNpopupCallback, - (XtCallbackProc)GrabShellPopup, - globalRef); - XtAddCallback(list_shell, - XmNpopdownCallback, - (XtCallbackProc)GrabShellPopdown, - globalRef); - - /* - * Bug 4477410: Setting the width of the XmComboBox made the XmTextField - * too small, cutting off the dropdown list knob on the right side. Set - * the width of the TextField because it is the widget actually seen. - */ - /* Set the width and height of the TextField widget. */ - XtVaSetValues(text, - XmNwidth, width, - XmNheight, height, - NULL); - - XtAddCallback(list, - XmNbrowseSelectionCallback, - (XtCallbackProc)Choice_callback, - (XtPointer)globalRef); - - XtAddEventHandler(text, FocusChangeMask, True, - awt_canvas_event_handler, globalRef); - - awt_addWidget(text, cdata->comp.widget, globalRef, - java_awt_AWTEvent_KEY_EVENT_MASK - | java_awt_AWTEvent_MOUSE_EVENT_MASK - | java_awt_AWTEvent_MOUSE_MOTION_EVENT_MASK); - - XtSetMappedWhenManaged(cdata->comp.widget, False); - XtManageChild(cdata->comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: pSelect - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_pSelect(JNIEnv *env, jobject this, - jint index, jboolean init) -{ - struct ChoiceData *cdata; - Widget list; - - AWT_LOCK(); - - cdata = (struct ChoiceData *)JNU_GetLongFieldAsPtr(env, - this, mComponentPeerIDs.pData); - if (cdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - list = XtNameToWidget(cdata->comp.widget, "*List"); - - XmListDeselectAllItems(list); - XmListSelectPos(list, index + 1, False); - setSelection(env, this, cdata->comp.widget, index); - XmComboBoxUpdate(cdata->comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_setFont(JNIEnv *env, jobject this, - jobject f) -{ - struct ChoiceData *cdata; - struct FontData *fdata; - XmFontList fontlist; - Widget list; - Widget text; - char *err; - XmFontListEntry fontentry; - Position x=0, y=0; - - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - fdata = awtJNI_GetFontData(env, f, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(env, err); - AWT_UNLOCK(); - return; - } - - cdata = (struct ChoiceData *)JNU_GetLongFieldAsPtr(env, - this, mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - /* Make a fontset and set it. */ - if (awtJNI_IsMultiFont(env, f)) { - if (fdata->xfs == NULL) { - fdata->xfs = awtJNI_MakeFontSet(env, f); - } - if (fdata->xfs != NULL) { - fontentry = XmFontListEntryCreate("labelFont", - XmFONT_IS_FONTSET, - (XtPointer) (fdata->xfs)); - fontlist = XmFontListAppendEntry(NULL, fontentry); - /* - * Some versions of motif have a bug in - * XmFontListEntryFree() which causes it to free more than it - * should. Use XtFree() instead. See O'Reilly's - * Motif Reference Manual for more information. - */ - XmFontListEntryFree(&fontentry); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - XtVaSetValues(cdata->comp.widget, - XmNfontList, fontlist, - NULL); - list = XtNameToWidget(cdata->comp.widget, "*List"); - XtVaSetValues(list, - XmNfontList, fontlist, - NULL); - - text = XtNameToWidget(cdata->comp.widget, "*Text"); - XtVaSetValues(text, - XmNfontList, fontlist, - NULL); - XmFontListFree(fontlist); - XtVaGetValues(cdata->comp.widget, - XmNx, &x, - XmNy, &y, - NULL); - Java_sun_awt_motif_MChoicePeer_pReshape(env, this, x, y, 0, 0); - AWT_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: freeNativeData - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_freeNativeData(JNIEnv *env, jobject this) -{ - /* - * Fix for bug 4326619 - not necessary for Motif 2.1 - */ -} - - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_setBackground(JNIEnv *env, jobject this, - jobject c) -{ - struct ChoiceData *cdata; - Pixel bg; - Pixel fg; - int32_t i; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException: null color"); - return; - } - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* Get background color */ - bg = awtJNI_GetColor(env, c); - - /* - XmChangeColor(), in addtion to changing the background and - selection colors, also changes the foreground color to be - what it thinks should be. However, we want to use the color - that gets set by setForeground() instead. We therefore need to - save the current foreground color here, and then set it again - after the XmChangeColor() occurs. - */ - XtVaGetValues(cdata->comp.widget, XmNforeground, &fg, NULL); - - /* Set color */ - XmChangeColor(cdata->comp.widget, bg); - XtVaSetValues(cdata->comp.widget, XmNforeground, fg, NULL); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: setForeground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_setForeground(JNIEnv *env, jobject this, - jobject c) -{ - struct ChoiceData *cdata; - Pixel color; - int32_t i; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException: null color"); - return; - } - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - color = awtJNI_GetColor(env, c); - - XtVaSetValues(cdata->comp.widget, XmNforeground, color, NULL); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: pReshape - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_pReshape(JNIEnv *env, jobject this, - jint x, jint y, jint w, jint h) -{ - struct ChoiceData *cdata; - Widget list; - Dimension width = 0, height = 0; - jclass clsDimension; - jobject dimension; - jobject target; - Widget text=NULL; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - if (w == 0) { - /* Set the width and height of the TextField widget to the - * PreferredSize, based on the font size. - */ - clsDimension = (*env)->FindClass(env, "java/awt/Dimension"); - DASSERT(clsDimension != NULL); - dimension = JNU_CallMethodByName(env, NULL, - this, "getPreferredSize", "()Ljava/awt/Dimension;").l; - width = (Dimension)((*env)->GetIntField(env, dimension, - (*env)->GetFieldID(env, clsDimension, - "width" , "I"))); - height = (Dimension)((*env)->GetIntField(env, dimension, - (*env)->GetFieldID(env, clsDimension, - "height", "I"))); - } else { - /* Set the width and height of the TextField widget to the - * given values. BorderLayout passes these values, for example. - */ - width = w; - height = h; - } - text = XtNameToWidget(cdata->comp.widget, "*Text"); - /* - * Bug 4477410: Setting the width of the XmComboBox made the XmTextField - * too small, cutting off the dropdown list knob on the right side. Set - * the width of the TextField because it is the widget actually seen. - */ - XtVaSetValues(text, - XmNwidth, width, - XmNheight, height, - NULL); - - awt_util_reshape(cdata->comp.widget, x, y, width, height); - - list = XtNameToWidget(cdata->comp.widget, "*List"); - - XtVaSetValues(list, XmNwidth, width, NULL); - - /* Set the width and height of the Choice component. */ - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - if (target == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - (*env)->SetIntField(env, target, componentIDs.width, (jint)width); - (*env)->SetIntField(env, target, componentIDs.height, (jint)height); - - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: addItem - * Signature: (Ljava/lang/String;I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_addItem(JNIEnv *env, jobject this, - jstring item, jint index) -{ - if (JNU_IsNull(env, item)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - addItems(env, this, &item, 1, index); -} - - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: appendItems - * Signature: ([Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_appendItems(JNIEnv *env, jobject this, - jarray items) -{ - struct ChoiceData *cdata = NULL; - jstring *strItems = NULL; - int32_t nItems, i; - - if (JNU_IsNull(env, items)) { - return; - } - nItems = (*env)->GetArrayLength(env, items); - if (nItems == 0) { - return; - } - - AWT_LOCK(); - - cdata = (struct ChoiceData *)JNU_GetLongFieldAsPtr(env, - this, mComponentPeerIDs.pData); - if (cdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - - strItems = (jstring *)malloc(sizeof(jstring) * nItems); - if (strItems == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - - for (i = 0; i < nItems; ++i) { - strItems[i] = (jstring)(*env)->GetObjectArrayElement(env, - items, (jsize)i); - if (JNU_IsNull(env, strItems[i])) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - goto cleanup; - } - } - - addItems(env, this, strItems, nItems, (jint)cdata->n_items); - - cleanup: - if (strItems != NULL) { - free(strItems); - } - AWT_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: remove - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_remove(JNIEnv *env, jobject this, - jint index) -{ - struct ChoiceData *cdata; - Widget list; - Widget text=NULL; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - XmComboBoxDeletePos(cdata->comp.widget, index + 1); - --(cdata->n_items); - - list = XtNameToWidget(cdata->comp.widget, "*List"); - XtVaSetValues(list, XmNvisibleItemCount, min(MAX_VISIBLE, cdata->n_items), NULL); - - if (cdata->n_items == 0) { - /* No item is selected, so clear the TextField. */ - text = XtNameToWidget(cdata->comp.widget, "*Text"); - XtVaSetValues(text, XmNvalue, "", NULL); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MChoicePeer - * Method: removeAll - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MChoicePeer_removeAll(JNIEnv *env, jobject this) -{ - struct ChoiceData *cdata; - int32_t i; - Widget text=NULL; - Widget list; - - AWT_LOCK(); - - cdata = (struct ChoiceData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - for (i = cdata->n_items - 1; i >= 0; --i) { - XmComboBoxDeletePos(cdata->comp.widget, i); - } - cdata->n_items = 0; - - /* No item is selected, so clear the TextField. */ - text = XtNameToWidget(cdata->comp.widget, "*Text"); - XtVaSetValues(text, XmNvalue, "", NULL); - - /* should set XmNvisibleItemCount to 1 as 0 is invalid value */ - list = XtNameToWidget(cdata->comp.widget, "*List"); - XtVaSetValues(list, XmNvisibleItemCount, 1, NULL); - - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Component.c --- a/jdk/src/solaris/native/sun/awt/awt_Component.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1656 +0,0 @@ -/* - * Copyright 1995-2006 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. - */ - -#ifdef HEADLESS -#error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "canvas.h" -#include "awt_AWTEvent.h" -#include "VDrawingArea.h" -#include "awt_KeyboardFocusManager.h" -#include "awt_MToolkit.h" -#include "awt_TopLevel.h" -#include "java_awt_Color.h" -#include "java_awt_Cursor.h" -#include "java_awt_Font.h" -#include "java_awt_Point.h" -#include "java_awt_Component.h" -#include "java_awt_AWTEvent.h" -#include "java_awt_KeyboardFocusManager.h" -#include "java_awt_event_KeyEvent.h" -#include "java_awt_event_MouseEvent.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "multi_font.h" -#include "jni.h" -#include "jni_util.h" -#include -#include -#include -#include - -/* CanvasType widgets: Frame, Dialog, Window, Panel, Canvas, - * & all lightweights (Component, Container) - */ -#define IsCanvasTypeWidget(w) \ - XtIsSubclass(w, xmDrawingAreaWidgetClass) ||\ - XtIsSubclass(w, vDrawingAreaClass) - - -#include "awt_Component.h" -#include "awt_GraphicsEnv.h" - -#include "awt_AWTEvent.h" -#include "awt_Cursor.h" - -extern struct CursorIDs cursorIDs; -extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; -extern struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; - -/* fieldIDs for Component fields that may be accessed from C */ -struct ComponentIDs componentIDs; - -/* - * Class: java_awt_Component - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for Component.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_Component_initIDs -(JNIEnv *env, jclass cls) -{ - jclass keyclass = NULL; - - componentIDs.x = (*env)->GetFieldID(env, cls, "x", "I"); - componentIDs.y = (*env)->GetFieldID(env, cls, "y", "I"); - componentIDs.width = (*env)->GetFieldID(env, cls, "width", "I"); - componentIDs.height = (*env)->GetFieldID(env, cls, "height", "I"); - componentIDs.isPacked = (*env)->GetFieldID(env, cls, "isPacked", "Z"); - componentIDs.peer = - (*env)->GetFieldID(env, cls, "peer", "Ljava/awt/peer/ComponentPeer;"); - componentIDs.background = - (*env)->GetFieldID(env, cls, "background", "Ljava/awt/Color;"); - componentIDs.foreground = - (*env)->GetFieldID(env, cls, "foreground", "Ljava/awt/Color;"); - componentIDs.graphicsConfig = - (*env)->GetFieldID(env, cls, "graphicsConfig", - "Ljava/awt/GraphicsConfiguration;"); - componentIDs.name = - (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); - - /* Use _NoClientCode() methods for trusted methods, so that we - * know that we are not invoking client code on trusted threads - */ - componentIDs.getParent = - (*env)->GetMethodID(env, cls, "getParent_NoClientCode", - "()Ljava/awt/Container;"); - - componentIDs.getLocationOnScreen = - (*env)->GetMethodID(env, cls, "getLocationOnScreen_NoTreeLock", - "()Ljava/awt/Point;"); - - componentIDs.resetGCMID = - (*env)->GetMethodID(env, cls, "resetGC", "()V"); - - keyclass = (*env)->FindClass(env, "java/awt/event/KeyEvent"); - DASSERT (keyclass != NULL); - - componentIDs.isProxyActive = - (*env)->GetFieldID(env, keyclass, "isProxyActive", - "Z"); - - componentIDs.appContext = - (*env)->GetFieldID(env, cls, "appContext", - "Lsun/awt/AppContext;"); - - (*env)->DeleteLocalRef(env, keyclass); - - DASSERT(componentIDs.resetGCMID); -} - -/* fieldIDs for MComponentPeer fields that may be accessed from C */ -struct MComponentPeerIDs mComponentPeerIDs; - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MComponentPeer.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_initIDs -(JNIEnv *env, jclass cls) -{ - mComponentPeerIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); - mComponentPeerIDs.target = - (*env)->GetFieldID(env, cls, "target", "Ljava/awt/Component;"); - mComponentPeerIDs.jniGlobalRef = - (*env)->GetFieldID(env, cls, "jniGlobalRef", "J"); - mComponentPeerIDs.graphicsConfig = - (*env)->GetFieldID(env, cls, "graphicsConfig", - "Lsun/awt/X11GraphicsConfig;"); - mComponentPeerIDs.drawState = - (*env)->GetFieldID(env, cls, "drawState", "I"); - mComponentPeerIDs.isFocusableMID = - (*env)->GetMethodID(env, cls, "isFocusable", "()Z"); -} - -/* field and method IDs for java.awt.Container. */ -struct ContainerIDs containerIDs; - -/* - * Class: java_awt_Container - * Method: initIDs - * Signature: ()V - */ -/* This function gets called from the static initializer for java.awt.Container - to initialize the fieldIDs for fields that may be accessed from C */ -JNIEXPORT void JNICALL -Java_java_awt_Container_initIDs -(JNIEnv *env, jclass cls) -{ - containerIDs.layoutMgr = - (*env)->GetFieldID(env, cls, "layoutMgr", "Ljava/awt/LayoutManager;"); - - containerIDs.getComponents = - (*env)->GetMethodID(env, cls, "getComponents_NoClientCode", - "()[Ljava/awt/Component;"); - containerIDs.findComponentAt = - (*env)->GetMethodID(env, cls, "findComponentAt", - "(IIZ)Ljava/awt/Component;"); -} - -/* - * Fix for 4090493. When Motif computes indicator size, it uses - * (effectively) XmTextExtents, so the size of the indicator depends - * on the text of the label. The side effect is that if the label - * text is rendered using different platform fonts (for a single Java - * logical font) the display is inconsistent. E.g. for 12pt font - * English label will have a check mark, while Japanese label will - * not, because underlying X11 fonts have different metrics. - * - * The fix is to override Motif calculations for the indicatorSize and - * compute it ourselves based on the font metrics for all the platform - * fonts given Java font maps onto. Every time we set XmNfontList we - * should set XmNindicatorSize as well. - * - * The logic is in awt_computeIndicatorSize that just compute the - * arithmetic mean of platform fonts by now. HIE should take a look - * at this. - */ - -struct changeFontInfo { - XmFontList fontList; /* value to set */ - Boolean isMultiFont; /* only need to compute for multifont */ - struct FontData *fontData; /* need this to compute indicator size */ - Dimension indSize; /* computed once by changeFont */ - - Boolean initialized; - Boolean error; - JNIEnv *env; - jobject fObj; -}; - -static void -changeFont(Widget w, void *info) -{ - struct changeFontInfo *f = (struct changeFontInfo *)info; - WidgetClass widgetClass; - - if (f->error) - return; - - /* Some widgets use no fonts - skip them! */ - /* Also skip the Text widgets, since they each have their own setFont. */ - widgetClass = XtClass(w); - if (widgetClass == xmDrawingAreaWidgetClass || - widgetClass == xmScrollBarWidgetClass || - widgetClass == xmScrolledWindowWidgetClass || - widgetClass == xmComboBoxWidgetClass || - widgetClass == xmTextWidgetClass || - widgetClass == xmTextFieldWidgetClass) - return; - - if (!f->initialized) { - struct FontData *fdata; - char *err; - - f->initialized = TRUE; - - fdata = awtJNI_GetFontData(f->env, f->fObj, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(f->env, err); - f->error = TRUE; - return; - } - - if (awtJNI_IsMultiFont(f->env, f->fObj)) { - f->fontList = awtJNI_GetFontList(f->env, f->fObj); - f->isMultiFont = TRUE; - } else { - f->fontList = XmFontListCreate(fdata->xfont, "labelFont"); - f->isMultiFont = FALSE; - } - - if (f->fontList == NULL) { - JNU_ThrowNullPointerException(f->env, "NullPointerException"); - f->error = TRUE; - return; - } - } - - /* Fix for 4090493. */ - if (f->isMultiFont && XmIsToggleButton(w)) { - Dimension indSize; - - /* Compute indicator size if first time through. Note that - ToggleButtons that are children of menus live in different - hierarchy (MenuComponent), so we don't check for this case - here. In fact, the only time the XmNfontList is set on - MCheckboxMenuItemPeer widget is when it is created. */ - if (f->indSize == 0) - f->indSize = awt_computeIndicatorSize(f->fontData); - - XtVaSetValues(w, XmNfontList, f->fontList, NULL); - if (f->indSize != MOTIF_XmINVALID_DIMENSION) - XtVaSetValues(w, XmNindicatorSize, f->indSize, NULL); - } - else { /* usual case */ - XtVaSetValues(w, XmNfontList, f->fontList, NULL); - } -} - -static void -changeForeground(Widget w, void *fg) -{ - XtVaSetValues(w, XmNforeground, fg, NULL); -} - -static void -changeBackground(Widget w, void *bg) -{ - Pixel fg; - - XtVaGetValues(w, XmNforeground, &fg, NULL); - XmChangeColor(w, (Pixel) bg); - XtVaSetValues(w, XmNforeground, fg, NULL); -} - -// Sets widget's traversalOn property into value 'value' -void setTraversal(Widget w, Boolean value) { - if (w == NULL) { - return; - } - if (XmIsPrimitive(w)) { - XmPrimitiveWidget prim = (XmPrimitiveWidget)w; - prim->primitive.traversal_on = value; - } else - if (XmIsManager(w)) { - XmManagerWidget man = (XmManagerWidget)w; - man->manager.traversal_on = value; - } -} - - -AwtGraphicsConfigDataPtr -getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject this) { - AwtGraphicsConfigDataPtr adata; - jobject gc_object; - - /* GraphicsConfiguration object of MComponentPeer */ - gc_object = (*env)->GetObjectField(env, this, - mComponentPeerIDs.graphicsConfig); - - if (gc_object != NULL) { - adata = (AwtGraphicsConfigDataPtr) - JNU_GetLongFieldAsPtr(env, gc_object, - x11GraphicsConfigIDs.aData); - } else { - adata = getDefaultConfig(DefaultScreen(awt_display)); - } - - return adata; -} - -AwtGraphicsConfigDataPtr -copyGraphicsConfigToPeer(JNIEnv *env, jobject this) { - - jobject component_object, gc_object; - AwtGraphicsConfigDataPtr adata; - - /** - * Copy the GraphicsConfiguration object from Component object to - * MComponentPeer object. - */ - component_object = (*env)->GetObjectField(env, this, - mComponentPeerIDs.target); - /* GraphicsConfiguration object of Component */ - gc_object = (JNU_CallMethodByName(env, NULL, component_object, - "getGraphicsConfiguration", - "()Ljava/awt/GraphicsConfiguration;")).l; - - if (gc_object != NULL) { - /* Set graphicsConfig field of MComponentPeer */ - (*env)->SetObjectField (env, this, - mComponentPeerIDs.graphicsConfig, - gc_object); - adata = (AwtGraphicsConfigDataPtr) - JNU_GetLongFieldAsPtr(env, gc_object, - x11GraphicsConfigIDs.aData); - } else { - /* Component was not constructed with a GraphicsConfiguration - object */ - adata = getDefaultConfig(DefaultScreen(awt_display)); - } - - return adata; -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: getNativeColor - * Signature (Ljava/awt/Color;Ljava/awt/GraphicsConfiguration;)I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MComponentPeer_getNativeColor -(JNIEnv *env, jobject this, jobject color, jobject gc_object) { - AwtGraphicsConfigDataPtr adata; - adata = (AwtGraphicsConfigDataPtr) JNU_GetLongFieldAsPtr(env, gc_object, - x11GraphicsConfigIDs.aData); - return awtJNI_GetColorForVis(env, color, adata); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pInitialize - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pInitialize -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - Widget parent; - jobject target; - jobject globalRef; - EventMask xtMask; - jlong awtMask = (jlong) 0; - AwtGraphicsConfigDataPtr adata; - Boolean initialTraversal = False; - - globalRef = (jobject) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.jniGlobalRef); - - adata = copyGraphicsConfigToPeer(env, this); - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (JNU_IsNull(env, cdata) || (cdata == NULL)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* Allow FileDialog to have its own traversal policy because - * it doesn't interfer with our. - */ - if (XtIsSubclass(cdata->widget, xmFileSelectionBoxWidgetClass)) { - initialTraversal = True; - } - XtVaSetValues(cdata->widget, - XmNx, (*env)->GetIntField(env, target, componentIDs.x), - XmNy, (*env)->GetIntField(env, target, componentIDs.y), - XmNvisual, adata->awt_visInfo.visual, - XmNscreen, ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen), - /** - * From now we keep all but the focus owner widget unable - * to receive focus. This will prevent Motif from unexpected - * focus transfers. - */ - XmNtraversalOn, initialTraversal, - NULL); - - - /* For all but canvas-style components, pre-process - * mouse and keyboard events (which means posting them - * to the Java EventQueue before dispatching them to Xt). - * For canvas-style components ONLY pre-process mouse events - * because the input-method currently relies on key events - * being processed by Xt first. - */ - awtMask = java_awt_AWTEvent_MOUSE_EVENT_MASK | - java_awt_AWTEvent_MOUSE_MOTION_EVENT_MASK; - xtMask = ExposureMask | FocusChangeMask; - - if (!IsCanvasTypeWidget(cdata->widget)) { - awtMask |= java_awt_AWTEvent_KEY_EVENT_MASK; - } else { - xtMask |= (KeyPressMask | KeyReleaseMask); - } - XtAddEventHandler(cdata->widget, xtMask, - True, awt_canvas_event_handler, globalRef); - - awt_addWidget(cdata->widget, cdata->widget, globalRef, awtMask); - - cdata->repaintPending = RepaintPending_NONE; - - AWT_UNLOCK(); -} - -/** - * Updates stacking order of X windows according to the order of children widgets in - * parent widget - */ -void restack(Widget parent) { - WidgetList children; - int32_t num_children; - Window *windows; - int32_t num_windows = 0; - int32_t i; - XtVaGetValues(parent, - XmNnumChildren, &num_children, - XmNchildren, &children, - NULL); - - windows = (Window *) XtMalloc(num_children * sizeof(Window)); - for (i = 0; i < num_children; i++) { - if (XtIsRealized(children[i])) { - windows[num_windows++] = XtWindow(children[i]); - } - } - XRestackWindows(awt_display, windows, num_windows); - XtFree((char *) windows); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pShow - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pShow -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awt_util_show(cdata->widget); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pHide - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pHide -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awt_util_hide(cdata->widget); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pEnable - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pEnable -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - awt_util_enable(cdata->widget); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pDisable - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pDisable -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - awt_util_disable(cdata->widget); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pReshape - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pReshape -(JNIEnv *env, jobject this, jint x, jint y, jint w, jint h) -{ - struct ComponentData *cdata; - jint drawState; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* Set the draw state */ - drawState = (*env)->GetIntField(env, this, - mComponentPeerIDs.drawState); - (*env)->SetIntField(env, this, - mComponentPeerIDs.drawState, - drawState | JAWT_LOCK_BOUNDS_CHANGED | JAWT_LOCK_CLIP_CHANGED); - awt_util_reshape(cdata->widget, x, y, w, h); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pDispose -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - XtUnmanageChild(cdata->widget); - - awt_delWidget(cdata->widget); - awt_util_consumeAllXEvents(cdata->widget); - awt_util_cleanupBeforeDestroyWidget(cdata->widget); - XtDestroyWidget(cdata->widget); - - free((void *) cdata); - (*env)->SetLongField(env,this,mComponentPeerIDs.pData, (int64_t) 0); - - awtJNI_DeleteGlobalRef(env, this); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pMakeCursorVisible - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pMakeCursorVisible -(JNIEnv *env, jobject this) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - // need to change, may not be needed - // awt_util_setCursor(cdata->widget, cdata->cursor); - - AWT_FLUSH_UNLOCK(); -} - - -/* - * Call with AWT_LOCK held. - */ -static jobject -MComponentPeer_doGetLocationOnScreen(JNIEnv *env, jobject this) -{ - jobject point = NULL; - struct ComponentData *cdata; - int32_t x = 0, y = 0; - Screen *widget_screen = NULL; - Window child_ignored; - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return NULL; - } - if (!XtIsRealized(cdata->widget)) { - JNU_ThrowInternalError(env, "widget not visible on screen"); - return NULL; - } - - /* Translate the component to the screen coordinate system */ - XtVaGetValues(cdata->widget, XmNscreen, &widget_screen, NULL); - XTranslateCoordinates(awt_display, XtWindow(cdata->widget), - XRootWindowOfScreen(widget_screen), - 0, 0, &x, &y, - &child_ignored); - - point = JNU_NewObjectByName(env, "java/awt/Point", "(II)V", - (jint)x, (jint)y); - if (((*env)->ExceptionOccurred(env)) || JNU_IsNull(env, point)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return NULL; - } - - return point; -} - - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pGetLocationOnScreen - * Signature: ()Ljava/awt/Point; - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen(JNIEnv *env, - jobject this) -{ - jobject point; - - AWT_LOCK(); - point = MComponentPeer_doGetLocationOnScreen(env, this); - AWT_UNLOCK(); - return point; -} - - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pGetLocationOnScreen - * Signature: (Ljava/awt/Window;Lsun/awt/motif/MWindowPeer;)Ljava/awt/Point; - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MComponentPeer_pGetLocationOnScreen2( - JNIEnv *env, jobject this, jobject wtarget, jobject wpeer) -{ - jobject point; - struct ComponentData *cdata; - struct FrameData *wdata; - Screen *widget_screen = NULL; - Window child_ignored; - int32_t x = 0, y = 0; - - AWT_LOCK(); - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, wpeer, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->winData.comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - if (!XtIsRealized(wdata->winData.comp.widget)) { - JNU_ThrowInternalError(env, "widget not visible on screen"); - AWT_UNLOCK(); - return NULL; - } - - /* - * Translate directly if the parent window is already adopted by WM. - */ - if (wdata->configure_seen) { - point = MComponentPeer_doGetLocationOnScreen(env, this); - AWT_UNLOCK(); - return point; - } - - /* - * We are called while the parent window is still not adopted by - * WM (but may already be in the process of being reparented). - * Translate to the parent and add parent target's (x,y) to avoid - * racing with WM shuffling us into the final position. - */ - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (cdata == &wdata->winData.comp) { /* called for the window itself */ - x = y = 0; - } - else { - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - if (!XtIsRealized(cdata->widget)) { - JNU_ThrowInternalError(env, "widget not visible on screen"); - AWT_UNLOCK(); - return NULL; - } - - /* Translate to the outer canvas coordinate system first */ - XtVaGetValues(cdata->widget, XmNscreen, &widget_screen, NULL); - XTranslateCoordinates(awt_display, XtWindow(cdata->widget), - XtWindow(wdata->winData.comp.widget), - 0, 0, &x, &y, - &child_ignored); - } - - x += (*env)->GetIntField(env, wtarget, componentIDs.x); - y += (*env)->GetIntField(env, wtarget, componentIDs.y); - - point = JNU_NewObjectByName(env, "java/awt/Point", "(II)V", - (jint)x, (jint)y); - if (((*env)->ExceptionOccurred(env)) || JNU_IsNull(env, point)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - - AWT_UNLOCK(); - return point; -} - - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: getParent_NoClientCode - * Signature: (Ljava/awt/Component)Ljava/awt/Container; - * - * NOTE: This method may be called by privileged threads. - * DO NOT INVOKE CLIENT CODE ON THIS THREAD! - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MComponentPeer_getParent_1NoClientCode -(JNIEnv *env, jclass thisClass, jobject component) -{ - jobject parent = NULL; - - /* getParent is actually getParent_NoClientCode() */ - parent = (*env)->CallObjectMethod(env,component,componentIDs.getParent); - DASSERT(!((*env)->ExceptionOccurred(env))); - return parent; -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: getComponents_NoClientCode - * Signature: (Ljava/awt/Container)[Ljava/awt/Component; - * REMIND: Signature is incorrect for returned array value - * - * NOTE: This method may be called by privileged threads. - * DO NOT INVOKE CLIENT CODE ON THIS THREAD! - */ -JNIEXPORT jobjectArray JNICALL Java_sun_awt_motif_MComponentPeer_getComponents_1NoClientCode -(JNIEnv *env, jclass thisClass, jobject container) -{ - jobjectArray contents = NULL; - contents = (*env)->CallObjectMethod( - env, container, containerIDs.getComponents); - DASSERT(!((*env)->ExceptionOccurred(env))); - return contents; -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetForeground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetForeground -(JNIEnv *env, jobject this, jobject c) -{ - struct ComponentData *bdata; - Pixel color; - AwtGraphicsConfigDataPtr adata; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - adata = getGraphicsConfigFromComponentPeer(env, this); - - color = (Pixel) awtJNI_GetColorForVis (env, c, adata); - XtVaSetValues(bdata->widget, XmNforeground, color, NULL); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetBackground -(JNIEnv *env, jobject this, jobject c) -{ - struct ComponentData *bdata; - Pixel color; - Pixel fg; - AwtGraphicsConfigDataPtr adata; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - adata = getGraphicsConfigFromComponentPeer(env, this); - - color = (Pixel) awtJNI_GetColorForVis (env, c, adata); - XtVaGetValues(bdata->widget, XmNforeground, &fg, NULL); - XmChangeColor(bdata->widget, color); - XtVaSetValues(bdata->widget, XmNforeground, fg, NULL); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetScrollbarBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetScrollbarBackground -(JNIEnv *env, jobject this, jobject c) -{ - struct ComponentData *bdata; - Pixel color; - Pixel fg; - int32_t i; - WidgetList wlist; - Cardinal wlen = 0; - - /* This method propagates the specified background color to the scrollbars in the composite widget. - * Used to set background scrollbar color in List, TextArea, ScrollPane to its parent. - */ - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (!XtIsComposite(bdata->widget)) { - AWT_UNLOCK(); - return; - } - color = (Pixel) awtJNI_GetColor(env, c); - - XtVaGetValues(bdata->widget, - XmNchildren, &wlist, - XmNnumChildren, &wlen, - NULL); - if (wlen > 0) { /* this test doesn't make much sense, since wlen - is a Cardinal and cardinal is unsigned int... */ - for (i=0; i < wlen; i++) { - if (XtIsSubclass(wlist[i], xmScrollBarWidgetClass)) { - XtVaGetValues(wlist[i], XmNforeground, &fg, NULL); - XmChangeColor(wlist[i], color); - XtVaSetValues(wlist[i], XmNforeground, fg, NULL); - } - } - XtVaGetValues(bdata->widget, XmNforeground, &fg, NULL); - XmChangeColor(bdata->widget, color); - XtVaSetValues(bdata->widget, XmNforeground, fg, NULL); - } - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetInnerForeground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetInnerForeground -(JNIEnv *env, jobject this, jobject c) -{ - struct ComponentData *bdata; - Pixel color; - - /* This method propagates the specified foreground color to all its children. - * It is called to set foreground color in List, TextArea, ScrollPane. - */ - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - color = awtJNI_GetColor(env, c); - awt_util_mapChildren(bdata->widget, changeForeground, 1, (void *) color); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetFont -(JNIEnv *env, jobject this, jobject f) -{ - struct ComponentData *cdata; - - struct changeFontInfo finfo = { NULL, FALSE, NULL, 0, - FALSE, FALSE, NULL, NULL }; - - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - finfo.env = env; - finfo.fObj = f; - awt_util_mapChildren(cdata->widget, changeFont, 1, (void *)&finfo); - if (!finfo.error && finfo.fontList != NULL) { - XmFontListFree(finfo.fontList); - } - - AWT_FLUSH_UNLOCK(); -} /* MComponentPeer.pSetFont() */ - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: setTargetBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_setTargetBackground -(JNIEnv *env, jobject this, jobject c) -{ - jobject target = NULL; - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - (*env)->SetObjectField(env, target, componentIDs.background, c); - (*env)->DeleteLocalRef(env, target); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: pSetCursor - * Signature: (Ljava/awt/Cursor;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_pSetCursor -(JNIEnv *env, jobject this, jobject cursor) -{ - Cursor xcursor; - struct ComponentData *cdata; - - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL || JNU_IsNull(env, cursor)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awt_util_setCursor(cdata->widget, getCursor(env, cursor)); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: nativeHandleEvent - * Signature: (Ljava/awt/AWTEvent;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_nativeHandleEvent -(JNIEnv *env, jobject this, jobject event) -{ - extern void awt_modify_KeyEvent(JNIEnv *env, XEvent * xevent, jobject jevent); - jbyteArray array; - XEvent *xevent; - Widget widget = NULL; - Boolean consumed; - - if (JNU_IsNull(env, event)) { - return; - } - AWT_LOCK(); - - consumed = (*env)->GetBooleanField(env, event, awtEventIDs.consumed); - - /* - * Fix for bug 4280561 - * - * If a menu is up, we must dispatch all XEvents, to allow - * mouse grabs to be released and prevent server hangs. - */ - consumed = consumed && !awt_util_focusIsOnMenu(awt_display); - - if (consumed) { - AWT_UNLOCK(); - return; - } - - array = (jbyteArray)(*env)->GetObjectField(env, event, awtEventIDs.bdata); - if (array == NULL) { - AWT_UNLOCK(); - return; - } - - xevent = (XEvent *)(*env)->GetByteArrayElements(env, array, NULL); - if (xevent == NULL) { - AWT_UNLOCK(); - return; - } - - switch ((*env)->GetIntField(env, event, awtEventIDs.id)) { - case java_awt_event_KeyEvent_KEY_RELEASED: - case java_awt_event_KeyEvent_KEY_PRESSED: - awt_modify_KeyEvent(env, xevent, event); - if ((*env)->GetBooleanField(env, event, componentIDs.isProxyActive) == JNI_TRUE) { - xevent->xany.send_event = SPECIAL_KEY_EVENT; - } - break; - default: - break; - } - widget = XtWindowToWidget(awt_display, xevent->xany.window); - - if (!((widget == NULL) || (!XtIsObject(widget)) || - (widget->core.being_destroyed))) { - /* Queue the event to be handled by the AWT-Motif thread */ - if (!IsCanvasTypeWidget(widget)) { - awt_put_back_event(env, xevent); - } - } - - (*env)->ReleaseByteArrayElements(env, array, (jbyte *)xevent, JNI_ABORT); - (*env)->DeleteLocalRef(env, array); - - AWT_UNLOCK(); - return; -} - -// Returns the widget from parent's hierarchy which should be -// used for focus operations. This widget is stored in WidgetInfo -// structure and should be prepared by the appropriate component -// type constructor -Widget getFocusWidget(Widget parent) { - struct WidgetInfo * winfo = NULL; - DASSERT(parent != NULL); - if (parent == NULL) { - return NULL; - } - winfo = findWidgetInfo(parent); - if (winfo == NULL) { - return NULL; - } - return winfo->widget; -} - - -// Returns value of widget's traversalOn property -Boolean getTraversal(Widget w) { - if (w == NULL) { - return False; - } - if (XmIsPrimitive(w)) { - XmPrimitiveWidget prim = (XmPrimitiveWidget)w; - return prim->primitive.traversal_on; - } - if (XmIsManager(w)) { - XmManagerWidget man = (XmManagerWidget)w; - return man->manager.traversal_on; - } - return False; -} - - -void processTree(Widget from, Widget to, Boolean action) { -// Workhorse function that makes sure that the only widgets -// which have traversalOn == true are the ones on the path from -// shell to current focus widget. Function uses two widgets - -// the one which is supposed to have focus currently(from) and -// the one which will receive focus(to). Function disables and -// enables the appropriate widgets so 'to' can become focus owner. - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - int32_t count_from = 0, count_to = 0; - Widget parent_from = NULL, parent_to = NULL; - Widget * parents_from = NULL, * parents_to = NULL; - int32_t index = 0; - - // Count amount of parents up the tree from widget - parent_from = from; - while (parent_from != NULL) { - parent_from = XtParent(parent_from); - count_from++; - } - parent_to = to; - while (parent_to != NULL) { - parent_to = XtParent(parent_to); - count_to++; - } - - // Store all the parents in the list. Both list wittingly - // have common parts starting from the beginning. We need - // to find the end of this common part. - parents_from = (Widget*)malloc(count_from*sizeof(Widget*)); - parents_to = (Widget*)malloc(count_to*sizeof(Widget*)); - parent_from = from; - index = count_from; - while (parent_from != NULL) { - parents_from[index-1] = parent_from; - parent_from = XtParent(parent_from); - index--; - } - parent_to = to; - index = count_to; - while (parent_to != NULL) { - parents_to[index-1] = parent_to; - parent_to = XtParent(parent_to); - index--; - } - - // Process parents list. Find common part which is usually doesn't - // require changes. At the exit of the cycle index will point - // to the first widget which requeires the change. - - if (from != NULL && to != NULL) { - do { - if (index >= count_from-1 || index >= count_to-1) { - break; - } - if (parents_from[index] == parents_to[index]) - { - if (XtIsShell(parents_from[index])) { - index++; - continue; - } - if (action) { - if (getTraversal(parents_from[index])) { - index++; - } else { - break; - } - } else { - index++; - } - } else { - break; - } - } while (True); - } - - - if (action) { // enable the tree starting from uncommon part till 'to' - if (to != NULL) { - while (index < count_to - 1) { - if (!getTraversal(parents_to[index])) { - XtVaSetValues(parents_to[index], XmNtraversalOn, True, NULL); - } - index++; - } - XtVaSetValues(to, XmNtraversalOn, True, NULL); - } - } else if (from != NULL) { - // disable the tree starting from uncommon part to 'from' - if (parents_from[index] == parents_to[index]) { - if (index == count_from - 1) { - // 'from' is one of the parents of 'to' - no need - // to disable 'from' - goto skip_disable; - } - index++; - } - while (index < count_from - 1) { - if (!XmIsGadget(parents_from[index]) && !XtIsShell(parents_from[index])) { - setTraversal(parents_from[index], False); - } - index++; - } - if (!XmIsGadget(from)) { - setTraversal(parents_from[index], False); - } - } - skip_disable: - free(parents_from); - free(parents_to); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: requestFocus - * Signature: (Ljava/awt/Component;ZZJ)Z - */ -JNIEXPORT jboolean JNICALL Java_sun_awt_motif_MComponentPeer__1requestFocus -(JNIEnv *env, jobject this, jobject lightweightChild, jboolean temporary, - jboolean focusedWindowChangeAllowed, jlong time, jobject cause) -{ - struct ComponentData *bdata; - Boolean result; - jobject target; - jint retval; - Widget currentOwner = NULL; - jobject curPeer = NULL; - Widget shell; - Widget widgetToFocus = NULL; - - AWT_LOCK(); - - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (bdata == NULL || bdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return JNI_FALSE; - } - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - AWT_UNLOCK(); - return JNI_FALSE; - } - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - /* Don't need to free target explicitly. That will happen automatically - when this function returns. */ - - if (target == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return JNI_FALSE; - } - - /* The X11 implementation does not permit cross-Window focus transfers, - so always pass JNI_FALSE for that parameter. */ - retval = (*env)->CallStaticIntMethod - (env, keyboardFocusManagerIDs.keyboardFocusManagerCls, - keyboardFocusManagerIDs.shouldNativelyFocusHeavyweightMID, - target, lightweightChild, temporary, JNI_FALSE, time, cause); - - if (retval == java_awt_KeyboardFocusManager_SNFH_SUCCESS_HANDLED) { - AWT_UNLOCK(); - (*env)->DeleteLocalRef(env, target); - return JNI_TRUE; - } - if (retval == java_awt_KeyboardFocusManager_SNFH_FAILURE) { - AWT_UNLOCK(); - (*env)->DeleteLocalRef(env, target); - return JNI_FALSE; - } - - DASSERT(retval == java_awt_KeyboardFocusManager_SNFH_SUCCESS_PROCEED); - - shell = getShellWidget(bdata->widget); - currentOwner = XmGetFocusWidget(shell); - - widgetToFocus = getFocusWidget(bdata->widget); - - globalClearFocusPath(shell); - - // Prepare widgets tree - processTree(currentOwner, widgetToFocus, False); - processTree(currentOwner, widgetToFocus, True); - - /* - Fix for bug 4157017: replace XmProcessTraversal with - XtSetKeyboardFocus because XmProcessTraversal does not allow - focus to go to non-visible widgets. - - (There is a corresponding change to awt_MToolkit.c:dispatchToWidget) - - I found a last minute problem with this fix i.e. it broke the test - case for bug 4053856. XmProcessTraversal does something else (that - XtSetKeyboardFocus does not do) that stops this test case from - failing. So, as I do not have time to investigate, and having - both XmProcessTraversal and XtSetKeyboardFocus fixes 4157017 and - 4053856 and should be harmless (reviewer agreed), we have both - below - XmProcessTraversal AND XtSetKeyboardFocus. - */ - result = XmProcessTraversal(widgetToFocus, XmTRAVERSE_CURRENT); - if (!result) - { - Widget w = widgetToFocus; - - shell = getShellWidget(w); - XtSetKeyboardFocus(shell, w); - } - /* end 4157017 */ - - // Because Motif focus callbacks are disabled we need to generate - // the required events by ourselves. - // First, check if the current focused widget has the entry in focus - // list. If not, add it because it is required for further processing - if (currentOwner != NULL) { - jobject last = NULL; - curPeer = findPeer(¤tOwner); - if (curPeer == NULL) { - currentOwner = findTopLevelByShell(currentOwner); - if (currentOwner != NULL) { - curPeer = findPeer(¤tOwner); - } - } - if (curPeer != NULL) { - curPeer = (*env)->GetObjectField(env, curPeer, mComponentPeerIDs.target); - if (focusList == NULL) { - awt_canvas_addToFocusListWithDuplicates(curPeer, JNI_TRUE); - } else { - last = (*env)->NewLocalRef(env, focusList->requestor); - if (!(*env)->IsSameObject(env, last, curPeer)) { - awt_canvas_addToFocusList(curPeer); - } - if (!JNU_IsNull(env, last)) { - (*env)->DeleteLocalRef(env, last); - } - } - (*env)->DeleteLocalRef(env, curPeer); - } - } - awt_canvas_addToFocusList(target); - - // If new and current focus owners are the same do not generate FOCUS_LOST - // event because we don't expect it, but generate FOCUS_GAIN because we - // wait for it. - if ( currentOwner != NULL && !JNU_IsNull(env, curPeer) && - !(*env)->IsSameObject(env, curPeer, target)) { - callFocusHandler(currentOwner, FocusOut, cause); - } - callFocusHandler(widgetToFocus, FocusIn, cause); - (*env)->DeleteLocalRef(env, target); - - AWT_FLUSH_UNLOCK(); - return JNI_TRUE; -} - -Dimension -awt_computeIndicatorSize(struct FontData *fdata) -{ - int32_t height; - int32_t acc; - int32_t i; - - if (fdata == (struct FontData *) NULL) - return MOTIF_XmINVALID_DIMENSION; - - /* - * If Java font maps into single platform font - there's no - * problem. Let Motif use its usual calculations in this case. - */ - if (fdata->charset_num == 1) - return MOTIF_XmINVALID_DIMENSION; - - acc = 0; - for (i = 0; i < fdata->charset_num; ++i) { - XFontStruct *xfont = fdata->flist[i].xfont; - acc += xfont->ascent + xfont->descent; - } - - height = acc / fdata->charset_num; - if (height < MOTIF_XmDEFAULT_INDICATOR_DIM) - height = MOTIF_XmDEFAULT_INDICATOR_DIM; - - return height; -} - -Dimension -awt_adjustIndicatorSizeForMenu(Dimension indSize) -{ - if (indSize == 0 || indSize == MOTIF_XmINVALID_DIMENSION) - return MOTIF_XmINVALID_DIMENSION; /* let motif do the job */ - - /* Indicators in menus are smaller. - 2/3 is a magic number from Motif internals. */ - indSize = indSize * 2 / 3; - if (indSize < MOTIF_XmDEFAULT_INDICATOR_DIM) - indSize = MOTIF_XmDEFAULT_INDICATOR_DIM; - - return indSize; -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: getWindow - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_sun_awt_motif_MComponentPeer_getWindow -(JNIEnv *env, jobject this, jlong pData) -{ - jlong ret = (jlong)0; - struct ComponentData* cdata; - cdata = (struct ComponentData*)pData; - AWT_LOCK(); - ret = (jlong)XtWindow(cdata->widget); - AWT_FLUSH_UNLOCK(); - return ret; -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: restore_Focus - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_restoreFocus -(JNIEnv *env, jobject this) -{ - jobject focus_peer; - AWT_LOCK(); - - focus_peer = awt_canvas_getFocusOwnerPeer(); - if (!JNU_IsNull(env, focus_peer)) { - struct ComponentData *bdata; - Boolean result; - - bdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, focus_peer, mComponentPeerIDs.pData); - if (bdata != NULL) { - Widget widgetToFocus = getFocusWidget(bdata->widget); - result = XmProcessTraversal(widgetToFocus, XmTRAVERSE_CURRENT); - if (!result) - { - XtSetKeyboardFocus(getShellWidget(widgetToFocus), widgetToFocus); - } - } - } - (*env)->DeleteLocalRef(env, focus_peer); - - AWT_UNLOCK(); -} - -JNIEXPORT jboolean JNICALL -Java_sun_awt_motif_MComponentPeer_processSynchronousLightweightTransfer( - JNIEnv * env, jclass cls, jobject heavyweight, jobject descendant, - jboolean temporary, jboolean focusedWindowChangeAllowed, jlong time) -{ - return (*env)->CallStaticBooleanMethod(env, keyboardFocusManagerIDs.keyboardFocusManagerCls, - keyboardFocusManagerIDs.processSynchronousTransferMID, - heavyweight, descendant, temporary, - focusedWindowChangeAllowed, time); -} -/* - * Class: sun_awt_motif_MComponentPeer - * Method: getNativeFocusedWindow - * Signature: ()Ljava/awt/Window; - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MComponentPeer_getNativeFocusedWindow -(JNIEnv *env, jclass cls) -{ - jobject l_peer; - - AWT_LOCK(); - l_peer = awt_canvas_getFocusedWindowPeer(); - AWT_UNLOCK(); - - return (l_peer != NULL) - ? (*env)->GetObjectField(env, l_peer, mComponentPeerIDs.target) - : NULL; -} - -/** - * Makes sure that child has correct index inside parent - * Note: there was a short time when we were counting index in the - * opposite order when it seemed that X and Java z-order notions - * are different. Now we know they are not: last component is - * painted first and appears below all other components with - * smaller indices. - */ -void ensureIndex(Widget parent, Widget child, int index) { - WidgetList children; - int32_t num_children; - int32_t i; - - if (parent == NULL) { - return; - } - if (child == NULL) { - return; - } - XtVaGetValues(parent, - XmNnumChildren, &num_children, - XmNchildren, &children, - NULL); - if (index < 0 || index >= num_children) { - return; - } - if (children[index] != child) { - for (i = 0; i < num_children; i++) { - if (children[i] == child) { - break; - } - } - if (i < num_children) { - Widget temp = children[index]; - children[index] = child; - children[i] = temp; - } - } -} - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MPanelPeer_pEnsureIndex(JNIEnv * env, jobject this, jobject child, jint index) { - struct ComponentData *cdata; - Widget w_parent, w_child; - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - w_parent = cdata->widget; - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, child, mComponentPeerIDs.pData); - w_child = cdata->widget; - ensureIndex(w_parent, w_child, index); - AWT_UNLOCK(); -} - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MPanelPeer_pRestack(JNIEnv * env, jobject this) { - struct ComponentData *cdata; - Widget w_parent; - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - w_parent = cdata->widget; - restack(w_parent); - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Cursor.c --- a/jdk/src/solaris/native/sun/awt/awt_Cursor.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * Copyright 1998-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include -#include "awt_Component.h" -#include "awt_Cursor.h" -#include "java_awt_Cursor.h" -#include - -#include "jni.h" -#include "jni_util.h" - -/* fieldIDs for Cursor fields that may be accessed from C */ -struct CursorIDs cursorIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; - -static jweak curComp = 0; - -/* - * Class: java_awt_Cursor - * Method: initIDs - * Signature: ()V - */ -/* - * This function gets called from the static initializer for Cursor.java - * to initialize the fieldIDs for fields that may be accessed from C - */ -JNIEXPORT void JNICALL -Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls) -{ - cursorIDs.type = (*env)->GetFieldID(env, cls, "type", "I"); - cursorIDs.mSetPData = (*env)->GetMethodID(env, cls, "setPData", "(J)V"); - cursorIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); -} - -/* - * A utility to retrieve cursor from java.awt.Cursor - * Create and save the cursor first if it is not yet - */ -Cursor getCursor(JNIEnv *env, jobject jCur) -{ - int32_t cursorType = 0; - Cursor xcursor; - - xcursor = (Cursor)(*env)->GetLongField(env, jCur, cursorIDs.pData); - - if (xcursor != None) { - return xcursor; - } - - cursorType = (*env)->GetIntField(env, jCur, cursorIDs.type); - - DASSERT(cursorType != java_awt_Cursor_CUSTOM_CURSOR); - - switch (cursorType) { - case java_awt_Cursor_DEFAULT_CURSOR: - cursorType = XC_left_ptr; - break; - case java_awt_Cursor_CROSSHAIR_CURSOR: - cursorType = XC_crosshair; - break; - case java_awt_Cursor_TEXT_CURSOR: - cursorType = XC_xterm; - break; - case java_awt_Cursor_WAIT_CURSOR: - cursorType = XC_watch; - break; - case java_awt_Cursor_SW_RESIZE_CURSOR: - cursorType = XC_bottom_left_corner; - break; - case java_awt_Cursor_NW_RESIZE_CURSOR: - cursorType = XC_top_left_corner; - break; - case java_awt_Cursor_SE_RESIZE_CURSOR: - cursorType = XC_bottom_right_corner; - break; - case java_awt_Cursor_NE_RESIZE_CURSOR: - cursorType = XC_top_right_corner; - break; - case java_awt_Cursor_S_RESIZE_CURSOR: - cursorType = XC_bottom_side; - break; - case java_awt_Cursor_N_RESIZE_CURSOR: - cursorType = XC_top_side; - break; - case java_awt_Cursor_W_RESIZE_CURSOR: - cursorType = XC_left_side; - break; - case java_awt_Cursor_E_RESIZE_CURSOR: - cursorType = XC_right_side; - break; - case java_awt_Cursor_HAND_CURSOR: - cursorType = XC_hand2; - break; - case java_awt_Cursor_MOVE_CURSOR: - cursorType = XC_fleur; - break; - } - xcursor = XCreateFontCursor(awt_display, cursorType); - - (*env)->CallVoidMethod(env, jCur, cursorIDs.mSetPData, xcursor); - return xcursor; -} - -/* - * Class: java_awt_Cursor - * Method: finalizeImpl - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jclass clazz, jlong pData) -{ - Cursor xcursor; - - xcursor = (Cursor)pData; - if (xcursor != None) { - AWT_LOCK(); - XFreeCursor(awt_display, xcursor); - AWT_UNLOCK(); - } -} - -/* - * normal replace : CACHE_UDPATE => update curComp and updateCursor - * not replace : UPDATE_ONLY => intact curComp but updateCursor - * only replace : CACHE_ONLY => update curComp only, not updateCursor - * - * This function should only be called under AWT_LOCK(). Otherwise - * multithreaded access can corrupt the value of curComp variable. - */ -void updateCursor(XPointer client_data, int32_t replace) { - - static jclass globalCursorManagerClass = NULL; - static jmethodID updateCursorID = NULL; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject peer = (jobject) client_data; - jobject target; - - if ((*env)->PushLocalFrame(env, 16) < 0) - return; - - target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - if (replace != UPDATE_ONLY) { - if (!JNU_IsNull(env, curComp)) { - (*env)->DeleteWeakGlobalRef(env, curComp); - } - curComp = (*env)->NewWeakGlobalRef(env, target); - if (replace == CACHE_ONLY) { - (*env)->PopLocalFrame(env, 0); - return; - } - } - - /* Initialize our java identifiers once. Checking before locking - * is a huge performance win. - */ - if (globalCursorManagerClass == NULL) { - jobject sysClass = (*env)->FindClass(env, "sun/awt/motif/MGlobalCursorManager"); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - globalCursorManagerClass = (*env)->NewGlobalRef(env, sysClass); - - updateCursorID = (*env)->GetStaticMethodID(env, - globalCursorManagerClass, - "nativeUpdateCursor", - "(Ljava/awt/Component;)V" - ); - } - if (JNU_IsNull(env, globalCursorManagerClass) || updateCursorID == NULL) { - JNU_ThrowClassNotFoundException(env, "sun/awt/motif/MGlobalCursorManager"); - (*env)->PopLocalFrame(env, 0); - return; - } - } /* globalCursorManagerClass == NULL*/ - - (*env)->CallStaticVoidMethod(env, globalCursorManagerClass, - updateCursorID, target); - DASSERT(!((*env)->ExceptionOccurred(env))); - (*env)->PopLocalFrame(env, 0); -} - -/* - * Only call this function under AWT_LOCK(). Otherwise multithreaded - * access can corrupt the value of curComp variable. - */ -jobject getCurComponent() { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - return (*env)->NewLocalRef(env, curComp); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_DataTransferer.c --- a/jdk/src/solaris/native/sun/awt/awt_DataTransferer.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1068 +0,0 @@ -/* - * Copyright 2000-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include -#include - -#include - -#include -#include - -#include "sun_awt_datatransfer_DataTransferer.h" -#include "sun_awt_motif_MDataTransferer.h" - -#include "awt_XmDnD.h" -#include "awt_DataTransferer.h" - -static jclass string; - -XContext awt_convertDataContext = 0; - -Atom XA_TARGETS; - -extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; - -typedef enum { - SelectionPending, - SelectionSuccess, - SelectionFailure, - SelectionOwnerTimedOut -} SelectionStatus; - -/* Should only be accessed by the current owner of AWT_LOCK. */ -static SelectionStatus globalSelectionStatus = SelectionPending; - -static SelectionStatus get_selection_status() { - return globalSelectionStatus; -} - -static void set_selection_status(SelectionStatus status) { - globalSelectionStatus = status; -} - -static void -selection_request_filter(Widget widget, XtPointer closure, XEvent *event, - Boolean *cont) { - if (event->type == SelectionRequest) { - Window awt_root_window = XtWindow(awt_root_shell); - Atom selection = event->xselectionrequest.selection; - Window owner = XGetSelectionOwner(event->xany.display, selection); - - if (owner != awt_root_window) { - XSelectionEvent notify; - - notify.type = SelectionNotify; - notify.display = event->xselectionrequest.display; - notify.requestor = event->xselectionrequest.requestor; - notify.selection = event->xselectionrequest.selection; - notify.time = event->xselectionrequest.time; - notify.target = event->xselectionrequest.target; - notify.property = None; - - XSendEvent(notify.display, notify.requestor, False, - (unsigned long)0, (XEvent*)¬ify); - *cont = False; - } - } -} - -/** - * global function to initialize this client as a Dynamic-only app. - * - * gets called once during toolkit initialization. - */ - -void awt_initialize_DataTransferer() { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jclass stringClassLocal = NULL; - - DASSERT(string == NULL); - - stringClassLocal = (*env)->FindClass(env, "java/lang/String"); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - DASSERT(False); - } - - if (JNU_IsNull(env, stringClassLocal)) return; - - string = (*env)->NewGlobalRef(env, stringClassLocal); /* never freed! */ - (*env)->DeleteLocalRef(env, stringClassLocal); - - if (JNU_IsNull(env, string)) { - JNU_ThrowOutOfMemoryError(env, ""); - return; - } - - DASSERT(awt_convertDataContext == 0); - awt_convertDataContext = XUniqueContext(); - DASSERT(awt_convertDataContext != 0); - - /* - * Fixes for 4513976 and 4818143. - */ - XtAppSetSelectionTimeout(awt_appContext, - JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit", - "getDatatransferTimeout", "()I").i); - - /* - * Xt selection machinery doesn't respond to SelectionRequests if the - * event arrives on a widget that is not the current selection owner. - * This can happen if XtDisownSelection was called when SelectionRequest was - * already on the native queue. - * If the requestor is another JVM, it hangs for the selection timeout - * as SelectionNotify is never sent. - * We install an event handler that filters out SelectionRequests if the - * awt_root_shell is not the current selection owner. - */ - XtAddEventHandler(awt_root_shell, (EventMask)0, True, - selection_request_filter, NULL); - - XA_TARGETS = XInternAtom(awt_display, "TARGETS", False); -} - -/* - * Single routine to convert to target FILE_NAME or _DT_FILENAME - */ -Boolean -convertFileType(jbyteArray data, Atom * type, XtPointer * value, - unsigned long *length, int32_t *format) -{ - /* - * Convert the internal representation to an File Name. - * The data passed is an array of - * null separated bytes. Each series of bytes is a string - * that is then converted to an XString which are then put - * into an XStringList and put into an XTextProperty for - * usage in other programs. - * - * It would be desireable to have dataConvert to this conversion - * but it isn't possible to return a byte array that represents - * the XTextProperty. - */ - - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jboolean isCopy=JNI_FALSE; - XTextProperty tp; - jsize len; - jsize strings = 0; - jsize i; - char** stringList; - Status s; - jbyte* bytes; - char* start; - size_t slen; - char* utf; - - if ((*env)->PushLocalFrame(env, 16) < 0) { - return False; - } - - /* convert the data to an Array of Byte Elements */ - bytes = (*env)->GetByteArrayElements(env, data, &isCopy); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - if (JNU_IsNull(env, bytes)) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - /* Get the length of the area */ - len = (*env)->GetArrayLength(env, data); - if (len == 0) { - (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - /* - * determine the number of lists. The byteArray is null separated list of - * strings. - */ - for (i = 0; i < len; i++) { - if (bytes[i] == '\0') { - strings++; - } - } - - /* Allocate an X11 string list */ - stringList = (char **)XtCalloc(strings, sizeof(char *)); - if (stringList == (char**)NULL) { - (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - for (i = 0; i < strings; i++) { - if (i == 0) { - start = (char*)bytes; - } else { - start = (char*)&bytes[slen]; - } - - /* - * if start is a NULL we're at the end of the list - * We'll just a have null entry on the end of the list - */ - if (start[0] == '\0') { - stringList[i] = NULL; - continue; - } - slen = strlen(start) + 1; - - stringList[i] = (char*)XtCalloc(slen, sizeof(char)); - - if (stringList[i] == (char *)NULL) { - jsize j; - - (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); - - for (j = 0; j < i; j++) { - XtFree((void *)stringList[j]); - } - - (*env)->PopLocalFrame(env, NULL); - - return False; - } - - memcpy((void *)stringList[i], (const void*)start, slen); - } - - (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); - s = XStringListToTextProperty(stringList, strings, &tp); - - /* free the strings that were created */ - for (i = 0; i < strings; i++) { - if (stringList[i] != NULL) { - XtFree((void*)stringList[i]); - } - } - - XtFree((void*)stringList); - - if (s == 0) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - *value = (XtPointer)XtCalloc(tp.nitems, sizeof(char)); - - if (*value == (XtPointer)NULL) { - XFree((void*)tp.value); - - (*env)->PopLocalFrame(env, NULL); - - return False; - } - - memcpy((void *)(*value), (const void *)tp.value, tp.nitems); - - XFree((void*)tp.value); - - *length = tp.nitems; - *type = tp.encoding; - *format = tp.format; - (*env)->PopLocalFrame(env, NULL); - return True; -} - -/* - * Class: sun_awt_motif_MDataTransferer - * Method: getAtomForTarget - * Signature: (Ljava/lang/String;)J - */ - -JNIEXPORT jlong JNICALL -Java_sun_awt_motif_MDataTransferer_getAtomForTarget(JNIEnv *env, - jclass cls, - jstring targetString) -{ - Atom target; - char *target_str; - - if (JNU_IsNull(env, targetString)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return -1; - } - target_str = (char *) JNU_GetStringPlatformChars(env, targetString, NULL); - - AWT_LOCK(); - - target = XInternAtom(awt_display, target_str, False); - - AWT_UNLOCK(); - - JNU_ReleaseStringPlatformChars(env, targetString, - (const char *) target_str); - return target; -} - -/* - * Class: sun_awt_motif_MDataTransferer - * Method: getTargetNameForAtom - * Signature: (J)Ljava/lang/String; - */ - -JNIEXPORT jstring JNICALL -Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom(JNIEnv *env, - jclass cls, - jlong atom) -{ - jstring targetString; - char *name; - - AWT_LOCK(); - - name = XGetAtomName(awt_display, (Atom) atom); - - if (name == NULL) { - JNU_ThrowNullPointerException(env, "Failed to retrieve atom name."); - AWT_UNLOCK(); - return NULL; - } - - targetString = (*env)->NewStringUTF(env, (const char *)name); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - XFree (name); - AWT_UNLOCK(); - return NULL; - } - - if (JNU_IsNull(env, targetString)) { - JNU_ThrowNullPointerException(env, "Failed to create a string."); - XFree (name); - AWT_UNLOCK(); - return NULL; - } - - XFree (name); - - AWT_UNLOCK(); - return targetString; -} - -/* - * Class: sun_awt_datatransfer_DataTransferer - * Method: dragQueryFile - * Signature: ([B)[Ljava/lang/String; - * - * This method converts a byte array that came from File most likely from a - * drag operation into a String array. - */ - -JNIEXPORT jobjectArray JNICALL -Java_sun_awt_motif_MDataTransferer_dragQueryFile - (JNIEnv *env, jobject this, jbyteArray bytes) -{ - XTextProperty tp; - jbyte *value; - - char** strings = (char **)NULL; - int32_t nstrings = 0; - jobject filenames; - jobject ret = NULL; - int32_t i; - jsize len; - jboolean isCopy=JNI_FALSE; - - /* - * If the length of the byte array is 0 just return a null - */ - len = (*env)->GetArrayLength(env, bytes); - if (len == 0) { - return NULL; - } - - value = (*env)->GetByteArrayElements(env, bytes, &isCopy); - if (JNU_IsNull(env, value)) { - return NULL; - } - - AWT_LOCK(); - - tp.encoding = XInternAtom(awt_display, "STRING", False); - tp.value = (unsigned char *)value; - tp.nitems = len; - tp.format = 8; - - /* - * Convert the byte stream into a list of X11 strings - */ - if (XTextPropertyToStringList(&tp, &strings, &nstrings) == 0 || - nstrings == 0) - { - (*env)->ReleaseByteArrayElements(env, bytes, value, JNI_ABORT); - AWT_UNLOCK(); - return NULL; - } - - (*env)->ReleaseByteArrayElements(env, bytes, value, JNI_ABORT); - - filenames = (*env)->NewObjectArray(env, nstrings, string, NULL); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - goto wayout; - } - - if (JNU_IsNull(env, filenames)) { - goto wayout; - } - - /* - * Actuall conversion code per X11 String - */ - for (i = 0; i < nstrings; i++) { - jstring string = (*env)->NewStringUTF(env, - (const char *)strings[i]); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - goto wayout; - } - - if (JNU_IsNull(env, string)) { - goto wayout; - } - - (*env)->SetObjectArrayElement(env, filenames, i, string); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - goto wayout; - } - - (*env)->DeleteLocalRef(env, string); - } - - ret = filenames; - wayout: - /* - * Clean up and return - */ - XFreeStringList(strings); - AWT_UNLOCK(); - return ret; -} - -DECLARE_JAVA_CLASS(dataTransfererClazz, "sun/awt/datatransfer/DataTransferer") - -/** - * Returns a local reference to the singleton DataTransferer instance. - * The caller should delete the reference when done. - */ -static jobject -get_data_transferer(JNIEnv* env) { - jobject transferer = NULL; - - DECLARE_STATIC_OBJECT_JAVA_METHOD(getInstanceMethodID, dataTransfererClazz, - "getInstance", - "()Lsun/awt/datatransfer/DataTransferer;"); - - transferer = (*env)->CallStaticObjectMethod(env, clazz, getInstanceMethodID); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - DASSERT(!JNU_IsNull(env, transferer)); - - return transferer; -} - -static jobject -call_convertData(JNIEnv* env, jobject source, jobject contents, jlong format, - jobject formatMap) { - jobject transferer = get_data_transferer(env); - jobject ret = NULL; - DECLARE_OBJECT_JAVA_METHOD(convertDataMethodID, dataTransfererClazz, - "convertData", - "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B"); - - ret = (*env)->CallObjectMethod(env, transferer, convertDataMethodID, - source, contents, format, formatMap, - awt_currentThreadIsPrivileged(env)); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->DeleteLocalRef(env, transferer); - - return ret; -} - -static void -process_convert_data_requests() { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_4); - jobject transferer = get_data_transferer(env); - - DECLARE_VOID_JAVA_METHOD(processDataConversionRequestsMethodID, - dataTransfererClazz, - "processDataConversionRequests", - "()V"); - - (*env)->CallVoidMethod(env, transferer, - processDataConversionRequestsMethodID); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->DeleteLocalRef(env, transferer); -} - -Boolean -awt_convertData(Widget w, Atom * selection, Atom * target, Atom * type, - XtPointer * value, unsigned long *length, int32_t *format) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - Display* dpy = XtDisplay(w); - awt_convertDataCallbackStruct* structPtr = NULL; - - if (XFindContext(dpy, *selection, awt_convertDataContext, - (XPointer*)&structPtr) == XCNOMEM || structPtr == NULL) { - return False; - } - - if ((*env)->PushLocalFrame(env, 2) < 0) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - return False; - } - - if (*target == XA_TARGETS) { - jlongArray formats = structPtr->formats; - jsize count; - jlong* targets; - jboolean isCopy; - -#ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */ - Atom* aValue; - jlong* saveTargets; - jsize i; -#endif - - if (JNU_IsNull(env, formats)) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - count = (*env)->GetArrayLength(env, formats); - if (count == 0) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - targets = (*env)->GetLongArrayElements(env, formats, &isCopy); - - *type = XA_ATOM; - *format = 32; - -#ifdef _LP64 - *value = XtMalloc(count * sizeof(Atom)); - memcpy((void *)*value, (void *)targets, count * sizeof(Atom)); -#else - *value = aValue = (Atom *)XtMalloc(count * sizeof(Atom)); - saveTargets = targets; - for (i = 0; i < count; i++, aValue++, targets++) { - *aValue = (Atom)*targets; - } - targets = saveTargets; -#endif - (*env)->ReleaseLongArrayElements(env, formats, targets, JNI_ABORT); - - *length = count; - - } else if (*target == XInternAtom(dpy, _XA_DELETE, False)) { - - /* - * acknowledge the DELETE target here ... the "delete" semantic - * of move will take place after the drop is complete. - */ - - *type = XInternAtom(dpy, _XA_NULL, False); - *length = 0; - *value = (XtPointer)NULL; - /* Uninitialized format can cause crash in Xt conversion code. */ - *format = 8; - } else if (*target == XInternAtom(dpy, _XA_HOSTNAME, False)) { - struct utsname name; - XTextProperty tp; - - uname(&name); - - if (!XStringListToTextProperty((char **)&name.nodename, 1, &tp)) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - *value = (XtPointer)XtCalloc(tp.nitems, sizeof(char)); - - memcpy((void *)*value, (const void *)tp.value, tp.nitems); - - XFree((void *)tp.value); - - *type = tp.encoding; - *length = tp.nitems + 1; - *format = tp.format; - } else if (*target == XInternAtom(dpy, _XA_FILENAME, False) || - *target == XInternAtom(dpy, _DT_FILENAME, False)) { - - /* - * Convert the internal representation to an File Name. - * The data returned from dataConvert is a an array of - * null separated bytes. Each series of bytes is a string - * that is then converted to an XString which are then put - * into an XStringList and put into an XTextProperty for - * usage in other programs. - * - * It would be desireable to have dataConvert to this conversion - * but it isn't possible to return a byte array that represents - * the XTextProperty. - */ - jbyteArray data; - - /* - * Fix for 4513976. - * Type None should be used instead of XT_CONVERT_FAIL - * to report conversion failure. - */ - /* assume forthcoming error */ - *type = None; - *value = (XtPointer)NULL; - *length = 0; - *format = 8; - - data = call_convertData(env, structPtr->source, structPtr->transferable, - (jlong)*target, structPtr->formatMap); - - /* error test */ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - (*env)->PopLocalFrame(env, NULL); - return False; - } - if (JNU_IsNull(env, data)) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - - if (convertFileType(data, type, value, length, format) == False) { - (*env)->PopLocalFrame(env, NULL); - return False; - } - } else { - jbyteArray bytes = NULL; - jbyte* copy = NULL; - - /* - * Fix for 4513976. - * Type None should be used instead of XT_CONVERT_FAIL - * to report conversion failure. - */ - *type = None; /* assume forthcoming error */ - *value = (XtPointer)NULL; - *length = 0; - *format = 8; - - bytes = call_convertData(env, structPtr->source, structPtr->transferable, - (jlong)*target, structPtr->formatMap); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - if (bytes == NULL) { - (*env)->PopLocalFrame(env, NULL); - return False; - } else { - jsize len = (*env)->GetArrayLength(env, bytes); - - if (len == 0) { - *type = *target; - *format = 8; - (*env)->PopLocalFrame(env, NULL); - return True; - } - - copy = (jbyte*)XtCalloc(1, len * sizeof(jbyte)); - if (copy == (jbyte*)NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - (*env)->GetByteArrayRegion(env, (jbyteArray)bytes, 0, len, copy); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - XtFree((void *)copy); - (*env)->PopLocalFrame(env, NULL); - return False; - } - - *value = (XtPointer)copy; - *type = *target; - *length = len; - *format = 8; - } - } - - (*env)->PopLocalFrame(env, NULL); - return True; -} - - -jlongArray -getSelectionTargetsHelper(JNIEnv* env, XtPointer value, unsigned long length) -{ - Atom* targets = (Atom*)value; - jlongArray targetArray = NULL; - jlong* checkedTargets = NULL; - size_t count = 0, i = 0, j = 0; - - /* Get rid of zero atoms if there are any. */ - for (; i < length; i++) { - if (targets[i] != 0) { - count++; - } - } - checkedTargets = calloc(count, sizeof(jlong)); - if (checkedTargets == NULL) { - JNU_ThrowOutOfMemoryError(env, ""); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } else { - for (i = 0; i < length; i++) { - if (targets[i] != 0) { - checkedTargets[j++] = targets[i]; - } - } - - DASSERT(j == count); - - if ((*env)->EnsureLocalCapacity(env, 1) >= 0) { - - targetArray = (*env)->NewLongArray(env, count); - - if (!JNU_IsNull(env, targetArray)) { - (*env)->SetLongArrayRegion(env, targetArray, 0, count, - checkedTargets); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - - (*env)->DeleteLocalRef(env, targetArray); - targetArray = NULL; - } - } - } - free(checkedTargets); - } - - return targetArray; -} - -static void -get_selection_targets_callback(Widget w, XtPointer client_data, Atom* selection, - Atom* type, XtPointer value, - unsigned long* length, int32_t* format) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject* pReturnArray = (jobject*)client_data; - SelectionStatus status = SelectionFailure; - - /* - * It is highly unlikely that TARGETS will ever be passed even though that - * was what was requested. However, XA_ATOM ("ATOM") is likely. - * Actually they are the same so treat them as such. See XToolKit - * Intrinsic Manual on XtSelectionCallbackProc for more details on type. - */ - if (*type == XA_TARGETS || *type == XA_ATOM) { - jlongArray targetArray = getSelectionTargetsHelper(env, value, *length); - if (!JNU_IsNull(env, targetArray)) { - *pReturnArray = (*env)->NewGlobalRef(env, targetArray); - status = SelectionSuccess; - (*env)->DeleteLocalRef(env, targetArray); - } - } else if (*type == XT_CONVERT_FAIL) { - status = SelectionOwnerTimedOut; - } else { - /* - * A part of the fix for 4259272. - * Actually Xt Intrinsics says about XtSelectionCallback that - * "if there is no owner for the specified selection, or that owner - * cannot convert the selected data to the requested type, then this - * callback is called with value NULL and length zero". - * But we report success if type is not TARGETS, XA_ATOM or XT_CONVERT_FAIL, - * and we should not change this behaviour. We just return zero-length - * array instead of null, because null denotes that we could not get - * selection targets at the time of tracking changes of available on - * the selection data flavors. - */ - jlongArray targetArray = (*env)->NewLongArray(env, 0); - *pReturnArray = (*env)->NewGlobalRef(env, targetArray); - /* - * Fix for 4655996. - * Report success if there is no owner for this selection or the owner - * fails to provide target types. - */ - status = SelectionSuccess; - (*env)->DeleteLocalRef(env, targetArray); - } - - if (value != NULL) { - XtFree(value); - value = NULL; - } - - set_selection_status(status); -} - -static void -get_selection_data_callback(Widget w, XtPointer client_data, Atom * selection, - Atom * type, XtPointer value, unsigned long *length, - int32_t *format) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject* pData = (jobject*)client_data; - SelectionStatus status = SelectionFailure; - - if (*type == XT_CONVERT_FAIL) { - status = SelectionOwnerTimedOut; - } else if (*type != None) { - if ((*env)->EnsureLocalCapacity(env, 1) >= 0) { - jsize size = (*length <= INT_MAX) ? *length : INT_MAX; - jbyteArray array = (*env)->NewByteArray(env, size); - - if (!JNU_IsNull(env, array)) { - (*env)->SetByteArrayRegion(env, array, 0, size, (jbyte*)value); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } else { - *pData = (*env)->NewGlobalRef(env, array); - status = SelectionSuccess; - } - - (*env)->DeleteLocalRef(env, array); - } - } - } - - if (value != NULL) { - XtFree(value); - value = NULL; - } - - set_selection_status(status); -} - -static int32_t -wait_for_selection_event(void *data) { - process_convert_data_requests(); - return get_selection_status() != SelectionPending; -} - -jlongArray -get_selection_targets(JNIEnv *env, Atom selection, Time time_stamp) { - jlongArray ret = NULL; - jlongArray targets = NULL; - SelectionStatus status = SelectionPending; - - AWT_LOCK(); - - XtAppSetSelectionTimeout(awt_appContext, - JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit", - "getDatatransferTimeout", "()I").i); - - set_selection_status(SelectionPending); - XtGetSelectionValue(awt_root_shell, selection, XA_TARGETS, - get_selection_targets_callback, (XtPointer)&targets, - time_stamp); - - awt_MToolkit_modalWait(wait_for_selection_event, NULL); - status = get_selection_status(); - - AWT_FLUSH_UNLOCK(); - - if (!JNU_IsNull(env, targets)) { - ret = (*env)->NewLocalRef(env, targets); - (*env)->DeleteGlobalRef(env, targets); - } - - switch (status) { - case SelectionSuccess: - break; - case SelectionFailure: - JNU_ThrowByName(env, "java/lang/IllegalStateException", - "Failed to get selection targets"); - break; - case SelectionOwnerTimedOut: - // return an empty array of targets if the selection owner timed out - ret = (*env)->NewLongArray(env, 0); - break; - default: - JNU_ThrowByName(env, "java/lang/IllegalStateException", - "Unexpected selection status"); - break; - } - - return ret; -} - -jbyteArray -get_selection_data(JNIEnv *env, Atom selection, Atom target, Time time_stamp) { - jbyteArray ret = NULL; - jbyteArray data = NULL; - SelectionStatus status = SelectionPending; - - AWT_LOCK(); - - XtAppSetSelectionTimeout(awt_appContext, - JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit", - "getDatatransferTimeout", "()I").i); - - set_selection_status(SelectionPending); - XtGetSelectionValue(awt_root_shell, selection, target, - get_selection_data_callback, - (XtPointer)&data, time_stamp); - - awt_MToolkit_modalWait(wait_for_selection_event, NULL); - status = get_selection_status(); - - AWT_FLUSH_UNLOCK(); - - if (!JNU_IsNull(env, data)) { - ret = (*env)->NewLocalRef(env, data); - (*env)->DeleteGlobalRef(env, data); - } - - switch (status) { - case SelectionSuccess: - break; - case SelectionFailure: - JNU_ThrowIOException(env, "Failed to get selection data"); - break; - case SelectionOwnerTimedOut: - JNU_ThrowIOException(env, "Selection owner timed out"); - break; - default: - JNU_ThrowIOException(env, "Unexpected selection status"); - break; - } - - return ret; -} - -void -awt_cleanupConvertDataContext(JNIEnv *env, Atom selectionAtom) { - awt_convertDataCallbackStruct* structPtr = NULL; - - if (XFindContext(awt_display, selectionAtom, awt_convertDataContext, - (XPointer*)&structPtr) == 0 && structPtr != NULL) { - - (*env)->DeleteGlobalRef(env, structPtr->source); - (*env)->DeleteGlobalRef(env, structPtr->transferable); - (*env)->DeleteGlobalRef(env, structPtr->formatMap); - (*env)->DeleteGlobalRef(env, structPtr->formats); - free(structPtr); - } - /* - * Xlib Programming Manual says that it is better to erase - * the current entry with XDeleteContext() before XSaveContext(). - */ - XDeleteContext(awt_display, selectionAtom, awt_convertDataContext); - if (XSaveContext(awt_display, selectionAtom, awt_convertDataContext, - (XPointer)NULL) == XCNOMEM) { - JNU_ThrowInternalError(env, "XError"); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -static Bool exitSecondaryLoop = True; - -/* - * This predicate procedure allows the Toolkit thread to process specific events - * while it is blocked waiting for the event dispatch thread to process - * a SunDropTargetEvent. We need this to prevent deadlock when the client code - * processing SunDropTargetEvent sets or gets the contents of the system - * clipboard/selection. In this case the event dispatch thread waits for the - * Toolkit thread to process PropertyNotify or SelectionNotify events. - */ -static Bool -secondary_loop_event(Display* dpy, XEvent* event, char* arg) { - return (event->type == SelectionNotify || - event->type == SelectionClear || - event->type == PropertyNotify) ? True : False; -} - - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MToolkitThreadBlockedHandler_enter(JNIEnv *env, jobject this) { - DASSERT(exitSecondaryLoop && awt_currentThreadIsPrivileged(env)); - exitSecondaryLoop = False; - while (!exitSecondaryLoop) { - XEvent event; - while (XCheckIfEvent(awt_display, &event, secondary_loop_event, NULL)) { - XtDispatchEvent(&event); - } - AWT_WAIT(AWT_DND_POLL_INTERVAL); - } -} - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MToolkitThreadBlockedHandler_exit(JNIEnv *env, jobject this) { - DASSERT(!exitSecondaryLoop && !awt_currentThreadIsPrivileged(env)); - exitSecondaryLoop = True; - AWT_NOTIFY_ALL(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_DataTransferer.h --- a/jdk/src/solaris/native/sun/awt/awt_DataTransferer.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - * Copyright 2000-2004 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. - */ - -#ifndef AWT_DATATRANSFERER_H -#define AWT_DATATRANSFERER_H - -#include -#include - -#define _XA_DELETE "DELETE" -#define _XA_FILENAME "FILE_NAME" -#define _XA_HOSTNAME "HOST_NAME" -#define _XA_NULL "NULL" -#define _DT_FILENAME "_DT_NETFILE" - -#define AWT_DND_POLL_INTERVAL ((unsigned long)250) /* milliseconds */ - -typedef struct { - jobject source; - jobject transferable; - jobject formatMap; - jlongArray formats; -} awt_convertDataCallbackStruct; - -extern XContext awt_convertDataContext; /* XContext is not 64 bits */ - -extern Atom XA_TARGETS; - -/* - * Single routine to convert to target FILE_NAME or _DT_FILENAME - */ -Boolean -convertFileType(jbyteArray data, Atom * type, XtPointer * value, - unsigned long *length, int32_t *format); - -Boolean -awt_convertData(Widget w, Atom * selection, Atom * target, Atom * type, - XtPointer * value, unsigned long *length, int32_t *format); - -jlongArray -get_selection_targets(JNIEnv *env, Atom selection, Time time_stamp); - -jlongArray -getSelectionTargetsHelper(JNIEnv* env, XtPointer value, unsigned long length); - -jbyteArray -get_selection_data(JNIEnv *env, Atom selection, Atom format, Time time_stamp); - -void -awt_cleanupConvertDataContext(JNIEnv *env, Atom selectionAtom); - -/* - * NOTE: You need these macros only if you take care of performance, since they - * provide proper caching. Otherwise you can use JNU_CallMethodByName etc. - */ - -/* - * This macro defines a function which returns the class for the specified - * class name with proper caching and error handling. - */ -#define DECLARE_JAVA_CLASS(javaclazz, name) \ -static jclass \ -get_ ## javaclazz(JNIEnv* env) { \ - static jclass javaclazz = NULL; \ - \ - if (JNU_IsNull(env, javaclazz)) { \ - jclass javaclazz ## Local = (*env)->FindClass(env, name); \ - \ - if (!JNU_IsNull(env, javaclazz ## Local)) { \ - javaclazz = (jclass)(*env)->NewGlobalRef(env, javaclazz ## Local); \ - (*env)->DeleteLocalRef(env, javaclazz ## Local); \ - if (JNU_IsNull(env, javaclazz)) { \ - JNU_ThrowOutOfMemoryError(env, ""); \ - } \ - } \ - \ - if (!JNU_IsNull(env, ((*env)->ExceptionOccurred(env)))) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - } \ - \ - DASSERT(!JNU_IsNull(env, javaclazz)); \ - \ - return javaclazz; \ -} - -/* - * The following macros defines blocks of code which retrieve a method of the - * specified class identified with the specified name and signature. - * The specified class should be previously declared with DECLARE_JAVA_CLASS. - * These macros should be placed at the beginning of a block, after definition - * of local variables, but before the code begins. - */ -#define DECLARE_VOID_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - \ - if (JNU_IsNull(env, method)) { \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return; \ - } \ - \ - method = (*env)->GetMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return; \ - } \ - } - -#define DECLARE_BOOLEAN_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - \ - if (JNU_IsNull(env, method)) { \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return False; \ - } \ - \ - method = (*env)->GetMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return False; \ - } \ - } - -#define DECLARE_JINT_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - \ - if (JNU_IsNull(env, method)) { \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return java_awt_dnd_DnDConstants_ACTION_NONE; \ - } \ - \ - method = (*env)->GetMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return java_awt_dnd_DnDConstants_ACTION_NONE; \ - } \ - } - -#define DECLARE_OBJECT_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - \ - if (JNU_IsNull(env, method)) { \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return NULL; \ - } \ - \ - method = (*env)->GetMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return NULL; \ - } \ - } - -#define DECLARE_STATIC_OBJECT_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return NULL; \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - method = (*env)->GetStaticMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return NULL; \ - } \ - } - -#define DECLARE_STATIC_VOID_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return; \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - method = (*env)->GetStaticMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return; \ - } \ - } - -#define DECLARE_STATIC_JINT_JAVA_METHOD(method, javaclazz, name, signature) \ - static jmethodID method = NULL; \ - jclass clazz = get_ ## javaclazz(env); \ - \ - if (JNU_IsNull(env, clazz)) { \ - return java_awt_dnd_DnDConstants_ACTION_NONE; \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - method = (*env)->GetStaticMethodID(env, clazz, name, signature); \ - \ - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \ - (*env)->ExceptionDescribe(env); \ - (*env)->ExceptionClear(env); \ - } \ - \ - if (JNU_IsNull(env, method)) { \ - DASSERT(False); \ - return java_awt_dnd_DnDConstants_ACTION_NONE; \ - } \ - } - -#endif /* AWT_DATATRANSFERER_H */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c --- a/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c Wed Jul 05 16:41:30 2017 +0200 @@ -29,7 +29,7 @@ #include "awt_p.h" #include "java_awt_Component.h" -#include "sun_awt_motif_MComponentPeer.h" +//#include "sun_awt_motif_MComponentPeer.h" #include "awt_Component.h" diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_FileDialog.c --- a/jdk/src/solaris/native/sun/awt/awt_FileDialog.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,925 +0,0 @@ -/* - * Copyright 1995-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include -#include -#include -#include -#include -#include "awt_p.h" -#include "java_awt_FileDialog.h" -#include "java_awt_event_MouseWheelEvent.h" -#include "sun_awt_motif_MFileDialogPeer.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "multi_font.h" - -#include "awt_Component.h" - -#include -#include -#include - -#define MAX_DIR_PATH_LEN 1024 - -extern void Text_handlePaste(Widget w, XtPointer client_data, XEvent * event, - Boolean * cont); - -extern struct MComponentPeerIDs mComponentPeerIDs; - -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* fieldIDs for FileDialog fields and methods that may be accessed from C */ -static struct FileDialogIDs { - jfieldID mode; - jfieldID file; -} fileDialogIDs; - -/* the field to store the default search procedure */ -static XmSearchProc DefaultSearchProc = NULL; - -/* mouse wheel handler for scrolling */ -void File_handleWheel(Widget w, XtPointer client_data, XEvent* event, Boolean* cont); - -/* - * Class: java_awt_FileDialog - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for FileDialog.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_FileDialog_initIDs - (JNIEnv *env, jclass cls) -{ - fileDialogIDs.mode = (*env)->GetFieldID(env, cls, "mode", "I"); - fileDialogIDs.file = - (*env)->GetFieldID(env, cls, "file", "Ljava/lang/String;"); - - DASSERT(fileDialogIDs.mode != NULL); - DASSERT(fileDialogIDs.file != NULL); -} - -/* - * client_data is MFileDialogPeer instance pointer - */ -static void -FileDialog_OK(Widget w, - void *client_data, - XmFileSelectionBoxCallbackStruct * call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) client_data; - struct FrameData *fdata; - char *file; - jstring jstr; - XmStringContext stringContext; - XmStringDirection direction; - XmStringCharSet charset; - Boolean separator; - - fdata = (struct FrameData *)JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) - return; - - if (!XmStringInitContext(&stringContext, call_data->value)) - return; - - if (!XmStringGetNextSegment(stringContext, &file, &charset, - &direction, &separator)) - file = NULL; - - if (file == NULL) - jstr = NULL; - else - jstr = JNU_NewStringPlatform(env, (const char *) file); - - if (jstr != 0) { - JNU_CallMethodByName(env, NULL, this, "handleSelected", - "(Ljava/lang/String;)V", jstr); - (*env)->DeleteLocalRef(env, jstr); - } - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - XmStringFreeContext(stringContext); - if (file != NULL) - XtFree(file); -} - -/* - * client_data is MFileDialogPeer instance pointer - */ -static void -FileDialog_CANCEL(Widget w, - void *client_data, - XmFileSelectionBoxCallbackStruct * call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) client_data; - struct FrameData *fdata; - - fdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, "handleCancel", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - - -/* - * client_data is MFileDialogPeer instance pointer - */ -static void -FileDialog_quit(Widget w, - XtPointer client_data, - XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, "handleQuit", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -static void -setDeleteCallback(jobject this, struct FrameData *wdata) -{ - Atom xa_WM_DELETE_WINDOW; - Atom xa_WM_PROTOCOLS; - - XtVaSetValues(wdata->winData.shell, - XmNdeleteResponse, XmDO_NOTHING, - NULL); - xa_WM_DELETE_WINDOW = XmInternAtom(XtDisplay(wdata->winData.shell), - "WM_DELETE_WINDOW", False); - xa_WM_PROTOCOLS = XmInternAtom(XtDisplay(wdata->winData.shell), - "WM_PROTOCOLS", False); - - XmAddProtocolCallback(wdata->winData.shell, - xa_WM_PROTOCOLS, - xa_WM_DELETE_WINDOW, - FileDialog_quit, (XtPointer) this); -} - -void -setFSBDirAndFile(Widget w, char *dir, char *file, - XmString *ffiles, int count) -{ - Widget textField, list; - char dirbuf[MAX_DIR_PATH_LEN]; - XmString xim, item; - size_t lastSelect; - - dirbuf[0] = (char) '\0'; - - if (dir != NULL && strlen(dir) < MAX_DIR_PATH_LEN) - strcpy(dirbuf, dir); - - /* -----> make sure dir ends in '/' */ - if (dirbuf[0] != (char) '\0') { - if (dirbuf[strlen(dirbuf) - 1] != (char) '/') - strcat(dirbuf, "/"); - } else { - getcwd(dirbuf, MAX_DIR_PATH_LEN - 16); - strcat(dirbuf, "/"); - } - - strcat(dirbuf, "[^.]*"); - xim = XmStringCreate(dirbuf, XmSTRING_DEFAULT_CHARSET); - XtVaSetValues(w, XmNdirMask, xim, NULL); - - if (ffiles != NULL) - XtVaSetValues(w, - XmNfileListItems, (count > 0) ? ffiles : NULL, - XmNfileListItemCount, count, - XmNlistUpdated, True, NULL); - - XmStringFree(xim); - - /* - * Select the filename from the filelist if it exists. - */ - - textField = XmFileSelectionBoxGetChild(w, XmDIALOG_TEXT); - list = XmFileSelectionBoxGetChild(w, XmDIALOG_LIST); - - if (textField != 0 && file != 0) { - lastSelect = strlen(file); - XtVaSetValues(textField, XmNvalue, file, NULL); - XmTextFieldSetSelection(textField, 0, lastSelect, CurrentTime); - - item = XmStringCreateLocalized(file); - XmListSelectItem(list, item, NULL); - XmStringFree(item); - } -} - -static void -changeBackground(Widget w, void *bg) -{ - /* - ** This is a work-around for bug 4325443, caused by motif bug 4345559, - ** XmCombobox dosn't return all children, so give it some help ... - */ - Widget grabShell; - grabShell = XtNameToWidget(w, "GrabShell"); - if (grabShell != NULL) { - awt_util_mapChildren(grabShell, changeBackground, 0, (void *) bg); - } - - XmChangeColor(w, (Pixel) bg); -} - -void -ourSearchProc(Widget w, XtPointer p) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - struct FrameData *wdata; - XtPointer peer; - jobject this; - jboolean res; - char * dir = NULL; - jstring dir_o; - int32_t i, filecount = 0; - XmString * filelist = NULL; - jobjectArray nffiles = NULL; - jclass clazz = NULL; - jstring jfilename = NULL; - char * cfilename = NULL; - XmFileSelectionBoxCallbackStruct * vals = (XmFileSelectionBoxCallbackStruct *)p; - - XtVaGetValues(w, XmNuserData, &peer, NULL); - this = (jobject)peer; - if (JNU_IsNull(env, this) ) { - return; - } - wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == 0 || - wdata->winData.comp.widget == 0 || - wdata->winData.shell == 0 || p == NULL ) { - return; - } - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - - if (DefaultSearchProc != NULL) { - /* Unmap the widget temporary. If it takes a long time to generate - the list items some visual artifacts may be caused. However, - we need to do this to have the widget that works as we expect. - */ - XtSetMappedWhenManaged(w, False); - /* Call the default Motif search procedure to take the - native filtered file list. - */ - DefaultSearchProc(w, vals); - XtSetMappedWhenManaged(w, True); - XtVaGetValues(w, - XmNlistItemCount, &filecount, - XmNlistItems, &filelist, - NULL); - /* We need to construct the new String array to pass it to - the Java code. - */ - clazz = (*env)->FindClass(env, "java/lang/String"); - /* It is ok if filecount is 0. */ - nffiles = (*env)->NewObjectArray(env, filecount, clazz, NULL); - if (JNU_IsNull(env, nffiles)) { - nffiles = NULL; - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - } else { - for (i = 0; i < filecount; i++) { - DASSERT(filelist[i] != NULL); - - XmStringGetLtoR(filelist[i], XmFONTLIST_DEFAULT_TAG, &cfilename); - jfilename = JNU_NewStringPlatform(env, cfilename); - - if (JNU_IsNull(env, jfilename)) { - XtFree(cfilename); - nffiles = NULL; - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - break; - } - - (*env)->SetObjectArrayElement(env, nffiles, i, jfilename); - - (*env)->DeleteLocalRef(env, jfilename); - XtFree(cfilename); - } - } - } - - XmStringGetLtoR(vals->dir, XmFONTLIST_DEFAULT_TAG, &dir); - dir_o = JNU_NewStringPlatform(env, dir); - res = JNU_CallMethodByName(env, NULL, this, - "proceedFiltering", - "(Ljava/lang/String;[Ljava/lang/String;Z)Z", - dir_o, nffiles, - awt_currentThreadIsPrivileged(env)).z; - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - XtVaSetValues(w, - XmNlistUpdated, res, - NULL); - (*env)->DeleteLocalRef(env, dir_o); - free(dir); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_create - (JNIEnv *env, jobject this, jobject parent) -{ - struct FrameData *fdata; - struct CanvasData *wdata; - int32_t argc; -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - Widget child, textField, dirList, fileList; - XmString xim; - Pixel bg; - jobject target; - jstring file; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; -#ifndef NOMODALFIX - extern void awt_shellPoppedUp(Widget shell, XtPointer c, XtPointer d); - extern void awt_shellPoppedDown(Widget shell, XtPointer c, XtPointer d); -#endif NOMODALFIX - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, parent) || JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - adata = copyGraphicsConfigToPeer(env, this); - - wdata = (struct CanvasData *) JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - - fdata = ZALLOC(FrameData); - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,fdata); - - if (fdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - XtVaGetValues(wdata->comp.widget, XmNbackground, &bg, NULL); - - /* - * XXX: this code uses FrameData but doesn't bother to init a lot - * of its memebers. This confuses the hell out of the code in - * awt_TopLevel.c that gets passes such half-inited FrameData. - */ - fdata->decor = MWM_DECOR_ALL; - - argc = 0; - XtSetArg(args[argc], XmNmustMatch, False); - argc++; - XtSetArg(args[argc], XmNautoUnmanage, False); - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); - argc++; - XtSetArg(args[argc], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, adata->awt_visInfo.screen)); - argc++; - XtSetArg(args[argc], XmNuserData, (XtPointer)globalRef); - argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); - argc++; - - XtSetArg(args[argc], XmNbuttonFontList, getMotifFontList()); - argc++; - XtSetArg(args[argc], XmNlabelFontList, getMotifFontList()); - argc++; - XtSetArg(args[argc], XmNtextFontList, getMotifFontList()); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - - fdata->winData.comp.widget = XmCreateFileSelectionDialog(wdata->shell, - "", - args, - argc); - fdata->winData.shell = XtParent(fdata->winData.comp.widget); - awt_util_mapChildren(fdata->winData.shell, changeBackground, 0, - (void *) bg); - child = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, - XmDIALOG_HELP_BUTTON); - - /* We should save a pointer to the default search procedure - to do some things that we cannot do else. For instance, - apply the native pattern. - */ - XtVaGetValues(fdata->winData.comp.widget, - XmNfileSearchProc, &DefaultSearchProc, - NULL); - XtVaSetValues(fdata->winData.comp.widget, - XmNfileSearchProc, ourSearchProc, - NULL); - - /* - * Get textfield in FileDialog. - */ - textField = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, - XmDIALOG_TEXT); - if (child != NULL) { - /* - * Workaround for Bug Id 4415659. - * If the dialog child is unmanaged before the dialog is managed, - * the Motif drop site hierarchy may be broken if we associate - * a drop target with the dialog before it is shown. - */ - XtSetMappedWhenManaged(fdata->winData.shell, False); - XtManageChild(fdata->winData.comp.widget); - XtUnmanageChild(fdata->winData.comp.widget); - XtSetMappedWhenManaged(fdata->winData.shell, True); - XtUnmanageChild(child); - } - if (!awtJNI_IsMultiFont(env, awtJNI_GetFont(env, this))) { - /* This process should not be done other than English language - locale. */ - child = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, - XmDIALOG_DEFAULT_BUTTON); - if (child != NULL) { - XmString xim; - - switch ((*env)->GetIntField(env, target, fileDialogIDs.mode)) { - case java_awt_FileDialog_LOAD: - xim = XmStringCreate("Open", "labelFont"); - XtVaSetValues(child, XmNlabelString, xim, NULL); - XmStringFree(xim); - break; - - case java_awt_FileDialog_SAVE: - xim = XmStringCreate("Save", "labelFont"); - XtVaSetValues(child, XmNlabelString, xim, NULL); - XmStringFree(xim); - break; - - default: - break; - } - } - } - XtAddCallback(fdata->winData.comp.widget, - XmNokCallback, - (XtCallbackProc) FileDialog_OK, - (XtPointer) globalRef); - XtAddCallback(fdata->winData.comp.widget, - XmNcancelCallback, - (XtCallbackProc) FileDialog_CANCEL, - (XtPointer) globalRef); - -#ifndef NOMODALFIX - XtAddCallback(fdata->winData.shell, - XtNpopupCallback, - awt_shellPoppedUp, - NULL); - XtAddCallback(fdata->winData.shell, - XtNpopdownCallback, - awt_shellPoppedDown, - NULL); -#endif NOMODALFIX - - setDeleteCallback(globalRef, fdata); - - if (textField != NULL) { - /* - * Insert event handler to correctly process cut/copy/paste keys - * such that interaction with our own clipboard mechanism will work - * properly. - * - * The Text_handlePaste() event handler is also used by both - * TextField/TextArea. - */ - XtInsertEventHandler(textField, - KeyPressMask, - False, Text_handlePaste, (XtPointer) globalRef, - XtListHead); - } - - /* To get wheel scrolling, we add an event handler to the directory list and - * file list widgets to handle mouse wheels */ - dirList = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, XmDIALOG_DIR_LIST); - if (dirList != NULL) { - XtAddEventHandler(dirList, ButtonPressMask, False, File_handleWheel, - (XtPointer) globalRef); - } - - fileList = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, XmDIALOG_LIST); - if (fileList != NULL) { - XtAddEventHandler(fileList, ButtonPressMask, False, File_handleWheel, - (XtPointer) globalRef); - } - - file = (*env)->GetObjectField(env, target, fileDialogIDs.file); - if (JNU_IsNull(env, file)) { - setFSBDirAndFile(fdata->winData.comp.widget, ".", "", NULL, -1); - } else { - char *fileString; - - fileString = (char *) JNU_GetStringPlatformChars(env, file, NULL); - setFSBDirAndFile(fdata->winData.comp.widget, ".", fileString, NULL, -1); - JNU_ReleaseStringPlatformChars(env, file, (const char *) fileString); - } - AWT_UNLOCK(); -} - -/* Event handler for making scrolling happen when the mouse wheel is rotated */ -void File_handleWheel(Widget w, XtPointer client_data, XEvent* event, Boolean* cont) { - unsigned int btn; - Widget scrolledWindow = NULL; - - /* only registered for ButtonPress, so don't need to check event type */ - btn = event->xbutton.button; - /* wheel up and wheel down show up as button 4 and 5, respectively */ - if (btn == 4 || btn == 5) { - scrolledWindow = XtParent(w); - if (scrolledWindow == NULL) { - return; - } - awt_util_do_wheel_scroll(scrolledWindow, - java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL, - 3, - btn == 4 ? -1 : 1); - } -} - - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: pReshape - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pReshape - (JNIEnv *env, jobject this, jint x, jint y, jint w, jint h) -{ - struct FrameData *wdata; - - AWT_LOCK(); - wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* GES: AVH's hack from awt_util.c: - * Motif ignores attempts to move a toplevel window to 0,0. - * Instead we set the position to 1,1. The expected value is - * returned by Frame.getBounds() since it uses the internally - * held rectangle rather than querying the peer. - */ - - if ((x == 0) && (y == 0)) { - XtVaSetValues(wdata->winData.shell, XmNx, 1, XmNy, 1, NULL); - } - XtVaSetValues(wdata->winData.shell, - XtNx, (XtArgVal) x, - XtNy, (XtArgVal) y, - NULL); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pDispose - (JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtUnmanageChild(wdata->winData.shell); - awt_util_consumeAllXEvents(wdata->winData.shell); - XtDestroyWidget(wdata->winData.shell); - free((void *) wdata); - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,NULL); - awtJNI_DeleteGlobalRef(env, this); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: pShow - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pShow - (JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - XmString dirMask = NULL; - - AWT_LOCK(); - wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtManageChild(wdata->winData.comp.widget); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: pHide - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pHide - (JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (XtIsManaged(wdata->winData.comp.widget)) { - XtUnmanageChild(wdata->winData.comp.widget); - } - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: setFileEntry - * Signature: (Ljava/lang/String;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_setFileEntry - (JNIEnv *env, jobject this, jstring dir, jstring file, jobjectArray ffiles) -{ - struct ComponentData *cdata; - char *cdir; - char *cfile; - char *cf; - struct FrameData *wdata; - int32_t length, i; - XmString * files = NULL; - jstring jf; - - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (wdata == NULL || wdata->winData.comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - cdir = (JNU_IsNull(env, dir)) - ? NULL - : (char *) JNU_GetStringPlatformChars(env, dir, NULL); - - cfile = (JNU_IsNull(env, file)) - ? NULL - : (char *) JNU_GetStringPlatformChars(env, file, NULL); - - if (ffiles != NULL) { - length = (*env)->GetArrayLength(env, ffiles); - files = (XmString*)calloc(length, sizeof(XmString)); - - for (i = 0; i < length; i++) { - jf = (jstring)(*env)->GetObjectArrayElement(env, ffiles, i); - cf = (char *) JNU_GetStringPlatformChars(env, jf, NULL); - - if ((*env)->GetStringLength(env, jf) == 0 && length == 1) { - length = 0; - files[0] = NULL; - } - else - files[i] = XmStringCreateLocalized(cf); - - if (cf) - JNU_ReleaseStringPlatformChars(env, jf, (const char *) cf); - } - - setFSBDirAndFile(wdata->winData.comp.widget, (cdir) ? cdir : "", - (cfile) ? cfile : "", files, length); - while(i > 0) { - XmStringFree(files[--i]); - } - if (files != NULL) { - free(files); - } - } - else - setFSBDirAndFile(wdata->winData.comp.widget, (cdir) ? cdir : "", - (cfile) ? cfile : "", NULL, -1); - - if (cdir) { - JNU_ReleaseStringPlatformChars(env, dir, (const char *) cdir); - } - - if (cfile) { - JNU_ReleaseStringPlatformChars(env, file, (const char *) cfile); - } - - AWT_FLUSH_UNLOCK(); -} - -static void -changeFont(Widget w, void *fontList) -{ - XtVaSetValues(w, XmNfontList, fontList, NULL); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: setFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_setFont - (JNIEnv *env, jobject this, jobject f) -{ - struct ComponentData *tdata; - struct FontData *fdata; - XmFontListEntry fontentry; - XmFontList fontlist; - char *err; - - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - fdata = awtJNI_GetFontData(env, f, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(env, err); - AWT_UNLOCK(); - return; - } - tdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (awtJNI_IsMultiFont(env, f)) { - if (fdata->xfs == NULL) { - fdata->xfs = awtJNI_MakeFontSet(env, f); - } - if (fdata->xfs != NULL) { - fontentry = XmFontListEntryCreate("labelFont", - XmFONT_IS_FONTSET, - (XtPointer) (fdata->xfs)); - fontlist = XmFontListAppendEntry(NULL, fontentry); - /* - * Some versions of motif have a bug in - * XmFontListEntryFree() which causes it to free more than it - * should. Use XtFree() instead. See O'Reilly's - * Motif Reference Manual for more information. - */ - XmFontListEntryFree(&fontentry); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - - if (fontlist != NULL) { - /* setting the fontlist in the FileSelectionBox is not good enough -- - you have to set the resource for all the descendants individually */ - awt_util_mapChildren(tdata->widget, changeFont, 1, (void *)fontlist); - XmFontListFree(fontlist); - } else { - JNU_ThrowNullPointerException(env, "NullPointerException"); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFileDialogPeer - * Method: insertReplaceFileDialogText - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText - (JNIEnv *env, jobject this, jstring l) -{ - struct ComponentData *cdata; - char *cl; - XmTextPosition start, end; - Widget textField; - jobject font; - - /* - * Replaces the text in the FileDialog's textfield with the passed - * string. - */ - - AWT_LOCK(); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - textField = XmFileSelectionBoxGetChild(cdata->widget, XmDIALOG_TEXT); - - if (textField == NULL) { - JNU_ThrowNullPointerException(env, "Null TextField in FileDialog"); - AWT_UNLOCK(); - return; - } - - font = awtJNI_GetFont(env, this); - - if (JNU_IsNull(env, l)) { - cl = NULL; - } else { - /* - * We use makePlatformCString() to convert unicode to EUC here, - * although output only components (Label/Button/Menu..) - * is not using make/allocCString() functions anymore. - * Because Motif TextFiled widget does not support multi-font - * compound string. - */ - - cl = (char *) JNU_GetStringPlatformChars(env, l, NULL); - } - - if (!XmTextGetSelectionPosition(textField, &start, &end)) { - start = end = XmTextGetInsertionPosition(textField); - } - XmTextReplace(textField, start, end, cl); - - if (cl != NULL && cl !="") { - JNU_ReleaseStringPlatformChars(env, l, cl); - } - AWT_FLUSH_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_GlobalCursorManager.c --- a/jdk/src/solaris/native/sun/awt/awt_GlobalCursorManager.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright 1999-2001 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. - */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "awt_Component.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "jni.h" -#include "jni_util.h" - -static jfieldID xID; -static jfieldID yID; - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct ComponentIDs componentIDs; -extern struct ContainerIDs containerIDs; -extern jobject getCurComponent(); - -/* - * Class: sun_awt_motif_MGlobalCursorManager - * Method: cacheInit - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MGlobalCursorManager_cacheInit - (JNIEnv *env, jclass cls) -{ - jclass clsDimension = (*env)->FindClass(env, "java/awt/Point"); - xID = (*env)->GetFieldID(env, clsDimension, "x", "I"); - yID = (*env)->GetFieldID(env, clsDimension, "y", "I"); -} - -/* - * Class: sun_awt_motif_MGlobalCursorManager - * Method: getCursorPos - * Signature: (Ljava/awt/Point;)Ljava/awt/Component - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MGlobalCursorManager_getCursorPos - (JNIEnv *env, jobject this, jobject point) -{ - Window root, rw, cw; - int32_t rx, ry, x, y; - uint32_t kbs; - - AWT_LOCK(); - root = RootWindow(awt_display, DefaultScreen(awt_display)); - XQueryPointer(awt_display, root, &rw, &cw, &rx, &ry, &x, &y, &kbs); - - (*env)->SetIntField(env, point, xID, rx); - (*env)->SetIntField(env, point, yID, ry); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MGlobalCursorManager - * Method: getCursorPos - * Signature: ()Ljava/awt/Component - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MGlobalCursorManager_findHeavyweightUnderCursor - (JNIEnv *env, jobject this) -{ - jobject target; - - AWT_LOCK(); - target = getCurComponent(); - AWT_FLUSH_UNLOCK(); - return target; -} - -/* - * Class: sun_awt_motif_MGlobalCursorManager - * Method: getLocationOnScreen - * Signature: (Ljava/awt/Component;)Ljava/awt/Point - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MGlobalCursorManager_getLocationOnScreen - (JNIEnv *env, jobject this, jobject component) -{ - jobject point = - (*env)->CallObjectMethod(env, component, - componentIDs.getLocationOnScreen); - return point; -} - -/* - * Class: sun_awt_motif_MGlobalCursorManager - * Method: findComponentAt - * Signature: (Ljava/awt/Container;II)Ljava/awt/Component - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MGlobalCursorManager_findComponentAt - (JNIEnv *env, jobject this, jobject container, jint x, jint y) -{ - /* - * Call private version of Container.findComponentAt with the following - * flag set: ignoreEnabled = false (i.e., don't return or recurse into - * disabled Components). - * NOTE: it may return a JRootPane's glass pane as the target Component. - */ - jobject component = - (*env)->CallObjectMethod(env, container, containerIDs.findComponentAt, - x, y, JNI_FALSE); - return component; -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_KeyboardFocusManager.c --- a/jdk/src/solaris/native/sun/awt/awt_KeyboardFocusManager.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - * Copyright 2000-2003 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. - */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "jni.h" -#include "jni_util.h" - -#include "awt_KeyboardFocusManager.h" -#include "java_awt_KeyboardFocusManager.h" -#include "java_awt_event_FocusEvent.h" -#include "awt_Component.h" -#include "canvas.h" -#include "awt_MToolkit.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; - -struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; - -/* - * Class: java_awt_KeyboardFocusManager - * Method: initIDs - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_java_awt_KeyboardFocusManager_initIDs - (JNIEnv *env, jclass cls) -{ - jclass keyclass = NULL; - - keyboardFocusManagerIDs.keyboardFocusManagerCls = (jclass) - (*env)->NewGlobalRef(env, cls); - keyboardFocusManagerIDs.shouldNativelyFocusHeavyweightMID = - (*env)->GetStaticMethodID(env, cls, "shouldNativelyFocusHeavyweight", - "(Ljava/awt/Component;Ljava/awt/Component;ZZJLsun/awt/CausedFocusEvent$Cause;)I"); - keyboardFocusManagerIDs.heavyweightButtonDownMID = - (*env)->GetStaticMethodID(env, cls, "heavyweightButtonDown", - "(Ljava/awt/Component;J)V"); - keyboardFocusManagerIDs.heavyweightButtonDownZMID = - (*env)->GetStaticMethodID(env, cls, "heavyweightButtonDown", - "(Ljava/awt/Component;JZ)V"); - keyboardFocusManagerIDs.markClearGlobalFocusOwnerMID = - (*env)->GetStaticMethodID(env, cls, "markClearGlobalFocusOwner", - "()Ljava/awt/Window;"); - - keyboardFocusManagerIDs.processSynchronousTransferMID = - (*env)->GetStaticMethodID(env, cls, "processSynchronousLightweightTransfer", - "(Ljava/awt/Component;Ljava/awt/Component;ZZJ)Z"); - - keyclass = (*env)->FindClass(env, "java/awt/event/KeyEvent"); - DASSERT (keyclass != NULL); - - keyboardFocusManagerIDs.isProxyActive = - (*env)->GetFieldID(env, keyclass, "isProxyActive", - "Z"); - - (*env)->DeleteLocalRef(env, keyclass); - - DASSERT(keyboardFocusManagerIDs.keyboardFocusManagerCls != NULL); - DASSERT(keyboardFocusManagerIDs.shouldNativelyFocusHeavyweightMID != - NULL); - DASSERT(keyboardFocusManagerIDs.heavyweightButtonDownMID != NULL); - DASSERT(keyboardFocusManagerIDs.heavyweightButtonDownZMID != NULL); - DASSERT(keyboardFocusManagerIDs.markClearGlobalFocusOwnerMID != NULL); - DASSERT(keyboardFocusManagerIDs.processSynchronousTransferMID != NULL); -} - -/* - * Class: java_awt_KeyboardFocusManager - * Method: getNativeFocusOwner - * Signature: ()Ljava/awt/Component; - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_KeyboardFocusManagerPeerImpl_getNativeFocusOwner - (JNIEnv *env, jclass cls) -{ - jobject l_peer; - - AWT_LOCK(); - l_peer = awt_canvas_getFocusOwnerPeer(); - AWT_UNLOCK(); - - return (l_peer != NULL) - ? (*env)->GetObjectField(env, l_peer, mComponentPeerIDs.target) - : NULL; -} - -/* - * Class: java_awt_KeyboardFocusManager - * Method: getNativeFocusedWindow - * Signature: ()Ljava/awt/Window; - */ -JNIEXPORT jobject JNICALL -Java_sun_awt_KeyboardFocusManagerPeerImpl_getNativeFocusedWindow - (JNIEnv *env, jclass cls) -{ - jobject l_peer; - - AWT_LOCK(); - l_peer = awt_canvas_getFocusedWindowPeer(); - AWT_UNLOCK(); - - return (l_peer != NULL) - ? (*env)->GetObjectField(env, l_peer, mComponentPeerIDs.target) - : NULL; -} - -/* - * Class: java_awt_KeyboardFocusManager - * Method: clearGlobalFocusOwner - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_KeyboardFocusManagerPeerImpl_clearNativeGlobalFocusOwner - (JNIEnv *env, jobject self, jobject activeWindow) -{ - /* Redirect focus to the focus proxy of the active Window. The effect - we want is for the active Window to remain active, but for none of - its children to be the focus owner. AWT maintains state to know - that any key events delivered after this call (but before focus is - re-established elsewhere) get ignored. */ - - Widget proxy; - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - - AWT_LOCK(); - - if (activeWindow != NULL) { - // Setting focus owner to proxy will be equivalent to having - // null focus owner in Java layer while we will still be - // able to receive key events. - proxy = findWindowsProxy(activeWindow, env); - - if (proxy != NULL) { - Widget curFocusWidget = XmGetFocusWidget(proxy); - if (curFocusWidget != NULL) { - callFocusHandler(curFocusWidget, FocusOut, NULL); - } - - // Disable all but proxy widgets - processTree(curFocusWidget, proxy, False); - - XmProcessTraversal(proxy, XmTRAVERSE_CURRENT); - } - } - - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Label.c --- a/jdk/src/solaris/native/sun/awt/awt_Label.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - * Copyright 1995-2001 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_Color.h" -#include "java_awt_Font.h" -#include "java_awt_Label.h" -#include "sun_awt_motif_MLabelPeer.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "awt_Component.h" - -#include "multi_font.h" -#include -#include - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -static char emptyString[] = ""; - - -/* - * Class: sun_awt_motif_MLabelPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MLabelPeer_create - (JNIEnv *env, jobject this, jobject parent) -{ - struct ComponentData *cdata; - struct ComponentData *wdata; - jobject target; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - - if (JNU_IsNull(env, target) || wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - cdata = ZALLOC(ComponentData); - if (cdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData,cdata); - - adata = copyGraphicsConfigToPeer(env, this); - - cdata->widget = XtVaCreateManagedWidget("", - xmLabelWidgetClass, wdata->widget, - XmNhighlightThickness, 0, - XmNalignment, XmALIGNMENT_BEGINNING, - XmNrecomputeSize, False, - XmNuserData, (XtPointer) globalRef, - XmNtraversalOn, True, - XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen), - XmNfontList, getMotifFontList(), - NULL); - XtSetMappedWhenManaged(cdata->widget, False); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MLabelPeer - * Method: setText - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MLabelPeer_setText - (JNIEnv *env, jobject this, jstring label) -{ - char *clabel = NULL; - char *clabelEnd; - struct ComponentData *cdata; - XmString xim = NULL; - jobject font; - Boolean isMultiFont; - - AWT_LOCK(); - - font = awtJNI_GetFont(env, this); - isMultiFont = awtJNI_IsMultiFont(env, font); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, label)) { - clabel = emptyString; - } else { - if (isMultiFont) { - if ((*env)->GetStringLength(env, label) <= 0) { - xim = XmStringCreateLocalized(""); - } else { - xim = awtJNI_MakeMultiFontString(env, label, font); - } - } else { - clabel = (char *) JNU_GetStringPlatformChars(env, label, NULL); - - /* scan for any \n's and terminate the string at that point */ - clabelEnd = strchr(clabel, '\n'); - if (clabelEnd != NULL) { - *clabelEnd = '\0'; - } - } - } - - if (!isMultiFont) { - xim = XmStringCreate(clabel, "labelFont"); - } - XtVaSetValues(cdata->widget, XmNlabelString, xim, NULL); - - if (!isMultiFont) { - /* Must test for "" too! */ - if (clabel != NULL && (*clabel != '\0')) { - JNU_ReleaseStringPlatformChars(env, label, (const char *) clabel); - } - } - XmStringFree(xim); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MLabelPeer - * Method: setAlignment - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MLabelPeer_setAlignment - (JNIEnv *env, jobject this, jint alignment) -{ - struct ComponentData *cdata; - - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - switch (alignment) { - case java_awt_Label_LEFT: - XtVaSetValues(cdata->widget, - XmNalignment, XmALIGNMENT_BEGINNING, - NULL); - break; - - case java_awt_Label_CENTER: - XtVaSetValues(cdata->widget, - XmNalignment, XmALIGNMENT_CENTER, - NULL); - break; - - case java_awt_Label_RIGHT: - XtVaSetValues(cdata->widget, - XmNalignment, XmALIGNMENT_END, - NULL); - break; - - default: - break; - } - - AWT_FLUSH_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_List.c --- a/jdk/src/solaris/native/sun/awt/awt_List.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,600 +0,0 @@ -/* - * Copyright 1995-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_List.h" -#include "java_awt_AWTEvent.h" -#include "sun_awt_motif_MListPeer.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "java_awt_event_MouseWheelEvent.h" -#include "canvas.h" - -#include "awt_Component.h" - -#include "multi_font.h" -#include -#include - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct ComponentIDs componentIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - - -/* - * client_data = MListPeer instance - */ -static void -Slist_callback(Widget w, XtPointer client_data, XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data; - - switch (cbs->reason) { - case XmCR_DEFAULT_ACTION: { - ConvertEventTimeAndModifiers converted; - - awt_util_convertEventTimeAndModifiers(cbs->event, &converted); - - if (cbs->event->type == KeyPress) { - /* When Default action comes from keyboard, no notification - * is given by motif that a selection has been made, even - * though, internally, the item will now be selected regardless - * of whether or not it was previously selected. ( on mouse - * generated DEFAULT ACTIONS the XmCR_BROWSE_SELECT is - * generated first ). - */ - JNU_CallMethodByName(env, NULL, (jobject) client_data - ,"handleListChanged" - ,"(I)V" - ,(cbs->item_position - 1)); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - - JNU_CallMethodByName(env, NULL, (jobject) client_data - ,"action" - ,"(IJI)V" - ,(cbs->item_position - 1) - ,converted.when - ,converted.modifiers); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - break; - } - case XmCR_BROWSE_SELECT: - JNU_CallMethodByName(env, NULL, (jobject) client_data - ,"handleListChanged" - ,"(I)V" - ,(cbs->item_position - 1)); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - break; - - case XmCR_MULTIPLE_SELECT: - JNU_CallMethodByName(env, NULL, (jobject) client_data - ,"handleListChanged" - ,"(I)V" - ,(cbs->item_position - 1)); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - break; - - default: - break; - } -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_create - (JNIEnv *env, jobject this, jobject parent) -{ - Cardinal argc; -#define MAX_ARGC 40 - Arg args[MAX_ARGC]; - struct ComponentData *wdata; - struct ListData *sdata; - Pixel bg; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - - adata = copyGraphicsConfigToPeer(env, this); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - wdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - sdata = (struct ListData *) calloc(1, sizeof(struct ListData)); - - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,sdata); - if (sdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - argc = 0; - XtSetArg(args[argc], XmNrecomputeSize, False); - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNlistSizePolicy, XmCONSTANT); - argc++; - XtSetArg(args[argc], XmNx, 0); - argc++; - XtSetArg(args[argc], XmNy, 0); - argc++; - XtSetArg(args[argc], XmNmarginTop, 0); - argc++; - XtSetArg(args[argc], XmNmarginBottom, 0); - argc++; - XtSetArg(args[argc], XmNmarginLeft, 0); - argc++; - XtSetArg(args[argc], XmNmarginRight, 0); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNlistMarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNlistMarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNscrolledWindowMarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNscrolledWindowMarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNuserData, (XtPointer) globalRef); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - sdata->list = XmCreateScrolledList(wdata->widget, - "slist", - args, - argc); - - sdata->comp.widget = XtParent(sdata->list); - XtSetMappedWhenManaged(sdata->comp.widget, False); - XtAddCallback(sdata->list, - XmNdefaultActionCallback, - Slist_callback, - (XtPointer) globalRef); - XtAddEventHandler(sdata->list, FocusChangeMask, - True, awt_canvas_event_handler, globalRef); - - awt_addWidget(sdata->list, sdata->comp.widget, globalRef, - java_awt_AWTEvent_KEY_EVENT_MASK | - java_awt_AWTEvent_MOUSE_EVENT_MASK | - java_awt_AWTEvent_MOUSE_MOTION_EVENT_MASK); - - XtManageChild(sdata->list); - XtManageChild(sdata->comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: setMultipleSelections - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_setMultipleSelections - (JNIEnv *env, jobject this, jboolean v) -{ - struct ListData *sdata; - jobject globalRef; - int32_t selPos; - Boolean selected; - - AWT_LOCK(); - - sdata = (struct ListData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - globalRef = (jobject) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.jniGlobalRef); - if (v == JNI_FALSE) { - XtVaSetValues(sdata->list, - XmNselectionPolicy, XmBROWSE_SELECT, - NULL); - XtRemoveCallback(sdata->list, - XmNmultipleSelectionCallback, - Slist_callback, - (XtPointer) globalRef); - XtAddCallback(sdata->list, - XmNbrowseSelectionCallback, - Slist_callback, - (XtPointer) globalRef); - - // If we change the selection mode from multiple to single - // we need to decide what the item should be selected: - // If a selected item has the location cursor, only that - // item will remain selected. If no selected item has the - // location cursor, all items will be deselected. - selPos = XmListGetKbdItemPos(sdata->list); - selected = XmListPosSelected(sdata->list, selPos); - XmListDeselectAllItems(sdata->list); - if (selected) { - Java_sun_awt_motif_MListPeer_select(env, this, selPos-1); - } - - } else { - XtVaSetValues(sdata->list, - XmNselectionPolicy, XmMULTIPLE_SELECT, - NULL); - XtRemoveCallback(sdata->list, - XmNbrowseSelectionCallback, - Slist_callback, - (XtPointer) globalRef); - XtAddCallback(sdata->list, - XmNmultipleSelectionCallback, - Slist_callback, - (XtPointer) globalRef); - } - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: setBackground - * Signature: (Ljava/awt/Color;)V - */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_setBackground - (JNIEnv *env, jobject this, jobject c) -{ - struct ListData *ldata; - Pixel color; - - if (JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - ldata = (struct ListData *) - JNU_GetLongFieldAsPtr(env,this, mComponentPeerIDs.pData); - if (ldata == NULL || ldata->list == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - color = awtJNI_GetColor(env, c); - XtVaSetValues(ldata->list, - XmNbackground, color, - NULL); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: isSelected - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_sun_awt_motif_MListPeer_isSelected - (JNIEnv *env, jobject this, jint pos) -{ - struct ListData *sdata; - - AWT_LOCK(); - - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return JNI_FALSE; - } - pos++; - if (XmListPosSelected(sdata->list, pos) == True) { - AWT_UNLOCK(); - return JNI_TRUE; - } else { - AWT_UNLOCK(); - return JNI_FALSE; - } -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: addItem - * Signature: (Ljava/lang/String;I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_addItem - (JNIEnv *env, jobject this, jstring item, jint index) -{ - XmString im; - struct ListData *sdata; - jobject font; - - /* - * Note: - * There used to be code in this function to fix: - * 4067355 size of listbox depends on when pack() is called (solaris) - * The fix (for jdk1.1.7) involved unmapping the List widget before the add - * is done and resizing/remapping it after the add. This causes significant - * performance degradation if addItem() is called a lot. A bug was filed - * on this performance problem: 4117288 - * The fix was backed out after testing that: - * - the problem reported in 4067355 was no longer reproducible - * - the performance problem is gone - */ - - AWT_LOCK(); - if (JNU_IsNull(env, item)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - font = awtJNI_GetFont(env, this); - - if (awtJNI_IsMultiFont(env, font)) { - im = awtJNI_MakeMultiFontString(env, item, font); - } else { - char *temp; - - temp = (char *) JNU_GetStringPlatformChars(env, item, NULL); - im = XmStringCreateLocalized(temp); - JNU_ReleaseStringPlatformChars(env, item, (const char *)temp); - } - - /* motif uses 1-based indeces for the list operations with 0 */ - /* referring to the last item on the list. Thus if index is -1 */ - /* then we'll get the right effect of adding to the end of the */ - /* list. */ - index++; - - XmListAddItemUnselected(sdata->list, im, index); - XmStringFree(im); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: delItems - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_delItems - (JNIEnv *env, jobject this, jint start, jint end) -{ - struct ListData *sdata; - Boolean was_mapped; - jobject target; - Position width, height; - int32_t itemCount; - - AWT_LOCK(); - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* [jk] catch bogus indexes (Sun bug) */ - XtVaGetValues(sdata->list, XmNitemCount, &itemCount, NULL); - if (itemCount == 0) { - AWT_UNLOCK(); - return; - } - if (start > itemCount) { - start = itemCount; - } - if (end > itemCount) { - end = itemCount; - } - start++; - end++; - - XtVaGetValues(sdata->comp.widget, XmNmappedWhenManaged, &was_mapped, NULL); - - /* If it was visible, then make it invisible while we update */ - if (was_mapped) { - XtSetMappedWhenManaged(sdata->comp.widget, False); - } - - if (start == end) { - XmListDeletePos(sdata->list, start); - } else { - XmListDeleteItemsPos(sdata->list, end - start + 1, start); - } - - width = (*env)->GetIntField(env, target, componentIDs.width); - height = (*env)->GetIntField(env, target, componentIDs.height); - XtVaSetValues(sdata->comp.widget, - XmNwidth, (width > 1) ? width-1 : 1, - XmNheight, (height > 1) ? height-1 : 1, - NULL); - XtVaSetValues(sdata->comp.widget, - XmNwidth, (width > 0) ? width : 1, - XmNheight, (height > 0) ? height : 1, - NULL); - /* If it was visible, then make it visible again once updated */ - if (was_mapped) { - XtSetMappedWhenManaged(sdata->comp.widget, True); - } - - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: pSelect - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_select - (JNIEnv *env, jobject this, jint pos) -{ - struct ListData *sdata; - - AWT_LOCK(); - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - pos++; - XmListSelectPos(sdata->list, pos, False); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: pDeselect - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_deselect - (JNIEnv *env, jobject this, jint pos) -{ - struct ListData *sdata; - - AWT_LOCK(); - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - pos++; - XmListDeselectPos(sdata->list, pos); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: makeVisible - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_makeVisible - (JNIEnv *env, jobject this, jint pos) -{ - int32_t top, visible; - struct ListData *sdata; - - AWT_LOCK(); - sdata = (struct ListData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaGetValues(sdata->list, - XmNtopItemPosition, &top, - XmNvisibleItemCount, &visible, - NULL); - pos++; - if (pos < top) { - XmListSetPos(sdata->list, pos); - } else { - XmListSetBottomPos(sdata->list, pos); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MListPeer - * Method: nativeHandleMouseWheel - * Signature: (III)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MListPeer_nativeHandleMouseWheel - (JNIEnv *env, jobject this, jint scrollType, jint scrollAmt, jint wheelAmt) -{ - struct ListData *ldata; - Widget list = NULL; - Widget scroll = NULL; - - AWT_LOCK(); - ldata = (struct ListData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (ldata == NULL || ldata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - // get the List widget - list = ldata->list; - if (list == NULL) { - AWT_UNLOCK(); - return; - } - - // get the ScrolledWindow - scroll = XtParent(list); - if (scroll == NULL) { - AWT_UNLOCK(); - return; - } - - awt_util_do_wheel_scroll(scroll, scrollType, scrollAmt, wheelAmt); - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_MToolkit.c --- a/jdk/src/solaris/native/sun/awt/awt_MToolkit.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/awt_MToolkit.c Wed Jul 05 16:41:30 2017 +0200 @@ -48,7 +48,7 @@ /* JNI field and method ids */ #include "awt_Component.h" -#include "awt_Cursor.h" +//#include "awt_Cursor.h" #include "awt_MenuComponent.h" #include "awt_TopLevel.h" #include "canvas.h" diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Menu.c --- a/jdk/src/solaris/native/sun/awt/awt_Menu.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,407 +0,0 @@ -/* - * Copyright 1995-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "color.h" -#include "java_awt_Menu.h" -#include "sun_awt_motif_MMenuPeer.h" -#include "java_awt_MenuBar.h" -#include "sun_awt_motif_MMenuBarPeer.h" - -#include "awt_MenuBar.h" -#include "awt_MenuComponent.h" -#include "awt_MenuItem.h" -#include "awt_Menu.h" - -#include "multi_font.h" -#include -#include -#include - -extern struct MenuComponentIDs menuComponentIDs; -extern struct MenuItemIDs menuItemIDs; -extern struct MMenuItemPeerIDs mMenuItemPeerIDs; -extern struct MMenuBarPeerIDs mMenuBarPeerIDs; - -struct MenuIDs menuIDs; - -/* - * Class: java_awt_Menu - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - Menu.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs - (JNIEnv *env, jclass cls) -{ - menuIDs.tearOff = (*env)->GetFieldID(env, cls, "tearOff", "Z"); - menuIDs.isHelpMenu = (*env)->GetFieldID(env, cls, "isHelpMenu", "Z"); -} - -/* - * Fix for Bug Traq 4251941 - segfault after double tear-off and close - * Removes the lost callback from menu item on tear-off control re-creation. - * Only for internal use, to be used from awtTearOffActivatedCallback - */ -static void awtTearOffShellDestroy(Widget widget, XtPointer closure, XtPointer data) { - if (widget != NULL ) { - XtSetKeyboardFocus(widget, NULL); - } -} - -/* - * Fix for Bug Traq 4251941 - segfault after double tear-off and close - * This callback is added to menu after the creation. - * It adds the destroy callback awtTearOffShellDestroy to remove the lost focus callback on destroy - */ -static void awtTearOffActivatedCallback(Widget widget, XtPointer closure, XtPointer data) { - Widget shell; - shell = XtParent(widget); - if (shell != NULL && XtClass(shell) == transientShellWidgetClass) { - XtAddCallback(shell, XtNdestroyCallback, awtTearOffShellDestroy, widget); - } -} - -extern Boolean skipNextNotifyWhileGrabbed; - -static void -Menu_popDownCB(Widget w, XtPointer client_data, XtPointer calldata) -{ - skipNextNotifyWhileGrabbed = True; -} - - - -/* - * this is a MMenuPeer instance - */ -static void -awtJNI_CreateMenu(JNIEnv * env, jobject this, Widget menuParent) -{ - int32_t argc; -#define MAX_ARGC 10 - Arg args[MAX_ARGC]; - char *ctitle = NULL; - struct MenuData *mdata; - struct FontData *fdata; - Pixel bg; - Pixel fg; - XmFontList fontlist = NULL; - Widget tearOff; - XmString mfstr = NULL; - XmString str = NULL; - jobject target; - jobject targetFont; - jobject label; - jobject font; - jboolean IsMultiFont; - jboolean isTearOff; - - /* perhaps this is unncessary, if awtJNI_CreateMenu is only called - * from a native method. - */ - if ((*env)->PushLocalFrame(env, (jint)16) < (jint)0) { - return; - } - - fdata = NULL; - - target = (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - (*env)->PopLocalFrame(env, NULL); - return; - } - font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", - "()Ljava/awt/Font;").l; - - mdata = ZALLOC(MenuData); - JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata); - if (mdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - (*env)->PopLocalFrame(env, NULL); - return; - } - targetFont = (*env)->GetObjectField(env, target, menuComponentIDs.font); - if (!JNU_IsNull(env, targetFont) && - (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { - IsMultiFont = awtJNI_IsMultiFont(env, targetFont); - } else { - IsMultiFont = awtJNI_IsMultiFont(env, font); - } - - label = (*env)->GetObjectField(env, target, menuItemIDs.label); - if (JNU_IsNull(env, label)) { - mfstr = XmStringCreateLocalized(""); - ctitle = ""; - } else { - if (IsMultiFont) { - mfstr = awtJNI_MakeMultiFontString(env, label, font); - } else { - ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL); - } - } - - XtVaGetValues(menuParent, XmNbackground, &bg, NULL); - XtVaGetValues(menuParent, XmNforeground, &fg, NULL); - - argc = 0; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - - XtSetArg(args[argc], XmNlabelFontList, getMotifFontList()); - argc++; - XtSetArg(args[argc], XmNbuttonFontList, getMotifFontList()); - argc++; - - isTearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff); - - if (isTearOff) { - XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED); - argc++; - } - - if (IsMultiFont) { - DASSERT(!(argc > MAX_ARGC)); - mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent, - "", - args, - argc); - } else { - DASSERT(!(argc > MAX_ARGC)); - mdata->itemData.comp.widget = XmCreatePulldownMenu(menuParent, - ctitle, - args, - argc); - } - awt_addMenuWidget(mdata->itemData.comp.widget); - - if (isTearOff) { - tearOff = XmGetTearOffControl(mdata->itemData.comp.widget); - XtVaSetValues(tearOff, - XmNbackground, bg, - XmNforeground, fg, - XmNhighlightColor, fg, - NULL); - XtAddCallback(mdata->itemData.comp.widget, XmNtearOffMenuActivateCallback, - awtTearOffActivatedCallback, NULL); - } - argc = 0; - XtSetArg(args[argc], XmNsubMenuId, mdata->itemData.comp.widget); - argc++; - - if (IsMultiFont) { - XtSetArg(args[argc], XmNlabelString, mfstr); - } else { - str = XmStringCreate(ctitle, XmSTRING_DEFAULT_CHARSET); - XtSetArg(args[argc], XmNlabelString, str); - } - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - - if (!JNU_IsNull(env, targetFont) && (fdata != NULL)) { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, targetFont); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } else { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, font); - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } - } - - if (IsMultiFont) { - DASSERT(!(argc > MAX_ARGC)); - mdata->comp.widget = XmCreateCascadeButton(menuParent, "", args, argc); - } else { - DASSERT(!(argc > MAX_ARGC)); - mdata->comp.widget = XmCreateCascadeButton(menuParent, ctitle, args, argc); - } - - if ((*env)->GetBooleanField(env, target, menuIDs.isHelpMenu)) { - XtVaSetValues(menuParent, - XmNmenuHelpWidget, mdata->comp.widget, - NULL); - } - - /** - * Add callback to MenuShell of the menu so we know when - * menu pops down. mdata->itemData.comp.widget is RowColumn, - * its parent - MenuShell. - */ - XtAddCallback(XtParent(mdata->itemData.comp.widget), XtNpopdownCallback, - Menu_popDownCB, - (XtPointer) - JNU_GetLongFieldAsPtr(env, this, - mMenuItemPeerIDs.jniGlobalRef)); - - /* - * Free resources - */ - if (!JNU_IsNull(env, targetFont)) { - XmFontListFree(fontlist); - } - - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - - if (str) { - XmStringFree(str); - str = NULL; - } - - XtManageChild(mdata->comp.widget); - XtSetSensitive(mdata->comp.widget, - (*env)->GetBooleanField(env, target, menuItemIDs.enabled) ? - True : False); - - if (ctitle != NULL && ctitle != "") { - JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle); - } - (*env)->PopLocalFrame(env, NULL); -} - - -/* - * Class: sun_awt_motif_MMenuPeer - * Method: createMenu - * Signature: (Lsun/awt/motif/MMenuBarPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createMenu - (JNIEnv *env, jobject this, jobject parent) -{ - struct ComponentData *mbdata; - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - mbdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mMenuBarPeerIDs.pData); - if (mbdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awtJNI_CreateMenu(env, this, mbdata->widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuPeer - * Method: createSubMenu - * Signature: (Lsun/awt/motif/MMenuPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_createSubMenu -(JNIEnv *env, jobject this, jobject parent) -{ - struct MenuData *mpdata; - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - mpdata = (struct MenuData *) - JNU_GetLongFieldAsPtr(env, parent, mMenuItemPeerIDs.pData); - if (mpdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awtJNI_CreateMenu(env, this, mpdata->itemData.comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuPeer_pDispose - (JNIEnv *env, jobject this) -{ - struct MenuData *mdata; - Widget parent; - Boolean isParentManaged = False; - - AWT_LOCK(); - - mdata = (struct MenuData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - if (mdata == NULL) { - AWT_UNLOCK(); - return; - } - awt_delMenuWidget(mdata->itemData.comp.widget); - XtUnmanageChild(mdata->comp.widget); - awt_util_consumeAllXEvents(mdata->itemData.comp.widget); - awt_util_consumeAllXEvents(mdata->comp.widget); - - parent = XtParent(mdata->itemData.comp.widget); - if (parent != NULL && XtIsManaged(parent)) { - isParentManaged = True; - XtUnmanageChild(parent); - } - - XtDestroyWidget(mdata->itemData.comp.widget); - - if (isParentManaged) { - XtManageChild(parent); - } - - XtDestroyWidget(mdata->comp.widget); - free((void *) mdata); - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Menu.h --- a/jdk/src/solaris/native/sun/awt/awt_Menu.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright 1998 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. - */ - -#include - -/* fieldIDs for Menu fields that may be accessed from C */ -struct MenuIDs { - jfieldID tearOff; - jfieldID isHelpMenu; -}; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_MenuBar.c --- a/jdk/src/solaris/native/sun/awt/awt_MenuBar.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * Copyright 1995-2004 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. - */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_MenuBar.h" -#include "sun_awt_motif_MMenuBarPeer.h" -#include "java_awt_Menu.h" -#include "java_awt_Frame.h" -#include "sun_awt_motif_MFramePeer.h" - -#include "awt_GraphicsEnv.h" -#include "awt_MenuBar.h" -#include "awt_Component.h" - -#include -#include - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; -struct MMenuBarPeerIDs mMenuBarPeerIDs; - -/* - * Class: sun_awt_motif_MMenuBarPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for MMenuBarPeer.java - to initialize the fieldIDs fields that may be accessed from C */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MMenuBarPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mMenuBarPeerIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); - mMenuBarPeerIDs.graphicsConfig = - (*env)->GetFieldID(env, cls, "graphicsConfig", - "Lsun/awt/X11GraphicsConfig;"); -} - -static AwtGraphicsConfigDataPtr -copyGraphicsConfigToMenuBarPeer( -JNIEnv *env, jobject frame, jobject thisMenuBar) { - - jobject gc_object; - AwtGraphicsConfigDataPtr adata; - - /* GraphicsConfiguration object of Component */ - gc_object = (*env)->GetObjectField(env, frame, - mComponentPeerIDs.graphicsConfig); - - if (gc_object != NULL) { - /* Set graphicsConfig field of MComponentPeer */ - (*env)->SetObjectField (env, thisMenuBar, - mMenuBarPeerIDs.graphicsConfig, - gc_object); - adata = (AwtGraphicsConfigDataPtr) - JNU_GetLongFieldAsPtr(env, gc_object, - x11GraphicsConfigIDs.aData); - } else { - /* Component was not constructed with a GraphicsConfiguration - object */ - adata = getDefaultConfig(DefaultScreen(awt_display)); - } - - return adata; -} - -AwtGraphicsConfigDataPtr -getGraphicsConfigFromMenuBarPeer(JNIEnv *env, jobject menubarPeer) { - - jobject gc_object; - AwtGraphicsConfigDataPtr adata; - - /* GraphicsConfiguration object of Component */ - gc_object = (*env)->GetObjectField(env, menubarPeer, - mMenuBarPeerIDs.graphicsConfig); - - if (gc_object != NULL) { - adata = (AwtGraphicsConfigDataPtr) - JNU_GetLongFieldAsPtr(env, gc_object, - x11GraphicsConfigIDs.aData); - } else { - adata = getDefaultConfig(DefaultScreen(awt_display)); - } - - return adata; -} - -/* - * Class: sun_awt_motif_MMenuBarPeer - * Method: create - * Signature: (Lsun/awt/motif/MFramePeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuBarPeer_create - (JNIEnv * env, jobject this, jobject frame) -{ -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - int32_t argc; - struct ComponentData *mdata; - struct FrameData *wdata; - Pixel bg; - Pixel fg; - AwtGraphicsConfigDataPtr adata; - - if (JNU_IsNull(env, frame)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, frame, mComponentPeerIDs.pData); - mdata = ZALLOC(ComponentData); - - if (wdata == NULL || mdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env, this, mMenuBarPeerIDs.pData, mdata); - - adata = copyGraphicsConfigToMenuBarPeer(env, frame, this); - - XtVaGetValues(wdata->winData.comp.widget, - XmNbackground, &bg, - XmNforeground, &fg, - NULL); - - argc = 0; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - mdata->widget = XmCreateMenuBar(wdata->mainWindow, "menu_bar", args, argc); - awt_addMenuWidget(mdata->widget); - XtSetMappedWhenManaged(mdata->widget, False); - XtManageChild(mdata->widget); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuBarPeer - * Method: dispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuBarPeer_pDispose - (JNIEnv * env, jobject this) -{ - struct ComponentData *mdata; - - AWT_LOCK(); - - /*hania LOOK HERE does this make sense? look at original code */ - mdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mMenuBarPeerIDs.pData); - if (mdata == NULL) { - AWT_UNLOCK(); - return; - } - awt_delMenuWidget(mdata->widget); - XtUnmanageChild(mdata->widget); - awt_util_consumeAllXEvents(mdata->widget); - XtDestroyWidget(mdata->widget); - free((void *) mdata); - (*env)->SetLongField(env, this, mMenuBarPeerIDs.pData, (jlong)0); - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_MenuBar.h --- a/jdk/src/solaris/native/sun/awt/awt_MenuBar.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright 1998-1999 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. - */ - -/* fieldIDs for MMenuBarPeer fields that may be accessed from C */ -struct MMenuBarPeerIDs { - jfieldID pData; - jfieldID graphicsConfig; -}; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_MenuComponent.c --- a/jdk/src/solaris/native/sun/awt/awt_MenuComponent.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright 1998-2006 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "java_awt_MenuComponent.h" -#include "jni_util.h" - -#include "awt_MenuComponent.h" - -struct MenuComponentIDs menuComponentIDs; - - -JNIEXPORT void JNICALL -Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jclass cls) -{ - menuComponentIDs.font = - (*env)->GetFieldID(env, cls, "font", "Ljava/awt/Font;"); - menuComponentIDs.appContext = - (*env)->GetFieldID(env, cls, "appContext", "Lsun/awt/AppContext;"); - menuComponentIDs.getParent = - (*env)->GetMethodID( - env, cls, "getParent_NoClientCode", "()Ljava/awt/MenuContainer;"); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_MenuItem.c --- a/jdk/src/solaris/native/sun/awt/awt_MenuItem.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,654 +0,0 @@ -/* - * Copyright 1995-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include -#include "java_awt_MenuItem.h" -#include "sun_awt_motif_MMenuItemPeer.h" -#include "sun_awt_motif_MCheckboxMenuItemPeer.h" -#include "java_awt_Menu.h" -#include "sun_awt_motif_MMenuPeer.h" - -#include "awt_MenuComponent.h" -#include "awt_MenuItem.h" - -#include "multi_font.h" -#include -#include -#include - -extern struct MenuComponentIDs menuComponentIDs; - -/* fieldIDs for MenuItem fields that may be accessed from C */ -struct MenuItemIDs menuItemIDs; - -/* - * Class: java_awt_MenuItem - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MenuItem.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_java_awt_MenuItem_initIDs - (JNIEnv *env, jclass cls) -{ - menuItemIDs.label = - (*env)->GetFieldID(env, cls, "label", "Ljava/lang/String;"); - menuItemIDs.enabled = - (*env)->GetFieldID(env, cls, "enabled", "Z"); - menuItemIDs.shortcut = - (*env)->GetFieldID(env, cls, "shortcut", "Ljava/awt/MenuShortcut;"); -} - -/* fieldIDs for MMenuItemPeer fields that may be accessed from C */ -struct MMenuItemPeerIDs mMenuItemPeerIDs; - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MMenuItemPeer.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mMenuItemPeerIDs.target = - (*env)->GetFieldID(env, cls, "target", "Ljava/awt/MenuItem;"); - mMenuItemPeerIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); - mMenuItemPeerIDs.isCheckbox = - (*env)->GetFieldID(env, cls, "isCheckbox", "Z"); - mMenuItemPeerIDs.jniGlobalRef = - (*env)->GetFieldID(env, cls, "jniGlobalRef", "J"); -} - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: getParent_NoClientCode - * Signature: (Ljava/awt/MenuComponent;)Ljava/awt/MenuContainer; - * - * Gets the MenuContainer parent of this object, without executing client - * code (e.g., no code in subclasses will be executed). - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MMenuItemPeer_getParent_1NoClientCode - (JNIEnv *env, jclass thisClass, jobject menuComponent) -{ - jobject parent = NULL; - - /* getParent is actually getParent_NoClientCode() */ - parent = (*env)->CallObjectMethod( - env,menuComponent,menuComponentIDs.getParent); - DASSERT(!((*env)->ExceptionOccurred(env))); - return parent; -} - -/* - * client_data is MMenuItemPeer instance pointer - */ -static void -MenuItem_selected(Widget w, XtPointer client_data, XmAnyCallbackStruct * s) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) client_data; - ConvertEventTimeAndModifiers converted; - - awt_util_convertEventTimeAndModifiers(s->event, &converted); - - if ((*env)->GetBooleanField(env, this, mMenuItemPeerIDs.isCheckbox)) { - jboolean state; - struct MenuItemData *mdata; - - mdata = (struct MenuItemData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata != NULL) { - XtVaGetValues(mdata->comp.widget, XmNset, &state, NULL); - - JNU_CallMethodByName(env, NULL, this - ,"action" - ,"(JIZ)V" - ,converted.when, converted.modifiers, - state); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - } else { - JNU_CallMethodByName(env, NULL, this, "action", "(JI)V", - converted.when, converted.modifiers); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } -} - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: createMenuItem - * Signature: (Lsun/awt/motif/MMenuPeer;)V - * - * ASSUMES: This function is never called by a privileged thread - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_createMenuItem( -JNIEnv *env, jobject this, jobject parent) -{ - int32_t argc; -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - char *clabel; - struct MenuData *menuData; - struct MenuItemData *mdata; - struct FontData *fdata; - Pixel bg; - Pixel fg; - XmFontList fontlist = NULL; - jobject target; - jobject targetFont; - XmString mfstr = NULL; - XmString shortcut_str = NULL; - XmString str = NULL; - jobject font; - jobject shortcut; - jboolean IsMultiFont; - jboolean isCheckbox; - jstring label; - jobject globalRef = (*env)->NewGlobalRef(env, this); - const jchar *unicodeLabel = NULL; - jsize unicodeLabelLen = 0; - jboolean isCopy = JNI_FALSE; - - // We call client code on this thread, so it must *NOT* be privileged - DASSERT(!awt_currentThreadIsPrivileged(env)); - - JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.jniGlobalRef, - globalRef); - - fdata = NULL; - - fflush(stderr); - target = - (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", - "()Ljava/awt/Font;").l; - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - menuData = (struct MenuData *) - JNU_GetLongFieldAsPtr(env, parent, mMenuItemPeerIDs.pData); - - targetFont = - (*env)->GetObjectField(env, target, menuComponentIDs.font); - if (!JNU_IsNull(env, targetFont) && - (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { - IsMultiFont = awtJNI_IsMultiFont(env, targetFont); - } else { - IsMultiFont = awtJNI_IsMultiFont(env, font); - } - - label = (*env)->GetObjectField(env, target, menuItemIDs.label); - if (JNU_IsNull(env, label) || ((*env)->GetStringLength (env, label) == 0)) { - mfstr = XmStringCreateLocalized(""); - clabel = ""; - } else { - if (IsMultiFont) { - mfstr = awtJNI_MakeMultiFontString(env, label, font); - } else { - mfstr = XmStringCreateLocalized(""); - } - clabel = (char *) JNU_GetStringPlatformChars(env, label, NULL); - } - - mdata = ZALLOC(MenuItemData); - JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata); - - argc = 0; - XtSetArg(args[argc], XmNbackground, &bg); - argc++; - XtSetArg(args[argc], XmNforeground, &fg); - argc++; - XtGetValues(menuData->itemData.comp.widget, args, argc); - - argc = 0; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - - /* check if the label is "-" but don't use strcmp(clabel, "-") because - * the high-order bytes in the unicode characters are not present in - * the C string (bugid 4099695) - */ - if (!JNU_IsNull(env, label)) { - unicodeLabel = (*env)->GetStringChars(env, label, &isCopy); - unicodeLabelLen = (*env)->GetStringLength(env, label); - } - if ((unicodeLabel != NULL) && (unicodeLabel[0] == '-') && - (unicodeLabelLen == 1)) { - DASSERT(!(argc > MAX_ARGC)); - mdata->comp.widget = XmCreateSeparator(menuData->itemData.comp.widget, - "", args, argc); - } else { - if (IsMultiFont) { - XtSetArg(args[argc], XmNlabelString, mfstr); - } else { - str = XmStringCreate(clabel, XmSTRING_DEFAULT_CHARSET); - XtSetArg(args[argc], XmNlabelString, str); - } - argc++; - - shortcut = - (*env)->GetObjectField(env, target, menuItemIDs.shortcut); - if (!JNU_IsNull(env, shortcut)) { - jstring shortcutText; - char *text = ""; - - shortcutText = JNU_CallMethodByName(env, NULL, shortcut, - "toString", - "()Ljava/lang/String;").l; - - if (!JNU_IsNull(env, shortcutText)) { - text = (char *) JNU_GetStringPlatformChars(env, shortcutText, NULL); - } - shortcut_str = XmStringCreate(text, XmSTRING_DEFAULT_CHARSET); - XtSetArg(args[argc], XmNacceleratorText, shortcut_str); - - argc++; - - if (!JNU_IsNull(env, shortcutText)) { - JNU_ReleaseStringPlatformChars(env, shortcutText, (const char *) text); - } - } - if (!JNU_IsNull(env, targetFont) && (fdata != NULL)) { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, targetFont); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } else { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, font); - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } - } - - isCheckbox = - (*env)->GetBooleanField(env, this, mMenuItemPeerIDs.isCheckbox); - if (isCheckbox) { - /* Fix for 4090493 */ - if (IsMultiFont) { - /* FontData that correspond to XmNfontList we just set */ - struct FontData *fdataForIndSize; - Dimension indSize; - if (!JNU_IsNull(env, targetFont) && (fdata != NULL)) { - fdataForIndSize = fdata; - } - else { - fdataForIndSize = awtJNI_GetFontData(env, font, NULL); - } - indSize = awt_adjustIndicatorSizeForMenu(awt_computeIndicatorSize(fdataForIndSize)); - if (indSize != MOTIF_XmINVALID_DIMENSION) { - XtSetArg(args[argc], XmNindicatorSize, indSize); argc++; - } - } - /* End of fix for 4090493 */ - XtSetArg(args[argc], XmNset, False); - argc++; - XtSetArg(args[argc], XmNvisibleWhenOff, True); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - mdata->comp.widget = XmCreateToggleButton(menuData->itemData.comp.widget, - clabel, - args, - argc); - } else { - DASSERT(!(argc > MAX_ARGC)); - mdata->comp.widget = XmCreatePushButton(menuData->itemData.comp.widget, - clabel, - args, - argc); - } - XtAddCallback(mdata->comp.widget, - ((isCheckbox) ? XmNvalueChangedCallback : XmNactivateCallback), - (XtCallbackProc) MenuItem_selected, - (XtPointer) globalRef); - - XtSetSensitive(mdata->comp.widget, - (*env)->GetBooleanField(env, target, menuItemIDs.enabled) ? - True : False); - - - if (!JNU_IsNull(env, targetFont)) { - XmFontListFree(fontlist); - } - } - - if (clabel && (clabel != "")) { - JNU_ReleaseStringPlatformChars(env, label, clabel); - } - - /* - * Free up resources after we have created the widget - */ - if (mfstr != NULL) { - XmStringFree(mfstr); - mfstr = NULL; - } - if (str) { - XmStringFree(str); - str = NULL; - } - if (shortcut_str) { - XmStringFree(shortcut_str); - shortcut_str = NULL; - } - if (isCopy == JNI_TRUE) { - (*env)->ReleaseStringChars(env, label, unicodeLabel); - } - - XtManageChild(mdata->comp.widget); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: pSetLabel - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_pSetLabel -(JNIEnv *env, jobject this, jstring label) -{ - struct ComponentData *wdata; - char *clabel; - XmString xim; - - AWT_LOCK(); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, label) || ((*env)->GetStringLength (env, label) == 0)) { - xim = XmStringCreateLocalized(""); - } else { - jobject font; - jobject target; - - target = (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", - "()Ljava/awt/Font;").l; - - if (awtJNI_IsMultiFont(env, font)) { - xim = awtJNI_MakeMultiFontString(env, label, font); - } else { - clabel = (char *) JNU_GetStringPlatformChars(env, label, NULL); - xim = XmStringCreate(clabel, "labelFont"); - JNU_ReleaseStringPlatformChars(env, label, clabel); - } - } - XtUnmanageChild(wdata->widget); - XtVaSetValues(wdata->widget, XmNlabelString, xim, NULL); - XtManageChild(wdata->widget); - XmStringFree(xim); - AWT_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: pSetShortCut - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_pSetShortcut -(JNIEnv *env, jobject this, jstring shortcut) -{ - struct ComponentData *wdata; - char *cshortcut; - XmString xim; - - - AWT_LOCK(); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, shortcut)) { - xim = XmStringCreateLocalized(""); - } else { - jobject font; - jobject target; - - target = (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", - "()Ljava/awt/Font;").l; - - if (awtJNI_IsMultiFont(env, font)) { - xim = awtJNI_MakeMultiFontString(env, shortcut, font); - } else { - cshortcut = (char *) JNU_GetStringPlatformChars(env, shortcut, NULL); - xim = XmStringCreate(cshortcut, "labelFont"); - JNU_ReleaseStringPlatformChars(env, shortcut, cshortcut); - } - } - - XtUnmanageChild(wdata->widget); - XtVaSetValues(wdata->widget, XmNacceleratorText, xim, NULL); - XtManageChild(wdata->widget); - XmStringFree(xim); - AWT_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: pEnable - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_pEnable -(JNIEnv *env, jobject this) -{ - struct MenuItemData *mdata; - - AWT_LOCK(); - - mdata = (struct MenuItemData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtSetSensitive(mdata->comp.widget, True); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: pDisable - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_pDisable -(JNIEnv *env, jobject this) -{ - struct MenuItemData *mdata; - - AWT_LOCK(); - - mdata = (struct MenuItemData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtSetSensitive(mdata->comp.widget, False); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MMenuItemPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MMenuItemPeer_pDispose -(JNIEnv *env, jobject this) -{ - struct MenuItemData *mdata; - Widget parent; - Boolean isParentManaged = False; - - AWT_LOCK(); - - mdata = (struct MenuItemData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata != NULL) { - /* Fix for 4280561:Workspace freezes, does not respond to mouse clicks - ** - ** this really helps a lot of Fujitsu problems, take down a popup - ** menu when removing items, on windows you could never get here, since - ** the show() of a popup menu puts it in a menu loop where further - ** events are processed in that loop, its like a modal dialog show, - ** in that it dosn't return till it comes down. - ** in X - future xevents will be dispatched immeadiatly, but some - ** may be still waiting on the java queue - which can cause them to be - ** dispatched out of order (sometimes hanging system !) - */ - /* note: should realy only take down if XtParent(mdata->comp.widget) - ** is the activePopup (in awt_PopupMenu.c) but ... - */ - { - removePopupMenus(); - } - XtUnmanageChild(mdata->comp.widget); - awt_util_consumeAllXEvents(mdata->comp.widget); - - parent = XtParent(mdata->comp.widget); - if (parent != NULL && XtIsManaged(parent)) { - isParentManaged = True; - XtUnmanageChild(parent); - } - - XtDestroyWidget(mdata->comp.widget); - - if (isParentManaged) { - XtManageChild(parent); - } - - free((void *) mdata); - (*env)->SetLongField(env, this, mMenuItemPeerIDs.pData, (jlong)0); - awtJNI_DeleteGlobalMenuRef(env, this); - } - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxMenuItemPeer - * Method: pSetState - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCheckboxMenuItemPeer_pSetState - (JNIEnv *env, jobject this, jboolean state) -{ - struct MenuItemData *mdata; - - AWT_LOCK(); - - mdata = (struct MenuItemData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata == NULL) { - JNU_ThrowNullPointerException(env, "menuitem data is null"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(mdata->comp.widget, XmNset, (Boolean)state, NULL); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCheckboxMenuItemPeer - * Method: getState - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL Java_sun_awt_motif_MCheckboxMenuItemPeer_getState - (JNIEnv *env, jobject this) -{ - struct MenuItemData *mdata; - Boolean state; - - AWT_LOCK(); - - mdata = (struct MenuItemData *) - (*env)->GetLongField(env, this, mMenuItemPeerIDs.pData); - - if (mdata == NULL) { - JNU_ThrowNullPointerException(env, "menuitem data is null"); - AWT_UNLOCK(); - return JNI_FALSE; - } - XtVaGetValues(mdata->comp.widget, XmNset, &state, NULL); - AWT_UNLOCK(); - return ((state) ? JNI_TRUE : JNI_FALSE); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_PopupMenu.c --- a/jdk/src/solaris/native/sun/awt/awt_PopupMenu.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,491 +0,0 @@ -/* - * Copyright 1996-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include -#include -#include -#include "color.h" -#include "java_awt_PopupMenu.h" -#include "java_awt_Component.h" -#include "java_awt_Event.h" -#include "sun_awt_motif_MPopupMenuPeer.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "awt_PopupMenu.h" -#include "awt_MenuItem.h" -#include "awt_Component.h" -#include "awt_MenuComponent.h" -#include "awt_Menu.h" -#include "awt_Event.h" - -#include "multi_font.h" -#include -#include - -extern struct MMenuItemPeerIDs mMenuItemPeerIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct MenuComponentIDs menuComponentIDs; -extern struct MenuItemIDs menuItemIDs; -extern struct MenuIDs menuIDs; -extern AwtGraphicsConfigDataPtr -getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject parentPeer); -extern Boolean keyboardGrabbed; -Boolean poppingDown = False; - -struct MPopupMenuPeerIDs mPopupMenuPeerIDs; - -static Widget activePopup; - -void removePopupMenus() { - if (activePopup != NULL && - XtIsManaged(activePopup)) - { - XtUnmanageChild(activePopup); - activePopup = NULL; - } -} - -Boolean awtMenuIsActive() { - return ((activePopup != NULL) || (awt_util_focusIsOnMenu(awt_display))); -} - -struct ClientDataStruct { - struct ComponentData *wdata; - jobject mMenuItemPeerIDs; -}; - -/* - * Class: sun_awt_motif_MPopupMenuPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MPopupMenuPeer.java to initialize the methodIDs for methods that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock = - (*env)->GetMethodID(env, cls, - "destroyNativeWidgetAfterGettingTreeLock", "()V"); -} - -extern Boolean skipNextNotifyWhileGrabbed; - -static void -Popup_popUpCB(Widget w, XtPointer client_data, XtPointer calldata) -{ - skipNextNotifyWhileGrabbed = True; -} -/* - * client_data is MPopupMenuPeer instance - */ -static void -Popup_popdownCB(Widget w, XtPointer client_data, XtPointer calldata) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject target = NULL; - - /* - * Fix for 4394847. Due to the race keyboard remains grabbed after menu - * was disposed. Clear the grab status here instead of processOneEvent. - */ - poppingDown = True; - keyboardGrabbed = False; - skipNextNotifyWhileGrabbed = True; - - XtRemoveCallback(w, XtNpopdownCallback, - Popup_popdownCB, (XtPointer) client_data); - - (*env)->CallVoidMethod(env, (jobject) client_data, - mPopupMenuPeerIDs.destroyNativeWidgetAfterGettingTreeLock); - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -/* - * Class: sun_awt_motif_MPopupMenuPeer - * Method: createMenu - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_createMenu - (JNIEnv *env, jobject this, jobject parent) -{ - struct ComponentData *wdata; - struct MenuData *mdata; - struct FontData *fdata; - char *ctitle = NULL; - int32_t argc; -#define MAX_ARGC 10 - Arg args[MAX_ARGC]; - Pixel bg; - Pixel fg; - XmFontList fontlist = NULL; - XmString mfstr = NULL; - jobject font; - jobject target; - jobject targetFont; - jobject label; - jboolean IsMultiFont; - jboolean tearOff; - jobject globalRef = (*env)->NewGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - - JNU_SetLongFieldFromPtr(env, this, - mMenuItemPeerIDs.jniGlobalRef, globalRef); - - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - target = - (*env)->GetObjectField(env, this, mMenuItemPeerIDs.target); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - - if (wdata == NULL || JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - mdata = ZALLOC(MenuData); - if (mdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.pData, mdata); - - adata = getGraphicsConfigFromComponentPeer(env, parent); - - /* - * Why are these different? - */ - font = JNU_CallMethodByName(env, NULL, target, "getFont_NoClientCode", - "()Ljava/awt/Font;").l; - targetFont = - (*env)->GetObjectField(env, target, menuComponentIDs.font); - if (!JNU_IsNull(env, targetFont) && - (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { - IsMultiFont = awtJNI_IsMultiFont(env, targetFont); - } else { - IsMultiFont = awtJNI_IsMultiFont(env, font); - } - - label = (*env)->GetObjectField(env, target, menuItemIDs.label); - if (JNU_IsNull(env, label)) { - mfstr = XmStringCreateLocalized(""); - ctitle = ""; - } else { - if (IsMultiFont) { - mfstr = awtJNI_MakeMultiFontString(env, label, font); - } else { - ctitle = (char *) JNU_GetStringPlatformChars(env, label, NULL); - } - } - - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - XtVaGetValues(wdata->widget, XmNforeground, &fg, NULL); - - argc = 0; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNforeground, fg); - argc++; - tearOff = (*env)->GetBooleanField(env, target, menuIDs.tearOff); - if (tearOff) { - XtSetArg(args[argc], XmNtearOffModel, XmTEAR_OFF_ENABLED); - argc++; - } - if (!JNU_IsNull(env, targetFont) - && (fdata = awtJNI_GetFontData(env, targetFont, NULL)) != NULL) { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, targetFont); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } else { - if (IsMultiFont) { - fontlist = awtJNI_GetFontList(env, font); - XtSetArg(args[argc], XmNfontList, fontlist); - argc++; - } - } - - XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - - if (IsMultiFont) { - DASSERT(!(argc > MAX_ARGC)); - mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget, - "", - args, - argc); - } else { - DASSERT(!(argc > MAX_ARGC)); - mdata->itemData.comp.widget = XmCreatePopupMenu(wdata->widget, - ctitle, - args, - argc); - } - awt_addMenuWidget(mdata->itemData.comp.widget); - - /* - * Fix for bug 4180147 - - * screen can be frozen when interacting with MB3 using AWT on Motif - */ - XtUngrabButton(wdata->widget, AnyButton, AnyModifier); - XtUngrabPointer(wdata->widget, CurrentTime); - - /* fix for bug #4169155: Popup menus get a leading separator on Motif - system. - Additional check that title string is not empty*/ - if (!JNU_IsNull(env, label) && - (*env)->GetStringUTFLength( env, label) != (jsize)0 ) { - if (IsMultiFont) { - XtVaCreateManagedWidget("", - xmLabelWidgetClass, - mdata->itemData.comp.widget, - XmNfontList, fontlist, - XmNlabelString, mfstr, - XmNbackground, bg, - XmNforeground, fg, - XmNhighlightColor, fg, - NULL); - XmStringFree(mfstr); - } else { - XmString xmstr = XmStringCreateLocalized(ctitle); - - XtVaCreateManagedWidget(ctitle, - xmLabelWidgetClass, - mdata->itemData.comp.widget, - XmNlabelString, xmstr, - XmNbackground, bg, - XmNforeground, fg, - XmNhighlightColor, fg, - NULL); - XmStringFree(xmstr); - JNU_ReleaseStringPlatformChars(env, label, (const char *) ctitle); - } - /* Create separator */ - XtVaCreateManagedWidget("", - xmSeparatorWidgetClass, - mdata->itemData.comp.widget, - XmNbackground, bg, - XmNforeground, fg, - NULL); - } - if (tearOff) { - Widget tearOffWidget = XmGetTearOffControl(mdata->itemData.comp.widget); - - XtVaSetValues(tearOffWidget, - XmNbackground, bg, - XmNforeground, fg, - XmNhighlightColor, fg, - NULL); - } - mdata->comp.widget = mdata->itemData.comp.widget; - - if (!JNU_IsNull(env, targetFont)) { - XmFontListFree(fontlist); - } - XtSetSensitive(mdata->comp.widget, - ((*env)->GetBooleanField(env, target, menuItemIDs.enabled) ? - True : False)); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MPopupMenuPeer - * Method: pShow - * Signature: (Ljava/awt/Event;IILsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pShow - (JNIEnv *env, jobject this, jobject event, jint x, jint y, jobject origin) -{ - struct MenuData *mdata; - struct ComponentData *wdata; - XButtonEvent *bevent; - XButtonEvent *newEvent = NULL; - void *data; - - AWT_LOCK(); - - mdata = (struct MenuData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - if (mdata == NULL || JNU_IsNull(env, event)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, origin, mComponentPeerIDs.pData); - - if ( wdata == NULL || wdata->widget == NULL ) { /* 425598 */ - JNU_ThrowNullPointerException(env, "NullPointerException"); /* 425598 */ - AWT_UNLOCK(); /* 425598 */ - return; /* 425598 */ - } /* 425598 */ - - if (!XtIsRealized(wdata->widget)) { - JNU_ThrowInternalError(env, "widget not visible on screen"); - AWT_UNLOCK(); - return; - } - - /* - * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. - * If another popup is currently visible hide it. - */ - if (activePopup != NULL && - activePopup != mdata->comp.widget && - XtIsObject(activePopup) && - XtIsManaged(activePopup)) { - removePopupMenus(); - } - - /* If the raw x event is not available, then we must use an unfortunate - * round-trip call to XTranslateCoordiates to get the root coordinates. - */ - data = JNU_GetLongFieldAsPtr(env, event, eventIDs.data); - if (data == NULL || ((XEvent *) data)->type != ButtonPress) { - int32_t rx, ry; - Window root, win; - - root = RootWindowOfScreen(XtScreen(wdata->widget)); - XTranslateCoordinates(awt_display, - XtWindow(wdata->widget), - root, - (int32_t) x, (int32_t) y, - &rx, &ry, - &win); - /* - printf("translated coords %d,%d to root %d,%d\n", x, y, rx, ry); - */ - - newEvent = (XButtonEvent *) malloc(sizeof(XButtonEvent)); - newEvent->type = ButtonPress; - newEvent->display = awt_display; - newEvent->window = XtWindow(wdata->widget); - newEvent->time = awt_util_getCurrentServerTime(); - newEvent->x = (int32_t) x; - newEvent->y = (int32_t) y; - newEvent->x_root = rx; - newEvent->y_root = ry; - bevent = newEvent; - - } else { - bevent = (XButtonEvent *) data; - } - - XtAddCallback(XtParent(mdata->comp.widget), XtNpopdownCallback, - Popup_popdownCB, - (XtPointer) - JNU_GetLongFieldAsPtr(env, this, - mMenuItemPeerIDs.jniGlobalRef)); - - XtAddCallback(XtParent(mdata->comp.widget), XtNpopupCallback, - Popup_popUpCB, - (XtPointer) - JNU_GetLongFieldAsPtr(env, this, - mMenuItemPeerIDs.jniGlobalRef)); - - - XmMenuPosition(mdata->comp.widget, bevent); - XtManageChild(mdata->comp.widget); - - /* - * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. - * Store the pointer to the currently showing popup. - */ - activePopup = mdata->comp.widget; - - if (newEvent) { - free((void *) newEvent); - } - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MPopupMenuPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MPopupMenuPeer_pDispose - (JNIEnv *env, jobject this) -{ - struct MenuData *mdata; - - AWT_LOCK(); - - mdata = (struct MenuData *) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.pData); - - if (mdata == NULL) { - AWT_UNLOCK(); - return; - } - /* - * Fix for BugTraq ID 4186663 - Pural PopupMenus appear at the same time. - * Clear the pointer to the currently showing popup. - */ - if (activePopup == mdata->comp.widget) { - activePopup = NULL; - } - awt_delMenuWidget(mdata->itemData.comp.widget); - XtUnmanageChild(mdata->comp.widget); - awt_util_consumeAllXEvents(mdata->comp.widget); - XtDestroyWidget(mdata->comp.widget); - free((void *) mdata); - (*env)->SetLongField(env, this, mMenuItemPeerIDs.pData, (jlong)0); - - awtJNI_DeleteGlobalMenuRef(env, this); - - poppingDown = False; - AWT_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Robot.c --- a/jdk/src/solaris/native/sun/awt/awt_Robot.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/awt_Robot.c Wed Jul 05 16:41:30 2017 +0200 @@ -204,14 +204,8 @@ /*********************************************************************************************/ -#ifdef XAWT -#define FUNC_NAME(name) Java_sun_awt_X11_XRobotPeer_ ## name -#else -#define FUNC_NAME(name) Java_sun_awt_motif_MRobotPeer_ ## name -#endif - JNIEXPORT void JNICALL -FUNC_NAME(setup) (JNIEnv * env, jclass cls) { +Java_sun_awt_X11_XRobotPeer_setup (JNIEnv * env, jclass cls) { int32_t xtestAvailable; DTRACE_PRINTLN("RobotPeer: setup()"); @@ -232,7 +226,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(getRGBPixelsImpl)( JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, jclass cls, jobject xgc, jint x, @@ -295,7 +289,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(keyPressImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_keyPressImpl (JNIEnv *env, jclass cls, jint keycode) { @@ -315,7 +309,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(keyReleaseImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_keyReleaseImpl (JNIEnv *env, jclass cls, jint keycode) { AWT_LOCK(); @@ -333,7 +327,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(mouseMoveImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_mouseMoveImpl (JNIEnv *env, jclass cls, jobject xgc, jint root_x, @@ -355,7 +349,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(mousePressImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_mousePressImpl (JNIEnv *env, jclass cls, jint buttonMask) { AWT_LOCK(); @@ -379,7 +373,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(mouseReleaseImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl (JNIEnv *env, jclass cls, jint buttonMask) { AWT_LOCK(); @@ -403,7 +397,7 @@ } JNIEXPORT void JNICALL -FUNC_NAME(mouseWheelImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_mouseWheelImpl (JNIEnv *env, jclass cls, jint wheelAmt) { /* Mouse wheel is implemented as a button press of button 4 and 5, so it */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_ScrollPane.c --- a/jdk/src/solaris/native/sun/awt/awt_ScrollPane.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,927 +0,0 @@ -/* - * Copyright 1996-2002 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" - -#include "java_awt_Adjustable.h" -#include "java_awt_Insets.h" -#include "java_awt_ScrollPane.h" -#include "java_awt_event_AdjustmentEvent.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MScrollPanePeer.h" -#include "java_awt_AWTEvent.h" - -#include "awt_Component.h" -#include "canvas.h" - -#include -#include -#include - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* fieldIDs for ScrollPane fields that may be accessed from C */ -static struct ScrollPaneIDs { - jfieldID scrollbarDisplayPolicy; -} scrollPaneIDs; - -/* - * Class: java_awt_ScrollPane - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - ScrollPane.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_java_awt_ScrollPane_initIDs - (JNIEnv *env, jclass cls) -{ - scrollPaneIDs.scrollbarDisplayPolicy = - (*env)->GetFieldID(env, cls, "scrollbarDisplayPolicy", "I"); -} - -/* fieldIDs for MScrollPanePeer fields that may be accessed from C */ -static struct MScrollPanePeerIDs { - jmethodID postScrollEventID; -} mScrollPanePeerIDs; - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MScrollPanePeer.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MScrollPanePeer_initIDs - (JNIEnv *env, jclass cls) -{ - mScrollPanePeerIDs.postScrollEventID = - (*env)->GetMethodID(env, cls, "postScrollEvent", "(IIIZ)V"); -} - -static void -dump_scroll_attrs(Widget scrollbar) -{ - unsigned char orient; - int32_t value, size, incr, pIncr, max, min; - - XtVaGetValues(scrollbar, - XmNvalue, &value, - XmNincrement, &incr, - XmNpageIncrement, &pIncr, - XmNsliderSize, &size, - XmNmaximum, &max, - XmNminimum, &min, - XmNorientation, &orient, - NULL); - - jio_fprintf(stdout, "%s: min=%d max=%d slider-size=%d incr=%d pageIncr=%d value = %d\n", - orient == XmVERTICAL ? "VSB" : "HSB", min, max, size, - incr, pIncr, value); -} - - -/* - * client_data is MScrollPanePeer instance - */ -static void -postScrollEvent(jint jorient, jobject peer, XmScrollBarCallbackStruct *scroll) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - jint jscrollcode; - jboolean jadjusting = JNI_FALSE; - - switch (scroll->reason) { - case XmCR_DECREMENT: - jscrollcode = java_awt_event_AdjustmentEvent_UNIT_DECREMENT; - break; - case XmCR_INCREMENT: - jscrollcode = java_awt_event_AdjustmentEvent_UNIT_INCREMENT; - break; - case XmCR_PAGE_DECREMENT: - jscrollcode = java_awt_event_AdjustmentEvent_BLOCK_DECREMENT; - break; - case XmCR_PAGE_INCREMENT: - jscrollcode = java_awt_event_AdjustmentEvent_BLOCK_INCREMENT; - break; - case XmCR_DRAG: - jscrollcode = java_awt_event_AdjustmentEvent_TRACK; - jadjusting = JNI_TRUE; - break; - case XmCR_VALUE_CHANGED: /* drag finished */ - case XmCR_TO_TOP: - case XmCR_TO_BOTTOM: - jscrollcode = java_awt_event_AdjustmentEvent_TRACK; - break; - default: - DASSERT(FALSE); - return; - } - - (*env)->CallVoidMethod(env, peer, mScrollPanePeerIDs.postScrollEventID, - jorient, jscrollcode, (jint)scroll->value, jadjusting); - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -/* - * client_data is MScrollPanePeer instance - */ -static void -ScrollPane_scrollV(Widget w, XtPointer client_data, XtPointer call_data) -{ - postScrollEvent(java_awt_Adjustable_VERTICAL, (jobject)client_data, - (XmScrollBarCallbackStruct *)call_data); -} - -/* - * client_data is MScrollPanePeer instance - */ -static void -ScrollPane_scrollH(Widget w, XtPointer client_data, XtPointer call_data) -{ - postScrollEvent(java_awt_Adjustable_HORIZONTAL, (jobject)client_data, - (XmScrollBarCallbackStruct *)call_data); -} - - -typedef XmNavigability (*NavigableCallback) (Widget); - -NavigableCallback oldClipNavigable = NULL; -Boolean clipCallbackInitialized = False; -XmNavigability MyClipNavigable(Widget wid) { - // We've installed this function for ClipWindow - if (XmIsClipWindow(wid)) { - // To be able to request focus on ClipWindow by call - // XmProcessTraversal(, XmTRAVERSE_CURRENT) we need to make - // it return XmCONTROL_NAVIGABLE. Default implementation returns - // DESCENDANTS_TAB_NAVIGABLE which doesn't allow this. - return XmCONTROL_NAVIGABLE; - } - if (oldClipNavigable) { - return oldClipNavigable(wid); - } - // this will never happen - return XmCONTROL_NAVIGABLE; -} - -const char * ScrollPaneManagerName = "ScrolledWindowClipWindow"; -NavigableCallback oldManagerNavigable = NULL; -Boolean managerCallbackInitialized = False; -XmNavigability MyManagerNavigable(Widget wid) { - // We've installed this function for Manager - // with the name ScrollPaneManagerName - if (XmIsManager(wid) - && ( XtName(wid) != NULL && strcmp(XtName(wid), ScrollPaneManagerName) == 0) ) - { - // To be able to request focus on Manager by call - // XmProcessTraversal(, XmTRAVERSE_CURRENT) we need to make - // it return XmCONTROL_NAVIGABLE. Default implementation returns - // DESCENDANTS_TAB_NAVIGABLE which doesn't allow this. - return XmCONTROL_NAVIGABLE; - } - if (oldManagerNavigable) { - return oldManagerNavigable(wid); - } - // this will never happen - return XmCONTROL_NAVIGABLE; -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MScrollPanePeer_create - (JNIEnv *env, jobject this, jobject parent) -{ - int32_t argc; -#define MAX_ARGC 40 - Arg args[MAX_ARGC]; - struct ComponentData *wdata; - struct ComponentData *sdata; - jobject target; - Pixel bg; - Widget vsb, hsb; - jint sbDisplay; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - - if (JNU_IsNull(env, target) || wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - sdata = ZALLOC(ComponentData); - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,sdata); - - if (sdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - - adata = copyGraphicsConfigToPeer(env, this); - - argc = 0; - - sbDisplay = - (*env)->GetIntField(env, target, scrollPaneIDs.scrollbarDisplayPolicy); - - XtSetArg(args[argc], XmNuserData, (XtPointer) globalRef); - argc++; - - - if (sbDisplay == java_awt_ScrollPane_SCROLLBARS_NEVER) { - DASSERT(!(argc > MAX_ARGC)); - sdata->widget = XtCreateWidget(ScrollPaneManagerName, - xmManagerWidgetClass, wdata->widget, - args, argc); - - { - // To be able to request focus on Manager by call - // XmProcessTraversal(, XmTRAVERSE_CURRENT) we need to make - // it return XmCONTROL_NAVIGABLE from widgetNavigable callback. - // Default implementation returns DESCENDANTS_TAB_NAVIGABLE - // which doesn't allow this. - if (!managerCallbackInitialized) { - XmBaseClassExt *er; - WidgetClass wc; - managerCallbackInitialized = True; - wc = (WidgetClass) &xmManagerClassRec; - er = _XmGetBaseClassExtPtr(wc, XmQmotif); - oldManagerNavigable = (*er)->widgetNavigable; - (*er)->widgetNavigable = MyManagerNavigable; - } - } - } - else - { - XtSetArg(args[argc], XmNscrollingPolicy, XmAUTOMATIC); - argc++; - XtSetArg(args[argc], XmNvisualPolicy, XmCONSTANT); - argc++; - if (sbDisplay == java_awt_ScrollPane_SCROLLBARS_ALWAYS) { - DASSERT(!(argc > MAX_ARGC)); - XtSetArg(args[argc], XmNscrollBarDisplayPolicy, XmSTATIC); - argc++; - } else { - XtSetArg(args[argc], XmNscrollBarDisplayPolicy, XmAS_NEEDED); - argc++; - } - - XtSetArg(args[argc], XmNspacing, 0); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - sdata->widget = XmCreateScrolledWindow(wdata->widget, "scroller", args, argc); - - XtVaGetValues(sdata->widget, - XmNverticalScrollBar, &vsb, - XmNhorizontalScrollBar, &hsb, - NULL); - - if (vsb != NULL) { - XtAddCallback(vsb, XmNincrementCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNdecrementCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNpageIncrementCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNpageDecrementCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNtoTopCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNtoBottomCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNvalueChangedCallback, ScrollPane_scrollV, (XtPointer) globalRef); - XtAddCallback(vsb, XmNdragCallback, ScrollPane_scrollV, (XtPointer) globalRef); - - XtVaSetValues(vsb, XmNhighlightThickness, 0, NULL); - } - if (hsb != NULL) { - XtAddCallback(hsb, XmNincrementCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNdecrementCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNpageIncrementCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNpageDecrementCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNtoTopCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNtoBottomCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNvalueChangedCallback, ScrollPane_scrollH, (XtPointer) globalRef); - XtAddCallback(hsb, XmNdragCallback, ScrollPane_scrollH, (XtPointer) globalRef); - - XtVaSetValues(hsb, XmNhighlightThickness, 0, NULL); - } - { - /** - * Fix for 4033837 - ScrollPane doesn't generate mouse, focus, key events - * If ScrollPane created with ALWAYS or AS_NEEDED scrollbars policy then - * the upper widget is ClipWindow. We should install callbacks on it to - * receive event notifications. - */ - Widget clip = XtNameToWidget(sdata->widget, "*ClipWindow"); - if (clip != NULL) { - // To be able to request focus on Manager by call - // XmProcessTraversal(, XmTRAVERSE_CURRENT) we need to make - // it return XmCONTROL_NAVIGABLE from widgetNavigable callback. - // Default implementation returns DESCENDANTS_TAB_NAVIGABLE - // which doesn't allow this. - if (!clipCallbackInitialized) { - XmBaseClassExt *er; - clipCallbackInitialized = True; - er = _XmGetBaseClassExtPtr(XtClass(clip), XmQmotif); - oldClipNavigable = (*er)->widgetNavigable; - (*er)->widgetNavigable = MyClipNavigable; - } - awt_addWidget(clip, sdata->widget, globalRef, java_awt_AWTEvent_MOUSE_EVENT_MASK | - java_awt_AWTEvent_MOUSE_MOTION_EVENT_MASK | java_awt_AWTEvent_KEY_EVENT_MASK); - } - } - { - /** - * Fix for 4033837 - ScrollPane with ALWAYS doesn't have scrollbars visible - * It seems to be the bug in Motif, the workaround is to add empty child. - * User child will replace it when needed. This doesn't work if child had been - * removed. - */ - if (sbDisplay == java_awt_ScrollPane_SCROLLBARS_ALWAYS) { - Widget darea = NULL; - argc = 0; - XtSetArg(args[argc], XmNwidth, 1); - argc++; - XtSetArg(args[argc], XmNheight, 1); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNspacing, 0); - argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); - argc++; - darea = XmCreateDrawingArea(sdata->widget, "null_child", args, argc); - - XmScrolledWindowSetAreas(sdata->widget, NULL, NULL, darea); - XtSetMappedWhenManaged(darea, False); - XtManageChild(darea); - } - } - - } - - XtSetMappedWhenManaged(sdata->widget, False); - XtManageChild(sdata->widget); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pSetScrollChild - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MScrollPanePeer_pSetScrollChild - (JNIEnv *env, jobject this, jobject child) -{ - struct ComponentData *cdata; - struct ComponentData *sdata; - jobject target; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, child) || JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,child,mComponentPeerIDs.pData); - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (sdata == NULL || cdata == NULL || sdata->widget == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - - return; - } - if ((*env)->GetIntField(env, target, scrollPaneIDs.scrollbarDisplayPolicy) - == java_awt_ScrollPane_SCROLLBARS_NEVER) { - /* Do Nothing */ - } else { - XmScrolledWindowSetAreas(sdata->widget, NULL, NULL, cdata->widget); - /* - XtInsertEventHandler(cdata->widget, StructureNotifyMask, FALSE, - child_event_handler, sdata->widget, XtListHead); - */ - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pSetIncrement - * Signature: (III)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MScrollPanePeer_pSetIncrement - (JNIEnv *env, jobject this, jint orient, jint incrType, jint incr) -{ - struct ComponentData *sdata; - Widget scrollbar = NULL; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (sdata == NULL || sdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (!XtIsSubclass(sdata->widget, xmScrolledWindowWidgetClass)) { - AWT_UNLOCK(); - return; - } - if (orient == java_awt_Adjustable_VERTICAL) { - XtVaGetValues(sdata->widget, - XmNverticalScrollBar, &scrollbar, - NULL); - } else { - XtVaGetValues(sdata->widget, - XmNhorizontalScrollBar, &scrollbar, - NULL); - } - - if (scrollbar != NULL) { - if (incrType == sun_awt_motif_MScrollPanePeer_UNIT_INCREMENT) { - XtVaSetValues(scrollbar, - XmNincrement, (XtArgVal) incr, - NULL); - - } else { - /* BLOCK_INCREMENT */ - XtVaSetValues(scrollbar, - XmNpageIncrement, (XtArgVal) incr, - NULL); - } - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pGetScrollbarSpace - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MScrollPanePeer_pGetScrollbarSpace - (JNIEnv *env, jobject this, jint orient) -{ - struct ComponentData *sdata; - Widget scrollbar; - Dimension thickness = 0; - Dimension space = 0; - Dimension highlight = 0; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL || sdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (orient == java_awt_Adjustable_VERTICAL) { - XtVaGetValues(sdata->widget, - XmNverticalScrollBar, &scrollbar, - XmNspacing, &space, - NULL); - XtVaGetValues(scrollbar, - XmNwidth, &thickness, - XmNhighlightThickness, &highlight, - NULL); - } else { - XtVaGetValues(sdata->widget, - XmNhorizontalScrollBar, &scrollbar, - XmNspacing, &space, - NULL); - XtVaGetValues(scrollbar, - XmNheight, &thickness, - XmNhighlightThickness, &highlight, - NULL); - } - - AWT_UNLOCK(); - return (jint) (thickness + space + 2 * highlight); -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pGetBlockIncrement - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MScrollPanePeer_pGetBlockIncrement - (JNIEnv *env, jobject this, jint orient) -{ - int32_t pageIncr = 0; - struct ComponentData *sdata; - Widget scrollbar; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (sdata == NULL || sdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (orient == java_awt_Adjustable_VERTICAL) { - - XtVaGetValues(sdata->widget, - XmNverticalScrollBar, &scrollbar, - NULL); - XtVaGetValues(scrollbar, - XmNpageIncrement, &pageIncr, - NULL); - } else { - - XtVaGetValues(sdata->widget, - XmNhorizontalScrollBar, &scrollbar, - NULL); - XtVaGetValues(scrollbar, - XmNpageIncrement, &pageIncr, - NULL); - } - - AWT_UNLOCK(); - return (jint) (pageIncr); -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pInsets - * Signature: (IIII)Ljava/awt/Insets; - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MScrollPanePeer_pInsets - (JNIEnv *env, jobject this, jint width, jint height, jint childWidth, jint childHeight) -{ - struct ComponentData *sdata; - jobject target; - jobject insets = NULL; - Widget hsb, vsb; - Dimension hsbThickness, hsbHighlight, hsbSpace = 0, - vsbThickness, vsbHighlight, vsbSpace = 0, - space, border, shadow, hMargin, vMargin; - unsigned char placement; - Boolean hsbVisible, vsbVisible; - jint sbDisplay; - int32_t top, left, right, bottom; - jclass clazz; - jmethodID mid; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target) || sdata == NULL || sdata->widget == NULL) - { - JNU_ThrowNullPointerException(env, "sdata is NULL"); - AWT_UNLOCK(); - return 0; - } - sbDisplay = - (*env)->GetIntField(env, target, scrollPaneIDs.scrollbarDisplayPolicy); - - /* REMIND: investigate caching these values rather than querying for - * them each time. - */ - - if (sbDisplay == java_awt_ScrollPane_SCROLLBARS_NEVER) { - XtVaGetValues(sdata->widget, - XmNshadowThickness, &shadow, - NULL); - space = border = hMargin = vMargin = 0; - - } else { - XtVaGetValues(sdata->widget, - XmNverticalScrollBar, &vsb, - XmNhorizontalScrollBar, &hsb, - XmNscrollBarPlacement, &placement, - XmNspacing, &space, - XmNshadowThickness, &shadow, - XmNscrolledWindowMarginHeight, &vMargin, - XmNscrolledWindowMarginWidth, &hMargin, - XmNborderWidth, &border, - NULL); - - XtVaGetValues(vsb, - XmNwidth, &vsbThickness, - XmNhighlightThickness, &vsbHighlight, - NULL); - - XtVaGetValues(hsb, - XmNheight, &hsbThickness, - XmNhighlightThickness, &hsbHighlight, - NULL); - - hsbSpace = hsbThickness + space + hsbHighlight; - vsbSpace = vsbThickness + space + vsbHighlight; - -/* - XtVaGetValues(clip, - XmNwidth, &clipw, XmNheight, &cliph, - XmNx, &clipx, XmNy, &clipy, - NULL); - printf("insets: spacing=%d shadow=%d swMarginH=%d swMarginW=%d border=%d ; \ - vsb=%d vsbHL=%d ; hsb=%d hsbHL=%d ; %dx%d ->clip=%d,%d %dx%d\n", - space, shadow, vMargin, hMargin, border, - vsbThickness, vsbHighlight, hsbThickness, hsbHighlight, - w, h, clipx, clipy, clipw, cliph); -*/ - } - - /* We unfortunately have to use the size parameters to determine - * whether or not "as needed" scrollbars are currently present or - * not because we can't necessarily rely on getting valid geometry - * values straight from the Motif widgets until they are mapped. :( - */ - switch (sbDisplay) { - case java_awt_ScrollPane_SCROLLBARS_NEVER: - vsbVisible = hsbVisible = FALSE; - break; - - case java_awt_ScrollPane_SCROLLBARS_ALWAYS: - vsbVisible = hsbVisible = TRUE; - break; - - case java_awt_ScrollPane_SCROLLBARS_AS_NEEDED: - default: - vsbVisible = hsbVisible = FALSE; - if (childWidth > width - 2 * shadow) { - hsbVisible = TRUE; - } - if (childHeight > height - 2 * shadow) { - vsbVisible = TRUE; - } - if (!hsbVisible && vsbVisible && childWidth > width - 2 * shadow - vsbSpace) { - hsbVisible = TRUE; - } else if (!vsbVisible && hsbVisible && childHeight > height - 2 * shadow - hsbSpace) { - vsbVisible = TRUE; - } - } - - top = bottom = shadow + vMargin; - left = right = shadow + hMargin; - - if (sbDisplay != java_awt_ScrollPane_SCROLLBARS_NEVER) { - switch (placement) { - case XmBOTTOM_RIGHT: - bottom += (hsbVisible ? hsbSpace : (vsbVisible ? vsbHighlight : 0)); - right += (vsbVisible ? vsbSpace : (hsbVisible ? hsbHighlight : 0)); - top += (vsbVisible ? vsbHighlight : 0); - left += (hsbVisible ? hsbHighlight : 0); - break; - - case XmBOTTOM_LEFT: - bottom += (hsbVisible ? hsbSpace : (vsbVisible ? vsbHighlight : 0)); - left += (vsbVisible ? hsbSpace : (hsbVisible ? hsbHighlight : 0)); - top += (vsbVisible ? vsbHighlight : 0); - right += (hsbVisible ? hsbHighlight : 0); - break; - - case XmTOP_RIGHT: - top += (hsbVisible ? hsbSpace : (vsbVisible ? vsbHighlight : 0)); - right += (vsbVisible ? vsbSpace : (hsbVisible ? hsbHighlight : 0)); - bottom += (vsbVisible ? vsbHighlight : 0); - left += (hsbVisible ? hsbHighlight : 0); - break; - - case XmTOP_LEFT: - top += (hsbVisible ? hsbSpace : (vsbVisible ? vsbHighlight : 0)); - left += (vsbVisible ? vsbSpace : (hsbVisible ? hsbHighlight : 0)); - bottom += (vsbVisible ? vsbHighlight : 0); - right += (hsbVisible ? hsbHighlight : 0); - } - } - /* Deadlock prevention: - * don't hold the toolkit lock while invoking constructor. - */ - AWT_UNLOCK(); - - clazz = (*env)->FindClass(env, "java/awt/Insets"); - mid = (*env)->GetMethodID(env, clazz, "", "(IIII)V"); - if (mid != NULL) { - insets = (*env)->NewObject(env, clazz, mid, - (jint) top, - (jint) left, - (jint) bottom, - (jint) right); - - } - /* This should catch both method not found and error exceptions */ - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (JNU_IsNull(env, insets)) { - JNU_ThrowNullPointerException(env, "NullPointerException: insets constructor failed"); - } - return insets; -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: setScrollPosition - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MScrollPanePeer_setScrollPosition - (JNIEnv *env, jobject this, jint x, jint y) -{ - struct ComponentData *sdata; - jobject target; - Widget hsb, vsb; - int32_t size, incr, pIncr; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target) || sdata == NULL || sdata->widget == NULL) - { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if ((*env)->GetIntField(env, target, scrollPaneIDs.scrollbarDisplayPolicy) - == java_awt_ScrollPane_SCROLLBARS_NEVER) { - WidgetList children; - Cardinal numChildren; - - XtVaGetValues(sdata->widget, - XmNchildren, &children, - XmNnumChildren, &numChildren, - NULL); - - if (numChildren < 1) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtMoveWidget(children[0], (Position) -x, (Position) -y); - } else { - int32_t sb_min = 0; - int32_t sb_max = 0; - XtVaGetValues(sdata->widget, - XmNhorizontalScrollBar, &hsb, - XmNverticalScrollBar, &vsb, - NULL); - - if (vsb) { - XtVaGetValues(vsb, - XmNincrement, &incr, - XmNpageIncrement, &pIncr, - XmNsliderSize, &size, - XmNminimum, &sb_min, - XmNmaximum, &sb_max, - NULL); - /* Bug 4208972, 4275934 : Do range checking for scroll bar value. */ - if (y < sb_min) - y = sb_min; - if (y > (sb_max - size)) - y = sb_max - size; - XmScrollBarSetValues(vsb, (int32_t) y, size, incr, pIncr, TRUE); - } - if (hsb) { - XtVaGetValues(hsb, - XmNincrement, &incr, - XmNpageIncrement, &pIncr, - XmNsliderSize, &size, - XmNminimum, &sb_min, - XmNmaximum, &sb_max, - NULL); - /* Bug 4208972, 4275934 : Do range checking for scroll bar value. */ - if (x < sb_min) - x = sb_min; - if (x > (sb_max - size)) - x = sb_max - size; - XmScrollBarSetValues(hsb, (int32_t) x, size, incr, pIncr, TRUE); - } - } - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: pGetShadow - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MScrollPanePeer_pGetShadow( - JNIEnv *env, jobject this) { - struct ComponentData *sdata; - jobject target; - Dimension shadow=0 ; - - AWT_LOCK() ; - sdata = (struct ComponentData *) - (*env)->GetLongField(env,this,mComponentPeerIDs.pData); - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target) || sdata == NULL || sdata->widget == NULL) - { - JNU_ThrowNullPointerException(env, "sdata is NULL"); - AWT_UNLOCK(); - return 0; - } - - XtVaGetValues(sdata->widget, - XmNshadowThickness, - &shadow, - NULL); - - AWT_UNLOCK() ; - - return((jint)shadow) ; -} - -/* - * Class: sun_awt_motif_MScrollPanePeer - * Method: setTypedValue - * Signature: (Ljava/awt/ScrollPaneAdjustable;II)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollPanePeer_setTypedValue(JNIEnv *env, jobject peer, jobject adjustable, jint value, jint type) -{ - static jmethodID setTypedValueMID = 0; - if (setTypedValueMID == NULL) { - jclass clazz = (*env)->FindClass(env, "java/awt/ScrollPaneAdjustable"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - return; - } - setTypedValueMID = (*env)->GetMethodID(env, clazz, "setTypedValue", "(II)V"); - (*env)->DeleteLocalRef(env, clazz); - - DASSERT(setTypedValueMID != NULL); - } - (*env)->CallVoidMethod(env, adjustable, setTypedValueMID, value, type); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Scrollbar.c --- a/jdk/src/solaris/native/sun/awt/awt_Scrollbar.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,440 +0,0 @@ -/* - * Copyright 1995-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_Scrollbar.h" -#include "java_awt_event_MouseEvent.h" -#include "sun_awt_motif_MScrollbarPeer.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "awt_Component.h" -#include "canvas.h" - -#include -#include -#include "multi_font.h" - - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -/* fieldIDs for java.awt.Scrollbar fields that may be accessed from C */ -static struct ScrollbarIDs { - jfieldID orientation; - jfieldID visibleAmount; - jfieldID lineIncrement; - jfieldID pageIncrement; - jfieldID value; - jfieldID minimum; - jfieldID maximum; -} targetIDs; - -/* MScrollbarPeer callback methods */ -static struct { - jmethodID lineUp; - jmethodID lineDown; - jmethodID pageUp; - jmethodID pageDown; - jmethodID drag; - jmethodID dragEnd; - jmethodID warp; -} peerIDs; - - - -/* - * Class: java_awt_ScrollBar - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - Scrollbar.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_Scrollbar_initIDs(JNIEnv *env, jclass cls) -{ - targetIDs.orientation = - (*env)->GetFieldID(env, cls, "orientation", "I"); - targetIDs.visibleAmount = - (*env)->GetFieldID(env, cls, "visibleAmount", "I"); - targetIDs.lineIncrement = - (*env)->GetFieldID(env, cls, "lineIncrement", "I"); - targetIDs.pageIncrement = - (*env)->GetFieldID(env, cls, "pageIncrement", "I"); - targetIDs.value = - (*env)->GetFieldID(env, cls, "value", "I"); - targetIDs.minimum = - (*env)->GetFieldID(env, cls, "minimum", "I"); - targetIDs.maximum = - (*env)->GetFieldID(env, cls, "maximum", "I"); -} - - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MScrollbarPeer to initialize the JNI ids for fields and methods - that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollbarPeer_initIDs(JNIEnv *env, jclass cls) -{ - peerIDs.lineUp = - (*env)->GetMethodID(env, cls, "lineUp", "(I)V"); - peerIDs.lineDown = - (*env)->GetMethodID(env, cls, "lineDown", "(I)V"); - peerIDs.pageUp = - (*env)->GetMethodID(env, cls, "pageUp", "(I)V"); - peerIDs.pageDown = - (*env)->GetMethodID(env, cls, "pageDown", "(I)V"); - peerIDs.drag = - (*env)->GetMethodID(env, cls, "drag", "(I)V"); - peerIDs.dragEnd = - (*env)->GetMethodID(env, cls, "dragEnd", "(I)V"); - peerIDs.warp = - (*env)->GetMethodID(env, cls, "warp", "(I)V"); -} - -/* - * Call peer.jcallback(value) - */ -static void -DoJavaCallback(jobject peer, jmethodID jcallback, jint value) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - (*env)->CallVoidMethod(env, peer, jcallback, value); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - - -static void /* XtCallbackProc */ -decrementCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_DECREMENT); - DoJavaCallback(peer, peerIDs.lineUp, scroll->value); -} - -static void /* XtCallbackProc */ -incrementCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_INCREMENT); - DoJavaCallback(peer, peerIDs.lineDown, scroll->value); -} - -static void /* XtCallbackProc */ -pageDecrementCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_PAGE_DECREMENT); - DoJavaCallback(peer, peerIDs.pageUp, scroll->value); -} - -static void /* XtCallbackProc */ -pageIncrementCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_PAGE_INCREMENT); - DoJavaCallback(peer, peerIDs.pageDown, scroll->value); -} - -static void /* XtCallbackProc */ -dragCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_DRAG); - DoJavaCallback(peer, peerIDs.drag, scroll->value); -} - -static void /* XtCallbackProc */ -dragEndCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_VALUE_CHANGED); - DoJavaCallback(peer, peerIDs.dragEnd, scroll->value); -} - -static void /* XtCallbackProc */ -toTopCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_TO_TOP); - DoJavaCallback(peer, peerIDs.warp, scroll->value); -} - -static void /* XtCallbackProc */ -toBottomCallback(Widget w, jobject peer, - XmScrollBarCallbackStruct *scroll) -{ - DASSERT(scroll->reason == XmCR_TO_BOTTOM); - DoJavaCallback(peer, peerIDs.warp, scroll->value); -} - - -/* - * Class: sun_awt_motif_MScrollbarPeer - * Method: create - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollbarPeer_create(JNIEnv *env, jobject this, - jobject parent) -{ - Widget w; - - jobject target; - XtPointer globalRef = (XtPointer) /* jobject */ - awtJNI_CreateAndSetGlobalRef(env, this); - - struct ComponentData *pdata; /* for parent */ - struct ComponentData *sdata; /* for scrollbar */ - AwtGraphicsConfigDataPtr adata; - - int32_t value, visible, minimum, maximum; - int32_t lineIncrement, pageIncrement; - Pixel bg; - -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - int32_t argc = 0; - - - AWT_LOCK(); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - pdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, parent, mComponentPeerIDs.pData); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target) || pdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - - switch ((*env)->GetIntField(env, target, targetIDs.orientation)) { - case java_awt_Scrollbar_HORIZONTAL: - XtSetArg(args[argc], XmNorientation, XmHORIZONTAL); - argc++; - break; - - case java_awt_Scrollbar_VERTICAL: - XtSetArg(args[argc], XmNorientation, XmVERTICAL); - argc++; - break; - - default: - JNU_ThrowIllegalArgumentException(env, "bad scrollbar orientation"); - AWT_UNLOCK(); - return; - } - - adata = copyGraphicsConfigToPeer(env, this); - XtVaGetValues(pdata->widget, XmNbackground, &bg, NULL); - - visible = (int32_t) (*env)->GetIntField(env, target, targetIDs.visibleAmount); - value = (int32_t) (*env)->GetIntField(env, target, targetIDs.value); - minimum = (int32_t) (*env)->GetIntField(env, target, targetIDs.minimum); - maximum = (int32_t) (*env)->GetIntField(env, target, targetIDs.maximum); - lineIncrement = - (int32_t) (*env)->GetIntField(env, target, targetIDs.lineIncrement); - pageIncrement = - (int32_t) (*env)->GetIntField(env, target, targetIDs.pageIncrement); - - /* - * Sanity check. Scrollbar.setValues should have taken care. - */ - DASSERT(maximum > minimum); - DASSERT(visible <= maximum - minimum); - DASSERT(visible >= 1); - DASSERT(value >= minimum); - DASSERT(value <= maximum - visible); - - XtSetArg(args[argc], XmNx, 0); argc++; - XtSetArg(args[argc], XmNy, 0); argc++; - XtSetArg(args[argc], XmNvalue, value); argc++; - XtSetArg(args[argc], XmNsliderSize, visible); argc++; - XtSetArg(args[argc], XmNminimum, minimum); argc++; - XtSetArg(args[argc], XmNmaximum, maximum); argc++; - XtSetArg(args[argc], XmNincrement, lineIncrement); argc++; - XtSetArg(args[argc], XmNpageIncrement, pageIncrement); argc++; - XtSetArg(args[argc], XmNbackground, bg); argc++; - XtSetArg(args[argc], XmNrecomputeSize, False); argc++; - XtSetArg(args[argc], XmNuserData, globalRef); argc++; - XtSetArg(args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); argc++; - - DASSERT(argc <= MAX_ARGC); /* sanity check */ - - sdata = ZALLOC(ComponentData); - if (sdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, sdata); - - sdata->widget = w = - XmCreateScrollBar(pdata->widget, "scrollbar", args, argc); - - XtAddCallback(w, XmNdecrementCallback, - (XtCallbackProc)decrementCallback, globalRef); - XtAddCallback(w, XmNincrementCallback, - (XtCallbackProc)incrementCallback, globalRef); - XtAddCallback(w, XmNpageDecrementCallback, - (XtCallbackProc)pageDecrementCallback, globalRef); - XtAddCallback(w, XmNpageIncrementCallback, - (XtCallbackProc)pageIncrementCallback, globalRef); - XtAddCallback(w, XmNtoTopCallback, - (XtCallbackProc)toTopCallback, globalRef); - XtAddCallback(w, XmNtoBottomCallback, - (XtCallbackProc)toBottomCallback, globalRef); - XtAddCallback(w, XmNdragCallback, - (XtCallbackProc)dragCallback, globalRef); - XtAddCallback(w, XmNvalueChangedCallback, - (XtCallbackProc)dragEndCallback, globalRef); - - /* Set up workaround for the continuous scrolling bug */ - XtAddEventHandler(w, ButtonReleaseMask, False, - awt_motif_Scrollbar_ButtonReleaseHandler, NULL); - - /* Fix for 4955950. ButtonRelease & MotionNotify should be handled as well */ - XtAddEventHandler(w, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - False, awt_canvas_event_handler, globalRef); - - XtSetMappedWhenManaged(w, False); - XtManageChild(w); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MScrollbarPeer - * Method: pSetValues - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollbarPeer_pSetValues(JNIEnv *env, jobject this, - jint value, jint visible, jint minimum, jint maximum) -{ - struct ComponentData *sdata; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - /* pass in visible for sliderSize since Motif will calculate the */ - /* slider's size for us. */ - XtVaSetValues(sdata->widget, - XmNminimum, minimum, - XmNmaximum, maximum, - XmNvalue, value, - XmNsliderSize, visible, - NULL); - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MScrollbarPeer - * Method: setLineIncrement - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollbarPeer_setLineIncrement(JNIEnv *env, jobject this, - jint value) -{ - struct ComponentData *sdata; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(sdata->widget, - XmNincrement, value, - NULL); - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MScrollbarPeer - * Method: setPageIncrement - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MScrollbarPeer_setPageIncrement(JNIEnv *env, jobject this, - jint value) -{ - struct ComponentData *sdata; - - AWT_LOCK(); - - sdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (sdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(sdata->widget, - XmNpageIncrement, value, - NULL); - AWT_FLUSH_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_Selection.c --- a/jdk/src/solaris/native/sun/awt/awt_Selection.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,508 +0,0 @@ -/* - * Copyright 1996-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "awt_DataTransferer.h" -#include "java_awt_datatransfer_Transferable.h" -#include "java_awt_datatransfer_DataFlavor.h" -#include "sun_awt_motif_X11Selection.h" -#include "sun_awt_motif_X11Clipboard.h" -#include -#include -#include - -#include -#include - -/* fieldIDs for X11Selection fields that may be accessed from C */ -static struct X11SelectionIDs { - jfieldID holder; - jfieldID atom; - jfieldID contents; - jfieldID selections; -} x11SelectionIDs; - -DECLARE_JAVA_CLASS(selectionClazz, "sun/awt/motif/X11Selection") - -static jobject -call_getSelectionsArray(JNIEnv* env) { - DECLARE_STATIC_OBJECT_JAVA_METHOD(getSelectionsArray, selectionClazz, - "getSelectionsArray", "()[Ljava/lang/Object;") - DASSERT(!JNU_IsNull(env, getSelectionsArray)); - return (*env)->CallStaticObjectMethod(env, clazz, getSelectionsArray); -} - -static void -call_checkChange(JNIEnv* env, jobject jselection, jlongArray targetArray) -{ - DECLARE_VOID_JAVA_METHOD(checkChangeMID, selectionClazz, - "checkChange", "([J)V") - DASSERT(!JNU_IsNull(env, jselection)); - - (*env)->CallVoidMethod(env, jselection, checkChangeMID, targetArray); -} - -static jlongArray -call_getSelectionAtomsToCheckChange(JNIEnv* env) -{ - DECLARE_STATIC_OBJECT_JAVA_METHOD(getSelectionAtomsToCheckChangeMID, - selectionClazz, "getSelectionAtomsToCheckChange", "()[J") - - return (jlongArray)(*env)->CallStaticObjectMethod(env, - get_selectionClazz(env), getSelectionAtomsToCheckChangeMID); - -} - - -/* - * Class: sun_awt_motif_X11Selection - * Method: initIDs - * Signature: ()V - */ -/* This function gets called from the static initializer for - X11Selection.java to initialize the fieldIDs for fields that may - be accessed from C */ -JNIEXPORT void JNICALL Java_sun_awt_motif_X11Selection_initIDs - (JNIEnv *env, jclass cls) -{ - x11SelectionIDs.holder = (*env)-> - GetFieldID(env, cls, "holder","Lsun/awt/motif/X11SelectionHolder;"); - x11SelectionIDs.atom = (*env)->GetFieldID(env, cls, "atom", "J"); - x11SelectionIDs.contents = (*env)-> - GetFieldID(env, cls, "contents", - "Ljava/awt/datatransfer/Transferable;"); - x11SelectionIDs.selections = (*env)-> - GetStaticFieldID(env, cls, "selections", "Ljava/util/Vector;"); -} - -/* - * Class: sun_awt_motif_X11Selection - * Method: init - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_X11Selection_init - (JNIEnv *env, jclass this) -{ - AWT_LOCK(); - - AWT_UNLOCK(); -} - -static jobject -getX11Selection(JNIEnv * env, Atom atom) -{ - jobjectArray selections; - jsize selectionCount, i; - jobject selection; - jobject returnSelection = NULL; - - selections = (jobjectArray)call_getSelectionsArray(env); - - if (JNU_IsNull(env, selections)) { - return NULL; - } - - selectionCount = (*env)->GetArrayLength(env, selections); - - for (i = 0; i < selectionCount; i++) { - selection = (*env)->GetObjectArrayElement(env, selections, i); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - break; - } - if (JNU_IsNull(env, selection)) { - break; - } - if ((*env)->GetLongField(env, selection, x11SelectionIDs.atom) == atom) { - returnSelection = selection; - } else { - (*env)->DeleteLocalRef(env, selection); - } - } - - (*env)->DeleteLocalRef(env, selections); - - return returnSelection; -} - -Boolean -awtJNI_isSelectionOwner(JNIEnv * env, char *sel_str) -{ - Atom selection; - jobject x11sel; - - selection = XInternAtom(awt_display, sel_str, False); - - x11sel = getX11Selection(env, selection); - if (!JNU_IsNull(env, x11sel)) { - jobject holder; - - holder = (*env)->GetObjectField(env, x11sel, x11SelectionIDs.holder); - if (!JNU_IsNull(env, holder)) { - return TRUE; - } - } - return FALSE; -} - -static void losingSelectionOwnership(Widget w, Atom * selection); - -void -awtJNI_notifySelectionLost(JNIEnv * env, char *sel_str) -{ - Atom selection; - - selection = XInternAtom(awt_display, sel_str, False); - losingSelectionOwnership(NULL, &selection); -} - -static void -losingSelectionOwnership(Widget w, Atom * selection) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = getX11Selection(env, *selection); - - /* - * SECURITY: OK to call this on privileged thread - peer does - * not call into client code - */ - JNU_CallMethodByName(env, NULL, this, "lostSelectionOwnership", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - /* - * Fix for 4692059. - * The native context is cleaned up on the event dispatch thread after the - * references to the current contents and owner are cleared. - */ -} - -/* - * Class: sun_awt_motif_X11Selection - * Method: pGetSelectionOwnership - * Signature: (Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;[JLjava/util/Map;Lsun/awt/motif/X11SelectionHolder;)Z - */ -JNIEXPORT jboolean JNICALL -Java_sun_awt_motif_X11Selection_pGetSelectionOwnership(JNIEnv *env, - jobject this, - jobject source, - jobject transferable, - jlongArray formats, - jobject formatMap, - jobject holder) -{ - Boolean gotit = False; - Atom selection = (Atom)(*env)->GetLongField(env, this, - x11SelectionIDs.atom); - awt_convertDataCallbackStruct* structPtr = NULL; - Time time = CurrentTime; - - AWT_LOCK(); - - time = awt_util_getCurrentServerTime(); - - (*env)->SetObjectField(env, this, x11SelectionIDs.holder, NULL); - (*env)->SetObjectField(env, this, x11SelectionIDs.contents, NULL); - - gotit = XtOwnSelection(awt_root_shell, selection, time, awt_convertData, - losingSelectionOwnership, NULL); - - if (gotit) { - if (XFindContext(awt_display, selection, awt_convertDataContext, - (XPointer*)&structPtr) == 0 && structPtr != NULL) { - (*env)->DeleteGlobalRef(env, structPtr->source); - (*env)->DeleteGlobalRef(env, structPtr->transferable); - (*env)->DeleteGlobalRef(env, structPtr->formatMap); - (*env)->DeleteGlobalRef(env, structPtr->formats); - memset(structPtr, 0, sizeof(awt_convertDataCallbackStruct)); - } else { - XDeleteContext(awt_display, selection, awt_convertDataContext); - - structPtr = calloc(1, sizeof(awt_convertDataCallbackStruct)); - - if (structPtr == NULL) { - XtDisownSelection(awt_root_shell, selection, time); - AWT_UNLOCK(); - JNU_ThrowOutOfMemoryError(env, ""); - return JNI_FALSE; - } - - if (XSaveContext(awt_display, selection, awt_convertDataContext, - (XPointer)structPtr) == XCNOMEM) { - XtDisownSelection(awt_root_shell, selection, time); - free(structPtr); - AWT_UNLOCK(); - JNU_ThrowInternalError(env, "Failed to save context data for selection."); - return JNI_FALSE; - } - } - - structPtr->source = (*env)->NewGlobalRef(env, source); - structPtr->transferable = (*env)->NewGlobalRef(env, transferable); - structPtr->formatMap = (*env)->NewGlobalRef(env, formatMap); - structPtr->formats = (*env)->NewGlobalRef(env, formats); - - if (JNU_IsNull(env, structPtr->source) || - JNU_IsNull(env, structPtr->transferable) || - JNU_IsNull(env, structPtr->formatMap) || - JNU_IsNull(env, structPtr->formats)) { - - if (!JNU_IsNull(env, structPtr->source)) { - (*env)->DeleteGlobalRef(env, structPtr->source); - } - if (!JNU_IsNull(env, structPtr->transferable)) { - (*env)->DeleteGlobalRef(env, structPtr->transferable); - } - if (!JNU_IsNull(env, structPtr->formatMap)) { - (*env)->DeleteGlobalRef(env, structPtr->formatMap); - } - if (!JNU_IsNull(env, structPtr->formats)) { - (*env)->DeleteGlobalRef(env, structPtr->formats); - } - XtDisownSelection(awt_root_shell, selection, time); - XDeleteContext(awt_display, selection, awt_convertDataContext); - free(structPtr); - AWT_UNLOCK(); - JNU_ThrowOutOfMemoryError(env, ""); - return JNI_FALSE; - } - - (*env)->SetObjectField(env, this, x11SelectionIDs.holder, holder); - (*env)->SetObjectField(env, this, x11SelectionIDs.contents, transferable); - } - AWT_UNLOCK(); - - return (gotit ? JNI_TRUE : JNI_FALSE); -} - -/* - * Class: sun_awt_motif_X11Selection - * Method: clearNativeContext - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11Selection_clearNativeContext(JNIEnv *env, jobject this) { - Atom selection = (Atom)(*env)->GetLongField(env, this, - x11SelectionIDs.atom); - - AWT_LOCK(); - - XtDisownSelection(awt_root_shell, selection, CurrentTime); - awt_cleanupConvertDataContext(env, selection); - - AWT_UNLOCK(); -} - - -static void -getSelectionTargetsToCheckChange(Widget w, XtPointer client_data, - Atom * selection, Atom * type, XtPointer value, unsigned long *length, - int32_t *format) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - size_t count = 0, i = 0, j = 0; - jlongArray targetArray = NULL; - - // Should keep this in sync with getSelectionTargets() so that - // this function yields non-null targetArray iff - // getSelectionTargets() yields SelectionSuccess. - if (*type == XA_TARGETS || *type == XA_ATOM) { - targetArray = getSelectionTargetsHelper(env, value, *length); - } else if (*type != XT_CONVERT_FAIL) { - targetArray = (*env)->NewLongArray(env, 0); - } - - if (value != NULL) { - XtFree(value); - value = NULL; - } - - { - jobject jselection = getX11Selection(env, *selection); - call_checkChange(env, jselection, targetArray); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - (*env)->DeleteLocalRef(env, targetArray); - (*env)->DeleteLocalRef(env, jselection); - } -} - - -static Atom _XA_JAVA_TIME_PROPERTY_ATOM_CHECK_SELECTION_CHANGE_ON_TIMEOUT = 0; - -static void -checkSelectionChangeOnTimeout(XtPointer client_data, XtIntervalId* id) -{ - // We don't call XtGetSelectionValue(..., TARGETS, ..., awt_util_getCurrentServerTime()) - // here because awt_util_getCurrentServerTime() may block toolkit therad for a while - // whereas the current function is called very often at regular intervals. - // Instead we call XtGetSelectionValue(..., XtLastTimestampProcessed(awt_display)) - // in the property change event handler wherein we have got an up-to-date timestamp. - - XChangeProperty(awt_display, XtWindow(awt_root_shell), - _XA_JAVA_TIME_PROPERTY_ATOM_CHECK_SELECTION_CHANGE_ON_TIMEOUT, - XA_ATOM, 32, PropModeAppend, (unsigned char *)"", 0); - XFlush(awt_display); -} - - -static unsigned long selectionPollInterval; - -static void -propertyChangeEventHandlerToSelectionCheck -(Widget w, XtPointer client_data, XEvent* event, Boolean* continue_to_dispatch) -{ - JNIEnv *env; - jlongArray jselectionAtoms; - - if (event->type != PropertyNotify || event->xproperty.atom != - _XA_JAVA_TIME_PROPERTY_ATOM_CHECK_SELECTION_CHANGE_ON_TIMEOUT) { - return; - } - - env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jselectionAtoms = call_getSelectionAtomsToCheckChange(env); - - DASSERT(!JNU_IsNull(env, jselectionAtoms)); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } else { - jsize len = (*env)->GetArrayLength(env, jselectionAtoms); - jlong* selectionAtomsNative = - (*env)->GetLongArrayElements(env, jselectionAtoms, NULL); - if (!JNU_IsNull(env, selectionAtomsNative)) { - jsize i = 0; - for (i = 0; i < len; i++) { - XtGetSelectionValue(awt_root_shell, (Atom)selectionAtomsNative[i], XA_TARGETS, - getSelectionTargetsToCheckChange, (XtPointer)NULL, - XtLastTimestampProcessed(awt_display)); - } - (*env)->ReleaseLongArrayElements(env, jselectionAtoms, - selectionAtomsNative, JNI_ABORT); - } - } - - // Reschedule the timer callback. - XtAppAddTimeOut(awt_appContext, selectionPollInterval, - checkSelectionChangeOnTimeout, client_data); -} - - -static BOOL isClipboardViewerRegistered = FALSE; - -/* - * Class: sun_awt_motif_X11Clipboard - * Method: registerClipboardViewer - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11Clipboard_registerClipboardViewer(JNIEnv *env, jobject self, - jint pollInterval) -{ - AWT_LOCK(); - - if (isClipboardViewerRegistered) { - AWT_UNLOCK(); - return; - } - - if (_XA_JAVA_TIME_PROPERTY_ATOM_CHECK_SELECTION_CHANGE_ON_TIMEOUT == 0) { - _XA_JAVA_TIME_PROPERTY_ATOM_CHECK_SELECTION_CHANGE_ON_TIMEOUT = - XInternAtom(awt_display, - "_SUNW_JAVA_AWT_TIME_CHECK_SELECTION_CHANGE_ON_TIMEOUT", - False); - } - - XtAddEventHandler(awt_root_shell, PropertyChangeMask, False, - propertyChangeEventHandlerToSelectionCheck, NULL); - - selectionPollInterval = pollInterval; - - XtAppAddTimeOut(awt_appContext, selectionPollInterval, - checkSelectionChangeOnTimeout, (XtPointer)NULL); - - isClipboardViewerRegistered = TRUE; - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_X11Clipboard - * Method: unregisterClipboardViewer - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11Clipboard_unregisterClipboardViewer(JNIEnv *env, jobject self) -{ - AWT_LOCK(); - - if (!isClipboardViewerRegistered) { - AWT_UNLOCK(); - return; - } - - XtRemoveEventHandler(awt_root_shell, PropertyChangeMask, False, - propertyChangeEventHandlerToSelectionCheck, NULL); - - isClipboardViewerRegistered = FALSE; - - AWT_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_X11Clipboard - * Method: getClipboardFormats - * Signature: (J)[J - */ -JNIEXPORT jlongArray JNICALL -Java_sun_awt_motif_X11Clipboard_getClipboardFormats - (JNIEnv *env, jclass cls, jlong selectionAtom) -{ - Time time_stamp = awt_util_getCurrentServerTime(); - return get_selection_targets(env, selectionAtom, time_stamp); -} - -/* - * Class: sun_awt_motif_X11Clipboard - * Method: getClipboardData - * Signature: (JJ)[B - */ -JNIEXPORT jbyteArray JNICALL -Java_sun_awt_motif_X11Clipboard_getClipboardData - (JNIEnv *env, jclass cls, jlong selectionAtom, jlong format) -{ - Time time_stamp = awt_util_getCurrentServerTime(); - return get_selection_data(env, selectionAtom, format, time_stamp); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_TextArea.c --- a/jdk/src/solaris/native/sun/awt/awt_TextArea.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1003 +0,0 @@ -/* - * Copyright 1995-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "canvas.h" -#include "java_awt_TextArea.h" -#include "java_awt_Cursor.h" -#include "java_awt_Component.h" -#include "java_awt_Color.h" -#include "java_awt_AWTEvent.h" -#include "java_awt_Font.h" -#include "java_awt_event_MouseWheelEvent.h" -#include "sun_awt_motif_MTextAreaPeer.h" -#include "sun_awt_motif_MComponentPeer.h" - -#include "awt_Component.h" -#include "awt_Cursor.h" -#include "awt_TextArea.h" - -#include -#include -#include "multi_font.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct CursorIDs cursorIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); -struct TextAreaIDs textAreaIDs; -struct MTextAreaPeerIDs mTextAreaPeerIDs; - -/* - * Class: java_awt_TextArea - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for TextArea.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_TextArea_initIDs - (JNIEnv *env, jclass cls) -{ - textAreaIDs.scrollbarVisibility = - (*env)->GetFieldID(env, cls, "scrollbarVisibility", "I"); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MTextAreaPeer.java to initialize the fieldIDs for fields that may - be accessed from C */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MTextAreaPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mTextAreaPeerIDs.firstChangeSkipped = - (*env)->GetFieldID(env, cls, "firstChangeSkipped", "Z"); -} - -/* - * client_data is MTextAreaPeer instance - */ -void -TextArea_valueChanged(Widget w, XtPointer client_data, XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jboolean skipped; - - skipped = (*env)->GetBooleanField(env, (jobject) client_data, - mTextAreaPeerIDs.firstChangeSkipped); - if (!(*env)->ExceptionOccurred(env)) { - if (skipped == JNI_FALSE) { - (*env)->SetBooleanField(env, (jobject) client_data, - mTextAreaPeerIDs.firstChangeSkipped, - JNI_TRUE); - } else { - JNU_CallMethodByName(env, NULL, (jobject) client_data, - "valueChanged", "()V"); - } - } - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -extern void Text_handlePaste(Widget w, XtPointer client_data, XEvent * event, - Boolean * cont); - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: pCreate - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_pCreate - (JNIEnv *env, jobject this, jobject parent) -{ - struct TextAreaData *tdata; -#define MAX_ARGC 30 - Arg args[MAX_ARGC]; - int32_t argc; - struct ComponentData *wdata; - jobject target; - Pixel bg; - int32_t sbVisibility; - Boolean wordWrap = False, hsb = False, vsb = False; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - char *nonEmptyText = "* will never be shown *"; - - AWT_LOCK(); - - adata = copyGraphicsConfigToPeer(env, this); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - tdata = ZALLOC(TextAreaData); - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,tdata); - - if (tdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - XtVaGetValues(wdata->widget, XmNbackground, &bg, NULL); - - sbVisibility = (*env)->GetIntField(env, target, - textAreaIDs.scrollbarVisibility); - switch (sbVisibility) { - case java_awt_TextArea_SCROLLBARS_NONE: - wordWrap = True; - hsb = False; - vsb = False; - break; - - case java_awt_TextArea_SCROLLBARS_VERTICAL_ONLY: - wordWrap = True; - hsb = False; - vsb = True; - break; - - case java_awt_TextArea_SCROLLBARS_HORIZONTAL_ONLY: - wordWrap = False; - hsb = True; - vsb = False; - break; - - default: - case java_awt_TextArea_SCROLLBARS_BOTH: - wordWrap = False; - hsb = True; - vsb = True; - break; - } - - argc = 0; - XtSetArg(args[argc], XmNrecomputeSize, False); - argc++; - XtSetArg(args[argc], XmNx, 0); - argc++; - XtSetArg(args[argc], XmNy, 0); - argc++; - XtSetArg(args[argc], XmNbackground, bg); - argc++; - XtSetArg(args[argc], XmNeditMode, XmMULTI_LINE_EDIT); - argc++; - XtSetArg(args[argc], XmNwordWrap, wordWrap); - argc++; - XtSetArg(args[argc], XmNscrollHorizontal, hsb); - argc++; - XtSetArg(args[argc], XmNscrollVertical, vsb); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 2); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 2); - argc++; - XtSetArg(args[argc], XmNuserData, (XtPointer) globalRef); - argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen)); - argc++; - XtSetArg(args[argc], XmNfontList, getMotifFontList()); - argc++; - - /* Initialize with a non-empty text, so the - * TextArea_valueChanged callback will be called - * even if the following conditions are true: - * 1. TextArea constructed with an empty initial text. - * 2. setText() with an empty argument is called - * immediately after the TextArea component is created. - * For more details please see #4028580. - */ - XtSetArg(args[argc], XmNvalue, nonEmptyText); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - tdata->txt = XmCreateScrolledText(wdata->widget, "textA", - args, argc); - tdata->comp.widget = XtParent(tdata->txt); - - /* Bug 4208972. Give the ScrolledWindow a minimum size. */ - XtVaSetValues(tdata->comp.widget, - XmNwidth, 1, - XmNheight, 1, NULL); - - XtSetMappedWhenManaged(tdata->comp.widget, False); - XtManageChild(tdata->txt); - XtManageChild(tdata->comp.widget); - - XtAddCallback(tdata->txt, - XmNvalueChangedCallback, - TextArea_valueChanged, - (XtPointer) globalRef); - - XtAddEventHandler(tdata->txt, FocusChangeMask, - True, awt_canvas_event_handler, globalRef); - - XtInsertEventHandler(tdata->txt, - KeyPressMask, - False, Text_handlePaste, (XtPointer) globalRef, - XtListHead); - - awt_addWidget(tdata->txt, tdata->comp.widget, globalRef, - java_awt_AWTEvent_KEY_EVENT_MASK | - java_awt_AWTEvent_MOUSE_EVENT_MASK | - java_awt_AWTEvent_MOUSE_MOTION_EVENT_MASK); - /* - * Fix for BugTraq ID 4349615. - * Unregister Motif drop site to prevent it from crash - * when dropping java objects. - */ - XmDropSiteUnregister(tdata->txt); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getExtraWidth - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextAreaPeer_getExtraWidth - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - Dimension spacing, shadowThickness, textMarginWidth, sbWidth; - Widget verticalScrollBar; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - XtVaGetValues(tdata->txt, XmNmarginWidth, &textMarginWidth, NULL); - XtVaGetValues(tdata->comp.widget, - XmNspacing, &spacing, - XmNverticalScrollBar, &verticalScrollBar, - NULL); - if (verticalScrollBar != NULL) { - /* Assumption: shadowThickness same for scrollbars and text area */ - XtVaGetValues(verticalScrollBar, - XmNwidth, &sbWidth, - XmNshadowThickness, &shadowThickness, - NULL); - } else { - sbWidth = 0; - shadowThickness = 0; - } - - AWT_UNLOCK(); - - return (jint) (sbWidth + spacing + 2 * textMarginWidth + 4 * shadowThickness); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getExtraHeight - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextAreaPeer_getExtraHeight - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - Dimension spacing, shadowThickness, textMarginHeight, sbHeight; - Dimension sbShadowThickness, highlightThickness, sbHighlightThickness; - int32_t height; - Widget horizontalScrollBar; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - - XtVaGetValues(tdata->txt, XmNmarginHeight, &textMarginHeight, - XmNshadowThickness, &shadowThickness, - XmNhighlightThickness, &highlightThickness, NULL); - height = 2 * (textMarginHeight + shadowThickness + highlightThickness); - - XtVaGetValues(tdata->comp.widget, - XmNspacing, &spacing, - XmNhorizontalScrollBar, &horizontalScrollBar, - NULL); - - if (horizontalScrollBar != NULL) { - XtVaGetValues(horizontalScrollBar, - XmNshadowThickness, &sbShadowThickness, - XmNhighlightThickness, &sbHighlightThickness, - XmNheight, &sbHeight, - NULL); - height += sbHeight + spacing - + 2 * (sbShadowThickness + sbHighlightThickness); - } - - AWT_UNLOCK(); - - return (jint)height; -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: setTextBackground - * Signature: (Ljava/awt/Color;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_setTextBackground - (JNIEnv *env, jobject this, jobject c) -{ - struct TextAreaData *tdata; - Pixel color; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL || JNU_IsNull(env, c)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - color = awtJNI_GetColor(env, c); - XtVaSetValues(tdata->txt, - XmNbackground, color, - NULL); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: pSetEditable - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_pSetEditable - (JNIEnv *env, jobject this, jboolean editable) -{ - struct TextAreaData *tdata; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(tdata->txt, - XmNeditable, (editable ? True : False), - XmNcursorPositionVisible, (editable ? True : False), - NULL); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: select - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_select - (JNIEnv *env, jobject this, jint start, jint end) -{ - struct TextAreaData *tdata; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextSetSelection(tdata->txt, (XmTextPosition) start, (XmTextPosition) end, 0); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getSelectionStart - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextAreaPeer_getSelectionStart - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - XmTextPosition start, end, pos; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (XmTextGetSelectionPosition(tdata->txt, &start, &end) && - (start != end)) { - pos = start; - } else { - pos = XmTextGetInsertionPosition(tdata->txt); - } - AWT_UNLOCK(); - - return (jint) pos; -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getSelectionEnd - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextAreaPeer_getSelectionEnd - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - XmTextPosition start, end, pos; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (XmTextGetSelectionPosition(tdata->txt, &start, &end) && - (start != end)) { - pos = end; - } else { - pos = XmTextGetInsertionPosition(tdata->txt); - } - AWT_UNLOCK(); - - return (jint) pos; -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: setText - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_setText - (JNIEnv *env, jobject this, jstring txt) -{ - struct TextAreaData *tdata; - char *cTxt; - jobject font = awtJNI_GetFont(env, this); - - if (JNU_IsNull(env, txt)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - cTxt = (char *) JNU_GetStringPlatformChars(env, txt, NULL); - - if (cTxt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(tdata->txt, XmNvalue, cTxt, NULL); - - if (cTxt != NULL) { - JNU_ReleaseStringPlatformChars(env, txt, cTxt); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getText - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_sun_awt_motif_MTextAreaPeer_getText - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - char *cTxt; - jstring rval; - jobject font = awtJNI_GetFont(env, this); - - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env,this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - cTxt = XmTextGetString(tdata->txt); - - rval = JNU_NewStringPlatform(env, (const char *) cTxt); - - XtFree(cTxt); - - AWT_UNLOCK(); - - return rval; -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: insert - * Signature: (Ljava/lang/String;I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_insert - (JNIEnv *env, jobject this, jstring txt, jint pos) -{ - struct TextAreaData *tdata; - char *cTxt; - jobject font = awtJNI_GetFont(env, this); - - if (JNU_IsNull(env, txt)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - cTxt = (char *) JNU_GetStringPlatformChars(env, txt, NULL); - - if (cTxt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextInsert(tdata->txt, (XmTextPosition) pos, cTxt); - - if (cTxt != NULL) { - JNU_ReleaseStringPlatformChars(env, txt, cTxt); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: replaceRange - * Signature: (Ljava/lang/String;II)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_replaceRange - (JNIEnv *env, jobject this, jstring txt, jint start, jint end) -{ - struct TextAreaData *tdata; - char *cTxt; - jobject font = awtJNI_GetFont(env, this); - - if (JNU_IsNull(env, txt)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - cTxt = (char *) JNU_GetStringPlatformChars(env, txt, NULL); - - if (cTxt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextReplace(tdata->txt, - (XmTextPosition) start, - (XmTextPosition) end, - cTxt); - - if (cTxt != NULL) { - JNU_ReleaseStringPlatformChars(env, txt, cTxt); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: setFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_setFont - (JNIEnv *env, jobject this, jobject f) -{ - struct TextAreaData *tdata; - struct FontData *fdata; - XmFontList fontlist; - char *err; - XmFontListEntry fontentry; - - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - AWT_LOCK(); - - fdata = awtJNI_GetFontData(env, f, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(env, err); - AWT_UNLOCK(); - return; - } - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (awtJNI_IsMultiFont(env, f)) { - if (fdata->xfs == NULL) { - fdata->xfs = awtJNI_MakeFontSet(env, f); - } - if (fdata->xfs != NULL) { - fontentry = XmFontListEntryCreate("labelFont", - XmFONT_IS_FONTSET, - (XtPointer) (fdata->xfs)); - fontlist = XmFontListAppendEntry(NULL, fontentry); - /* - * Some versions of motif have a bug in - * XmFontListEntryFree() which causes it to free more than it - * should. Use XtFree() instead. See O'Reilly's - * Motif Reference Manual for more information. - */ - XmFontListEntryFree(&fontentry); - - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - - if (fontlist != NULL) { - Dimension textw, texth; - Dimension w, h; - - XtVaGetValues(tdata->txt, - XmNwidth, &textw, - XmNheight, &texth, - NULL); - XtVaGetValues(tdata->comp.widget, - XmNwidth, &w, - XmNheight, &h, - NULL); - - /* Must set width/height when we set the font, else - * Motif resets the text to a single row. - */ - XtVaSetValues(tdata->txt, - XmNfontList, fontlist, - XmNwidth, textw, - XmNheight, texth, - NULL); - XtVaSetValues(tdata->comp.widget, - XmNwidth, w, - XmNheight, h, - NULL); - - XmFontListFree(fontlist); - } else { - JNU_ThrowNullPointerException(env, "NullPointerException"); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: setCaretPosition - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_setCaretPosition - (JNIEnv *env, jobject this, jint pos) -{ - struct TextAreaData *tdata; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextSetInsertionPosition(tdata->txt, (XmTextPosition) pos); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: getCaretPosition - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextAreaPeer_getCaretPosition - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - XmTextPosition pos; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - pos = XmTextGetInsertionPosition(tdata->txt); - - AWT_UNLOCK(); - - return (jint) pos; -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: pShow - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_pShow2 - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - - AWT_LOCK(); - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awt_util_show(tdata->comp.widget); - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: pMakeCursorVisible - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_pMakeCursorVisible - (JNIEnv *env, jobject this) -{ - struct TextAreaData *tdata; - - AWT_LOCK(); - tdata = (struct TextAreaData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: pSetCursor - * Signature: (L/java/awt/Cursor;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_pSetCursor - (JNIEnv *env, jobject this, jobject cursor) -{ - Cursor xcursor; - struct TextAreaData *tdata; - - AWT_LOCK(); - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL || JNU_IsNull(env, cursor)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - awt_util_setCursor(tdata->txt, getCursor(env, cursor)); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextAreaPeer - * Method: nativeHandleMouseWheel - * Signature: (III)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextAreaPeer_nativeHandleMouseWheel - (JNIEnv *env, jobject this, jint scrollType, jint scrollAmt, jint wheelAmt) -{ - struct TextAreaData *tdata; - Widget text = NULL; - Widget scroll = NULL; - - AWT_LOCK(); - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - // get the Text widget - text = tdata->txt; - if (text == NULL) { - AWT_UNLOCK(); - return; - } - - // get the ScrolledWindow - scroll = XtParent(text); - if (scroll == NULL) { - AWT_UNLOCK(); - return; - } - - awt_util_do_wheel_scroll(scroll, scrollType, scrollAmt, wheelAmt); - AWT_UNLOCK(); -} - - - -/* To be fully implemented in a future release - * - * Class: sun_awt_windows_MTextAreaPeer - * Method: getIndexAtPoint - * Signature: (II)I - * -JNIEXPORT jint JNICALL -Java_sun_awt_motif_MTextAreaPeer_getIndexAtPoint(JNIEnv *env, jobject self, - jint x, jint y) -{ - struct TextAreaData *tdata; - XmTextPosition pos; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env,self,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return -1; - } - pos = XmTextXYToPos(tdata->txt, x, y); - AWT_UNLOCK(); - - return (jint) pos; -} -*/ - -/* To be fully implemented in a future release - * - * Class: sun_awt_windows_MTextAreaPeer - * Method: getCharacterBounds - * Signature: (I)Ljava/awt/Rectangle; - * -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MTextAreaPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i) -{ -#define Text_FontAscent(tfg) (((XmTextWidget)(tfg)) -> \ - text.output->data->font_ascent) -#define Text_FontDescent(tfg) (((XmTextWidget)(tfg)) -> \ - text.output->data->font_descent) - - struct TextAreaData *tdata; - jobject rect=NULL; - Position x=0, y=0; - Position next_x=0, next_y=0; - int32_t w=0, h=0; - - AWT_LOCK(); - - tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env,self,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->txt == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return (jobject) NULL; - } - - XmTextPosToXY(tdata->txt, i, &x, &y); - y -= Text_FontAscent(tdata->txt); - XmTextPosToXY(tdata->txt, i+1, &next_x, &next_y); - w = next_x - x; - h = Text_FontAscent(tdata->txt) + Text_FontDescent(tdata->txt); - - AWT_UNLOCK(); - - if (w>0) { - jclass clazz; - jmethodID mid; - - clazz = (*env)->FindClass(env, "java/awt/Rectangle"); - mid = (*env)->GetMethodID(env, clazz, "", "(IIII)V"); - if (mid != NULL) { - rect = (*env)->NewObject(env, clazz, mid, x, y, w, h); - if ((*env)->ExceptionOccurred(env)) { - return (jobject) NULL; - } - } - } - return rect; -} -*/ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_TextArea.h --- a/jdk/src/solaris/native/sun/awt/awt_TextArea.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright 2003 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. - */ - -#include "jni_util.h" - -/* fieldIDs for TextArea fields that may be accessed from C */ -static struct TextAreaIDs { - jfieldID scrollbarVisibility; -}; - -/* fieldIDs for MTextAreaPeer fields that may be accessed from C */ -struct MTextAreaPeerIDs { - jfieldID firstChangeSkipped; -}; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_TextField.c --- a/jdk/src/solaris/native/sun/awt/awt_TextField.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,989 +0,0 @@ -/* - * Copyright 1995-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include - -#include "awt_p.h" -#include "java_awt_TextField.h" -#include "java_awt_Color.h" -#include "java_awt_AWTEvent.h" -#include "java_awt_Font.h" -#include "java_awt_Canvas.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MCanvasPeer.h" -#include "sun_awt_motif_MTextFieldPeer.h" - -#include "awt_Component.h" -#include "awt_TextField.h" - -#include "multi_font.h" -#include -#include -#include -#include /* Motif TextField private header. */ - - -#define ECHO_BUFFER_LEN 1024 - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern AwtGraphicsConfigDataPtr - copyGraphicsConfigToPeer(JNIEnv *env, jobject this); -struct TextFieldIDs textFieldIDs; -struct MTextFieldPeerIDs mTextFieldPeerIDs; - -/* - * Class: java_awt_TextField - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for TextField.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_java_awt_TextField_initIDs - (JNIEnv *env, jclass cls) -{ - textFieldIDs.echoChar = - (*env)->GetFieldID(env, cls, "echoChar", "C"); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for - MTextFieldPeer.java to initialize the fieldIDs for fields that may - be accessed from C */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MTextFieldPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mTextFieldPeerIDs.firstChangeSkipped = - (*env)->GetFieldID(env, cls, "firstChangeSkipped", "Z"); -} - -static void -echoChar(Widget text_w, XtPointer unused, XmTextVerifyCallbackStruct * cbs) -{ - size_t len; - int32_t c; - char *val; - struct DPos *dp; - int32_t ret; - jobject globalRef; - int32_t i, numbytes; - - struct TextFieldData *tdata; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - /* - * Get the echoContextID from the globalRef which is stored in - * the XmNuserData resource for the widget. - */ - XtVaGetValues(text_w,XmNuserData,&globalRef,NULL); - - tdata = (struct TextFieldData *) - (*env)->GetLongField(env,globalRef,mComponentPeerIDs.pData); - - ret = XFindContext(XtDisplay(text_w), (XID)text_w, tdata->echoContextID, - (XPointer *)&dp); - if ((ret != 0) || (dp == NULL)) { - /* no context found or DPos is NULL - shouldn't happen */ - return; - } - - c = dp->echoC; - val = (char *) (dp->data); - - len = strlen(val); - if (cbs->text->ptr == NULL) { - if (cbs->text->length == 0 && cbs->startPos == 0) { - val[0] = '\0'; - return; - } else if (cbs->startPos == (len - 1)) { - /* handle deletion */ - cbs->endPos = strlen(val); - val[cbs->startPos] = '\0'; - return; - } else { - /* disable deletes anywhere but at the end */ - cbs->doit = False; - return; - } - } - if (cbs->startPos != len) { - /* disable "paste" or inserts into the middle */ - cbs->doit = False; - return; - } - /* append the value typed in */ - if ((cbs->endPos + cbs->text->length) > ECHO_BUFFER_LEN) { - val = realloc(val, cbs->endPos + cbs->text->length + 10); - } - strncat(val, cbs->text->ptr, cbs->text->length); - val[cbs->endPos + cbs->text->length] = '\0'; - - /* modify the output to be the echo character */ - for (len = 0, i = 0; len < cbs->text->length; i++) { - /* Write one echo character for each multibyte character. */ - numbytes = mblen(cbs->text->ptr + len, cbs->text->length - len); - cbs->text->ptr[i] = (char) c; - len += numbytes; - } - cbs->text->length = i; -} - -/* - * Event handler used by both TextField/TextArea to correctly process - * cut/copy/paste keys such that interaction with our own - * clipboard mechanism will work properly. - * - * client_data is MTextFieldPeer instance - */ -void -Text_handlePaste(Widget w, XtPointer client_data, XEvent * event, Boolean * cont) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - KeySym keysym; - Modifiers mods; - - /* Any event handlers which take peer instance pointers as - * client_data should check to ensure the widget has not been - * marked as destroyed as a result of a dispose() call on the peer - * (which can result in the peer instance pointer already haven - * been gc'd by the time this event is processed) - */ - if (event->type != KeyPress || w->core.being_destroyed) { - return; - } - - XtTranslateKeycode(event->xkey.display, (KeyCode) event->xkey.keycode, - event->xkey.state, &mods, &keysym); - - /* Should be a temporary fix for 4052132 if a cleaner fix is found later */ - if ((event->xkey.state & ControlMask) && (keysym == 'v' || keysym == 'V')) - keysym = osfXK_Paste; - if ((event->xkey.state & ShiftMask) && (keysym == osfXK_Insert)) - keysym = osfXK_Paste; - - switch (keysym) { - case osfXK_Paste: - /* If we own the selection, then paste the data directly */ - if (awtJNI_isSelectionOwner(env, "CLIPBOARD")) { - JNU_CallMethodByName(env, NULL, (jobject) client_data, - "pasteFromClipboard", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - *cont = FALSE; - } - break; - - case osfXK_Cut: - case osfXK_Copy: - /* For some reason if we own the selection, our loseSelection - * callback is not automatically called on cut/paste from - * text widgets. - */ - if (awtJNI_isSelectionOwner(env, "CLIPBOARD")) { - awtJNI_notifySelectionLost(env, "CLIPBOARD"); - } - break; - default: - break; - } -} - -/* - * client_data is MTextFieldPeer instance - */ -void -TextField_valueChanged(Widget w, XtPointer client_data, XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jboolean skipped; - - skipped = (*env)->GetBooleanField(env, (jobject) client_data, - mTextFieldPeerIDs.firstChangeSkipped); - if (!(*env)->ExceptionOccurred(env)) { - if (skipped == JNI_FALSE) { - (*env)->SetBooleanField(env, (jobject) client_data, - mTextFieldPeerIDs.firstChangeSkipped, - JNI_TRUE); - } else { - JNU_CallMethodByName(env, NULL, (jobject) client_data, - "valueChanged", "()V"); - } - } - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -/* - * client_data is MTextFieldPeer instance - */ -static void -TextField_action(Widget w, XtPointer client_data, XmAnyCallbackStruct * s) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - ConvertEventTimeAndModifiers converted; - - awt_util_convertEventTimeAndModifiers(s->event, &converted); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, "action", "(JI)V", - converted.when, converted.modifiers); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: pCreate - * Signature: (Lsun/awt/motif/MComponentPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_pCreate - (JNIEnv *env, jobject this, jobject parent) -{ - struct ComponentData *wdata; - struct TextFieldData *tdata; - - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - - adata = copyGraphicsConfigToPeer(env, this); - - if (JNU_IsNull(env, parent)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - wdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - tdata = ZALLOC(TextFieldData); - if (tdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,tdata); - - tdata->comp.widget = XtVaCreateManagedWidget("textfield", - xmTextFieldWidgetClass, - wdata->widget, - XmNrecomputeSize, False, - XmNhighlightThickness, 1, - XmNshadowThickness, 2, - XmNuserData, (XtPointer) globalRef, - XmNscreen, - ScreenOfDisplay(awt_display, - adata->awt_visInfo.screen), - XmNfontList, getMotifFontList(), - NULL); - tdata->echoContextIDInit = FALSE; - - XtSetMappedWhenManaged(tdata->comp.widget, False); - XtAddCallback(tdata->comp.widget, - XmNactivateCallback, - (XtCallbackProc) TextField_action, - (XtPointer) globalRef); - XtAddCallback(tdata->comp.widget, - XmNvalueChangedCallback, - (XtCallbackProc) TextField_valueChanged, - (XtPointer) globalRef); - XtInsertEventHandler(tdata->comp.widget, - KeyPressMask, - False, Text_handlePaste, (XtPointer) globalRef, - XtListHead); - /* - * Fix for BugTraq ID 4349615. - * Unregister Motif drop site to prevent it from crash - * when dropping java objects. - */ - XmDropSiteUnregister(tdata->comp.widget); - - AWT_UNLOCK(); -} - -/* - * Class sun_awt_motif_MTextFieldPeer - * Method: pSetEditable - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_pSetEditable - (JNIEnv *env, jobject this, jboolean editable) -{ - struct TextFieldData *tdata; - - AWT_LOCK(); - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(tdata->comp.widget, - XmNeditable, (editable ? True : False), - XmNcursorPositionVisible, (editable ? True : False), - NULL); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: select - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_select - (JNIEnv *env, jobject this, jint start, jint end) -{ - struct TextFieldData *tdata; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextSetSelection(tdata->comp.widget, (XmTextPosition) start, (XmTextPosition) end, 0); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: getSelectionStart - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextFieldPeer_getSelectionStart - (JNIEnv *env, jobject this) -{ - struct TextFieldData *tdata; - XmTextPosition start, end, pos; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (XmTextGetSelectionPosition(tdata->comp.widget, &start, &end) && - (start != end)) { - pos = start; - } else { - pos = XmTextGetInsertionPosition(tdata->comp.widget); - } - AWT_UNLOCK(); - - return (jint) pos; -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: getSelectionEnd - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextFieldPeer_getSelectionEnd - (JNIEnv *env, jobject this) -{ - struct TextFieldData *tdata; - XmTextPosition start, end, pos; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - if (XmTextGetSelectionPosition(tdata->comp.widget, &start, &end) && - (start != end)) { - pos = end; - } else { - pos = XmTextGetInsertionPosition(tdata->comp.widget); - } - AWT_UNLOCK(); - - return (jint) pos; -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: setText - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_setText - (JNIEnv *env, jobject this, jstring l) -{ - struct TextFieldData *tdata; - char *cl; - jobject target; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (JNU_IsNull(env, l)) { - cl = ""; - } else { - /* - * Note: Motif TextField widgets do not support multi-font - * compound strings. - */ - cl = (char *) JNU_GetStringPlatformChars(env, l, NULL); - } - - /* Fix for bug 4084454 : setText appears in clear */ - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - if ((*env)->GetCharField(env, target, textFieldIDs.echoChar) != 0) { - XtVaSetValues(tdata->comp.widget, - XmNvalue, "", NULL); - XmTextFieldInsert(tdata->comp.widget,0,cl); - XmTextSetInsertionPosition(tdata->comp.widget, - (XmTextPosition) strlen(cl)); - } - else { - XtVaSetValues(tdata->comp.widget, - XmNvalue, cl, - NULL); - } - /* - * Fix for BugTraq Id 4185654 - TextField.setText() incorrect justification - * Comment out the next line. - */ - /* XmTextSetInsertionPosition(tdata->comp.widget, - * (XmTextPosition) strlen(cl)); - */ - - if (cl != NULL && cl != "") { - JNU_ReleaseStringPlatformChars(env, l, cl); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: insertReplaceText - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_insertReplaceText - (JNIEnv *env, jobject this, jstring l) -{ - struct TextFieldData *tdata; - char *cl; - XmTextPosition start, end; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - if (JNU_IsNull(env, l)) { - cl = ""; - } else { - /* - * Note: Motif TextField widgets do not support multi-font - * compound strings. - */ - cl = (char *) JNU_GetStringPlatformChars(env, l, NULL); - } - - if (!XmTextGetSelectionPosition(tdata->comp.widget, &start, &end)) { - start = end = XmTextGetInsertionPosition(tdata->comp.widget); - } - XmTextReplace(tdata->comp.widget, start, end, cl); - - if (cl != NULL && cl != "") { - JNU_ReleaseStringPlatformChars(env, l, cl); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: preDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_preDispose - (JNIEnv *env, jobject this) -{ - struct TextFieldData *tdata; - struct DPos *dp; - jobject target; - int32_t ret; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if ((*env)->GetCharField(env, target, textFieldIDs.echoChar) != 0) { - ret = XFindContext(XtDisplay(tdata->comp.widget), (XID)(tdata->comp.widget), - tdata->echoContextID, (XPointer *)&dp); - if ((ret == 0) && dp != NULL) { - - /* Remove the X context associated with this textfield's - * echo character. BugId #4225734 - */ - XDeleteContext(XtDisplay(tdata->comp.widget), - (XID)(tdata->comp.widget), - tdata->echoContextID); - - tdata->echoContextIDInit = FALSE; - - /* Free up the space allocated for the echo character data. */ - if (dp->data) { - free(dp->data); - } - free(dp); - } - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: getText - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_sun_awt_motif_MTextFieldPeer_getText - (JNIEnv *env, jobject this) -{ - struct TextFieldData *tdata; - char *val; - struct DPos *dp; - jobject target; - int32_t ret; - jstring returnVal; - - AWT_LOCK(); - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if ((*env)->GetCharField(env, target, textFieldIDs.echoChar) != 0) { - ret = XFindContext(XtDisplay(tdata->comp.widget), (XID)tdata->comp.widget, - tdata->echoContextID, (XPointer *)&dp); - if ((ret == 0) && (dp != NULL)) { - val = (char *)(dp->data); - } else { - val = ""; - } - } else { - XtVaGetValues(tdata->comp.widget, XmNvalue, &val, NULL); - } - AWT_UNLOCK(); - - returnVal = JNU_NewStringPlatform(env, (const char *) val); - if ((*env)->GetCharField(env, target, textFieldIDs.echoChar) == 0) { - free(val); - } - return returnVal; -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: setEchoChar - * Signature: (C)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_setEchoChar - (JNIEnv *env, jobject this, jchar c) -{ - char *val; - char *cval; - struct TextFieldData *tdata; - struct DPos *dp; - int32_t i; - size_t len; - int32_t ret; - - AWT_LOCK(); - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - XtVaGetValues(tdata->comp.widget, - XmNvalue, &cval, - NULL); - - DASSERT(c != 0 || tdata->echoContextIDInit); - - if (!tdata->echoContextIDInit) { - tdata->echoContextID = XUniqueContext(); - tdata->echoContextIDInit = TRUE; - } - ret = XFindContext(XtDisplay(tdata->comp.widget), (XID)(tdata->comp.widget), - tdata->echoContextID, (XPointer *)&dp); - /* - * Fix for BugTraq ID 4307281. - * Special case for setting echo char to 0: - * - remove the callback and X context associated with echo character; - * - restore the original text. - */ - if (c == 0) { - XtRemoveCallback(tdata->comp.widget, XmNmodifyVerifyCallback, - (XtCallbackProc) echoChar, NULL); - if (ret == 0 && dp != NULL) { - - /* Remove the X context associated with echo character. */ - XDeleteContext(XtDisplay(tdata->comp.widget), - (XID)(tdata->comp.widget), - tdata->echoContextID); - - tdata->echoContextIDInit = FALSE; - - /* Restore the original text. */ - if (dp->data != NULL) { - val = (char *)(dp->data); - } else { - val = ""; - } - XtVaSetValues(tdata->comp.widget, - XmNvalue, val, - NULL); - - /* Free up the space allocated for the echo character data. */ - if (dp->data) { - free(dp->data); - } - free(dp); - } - AWT_UNLOCK(); - return; - } - if (ret != 0) { - dp = NULL; - } - - if (dp != NULL) { - /* Fix bug 4124697: cannot change setEchoChar twice on Motif */ - XtRemoveCallback(tdata->comp.widget, XmNmodifyVerifyCallback, - (XtCallbackProc) echoChar, NULL); - } else { - if ((int32_t) strlen(cval) > ECHO_BUFFER_LEN) { - val = (char *) malloc(strlen(cval) + 1); - } else { - val = (char *) malloc(ECHO_BUFFER_LEN + 1); - } - if (val == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - if (cval != NULL) { - strcpy(val, cval); - } else { - *val = '\0'; - } - dp = (struct DPos *) malloc(sizeof(struct DPos)); - - dp->x = -1; - dp->data = (void *) val; - } - - dp->echoC = c; - len = strlen(cval); - for (i = 0; i < len; i++) { - cval[i] = (char) (c); - } - XtVaSetValues(tdata->comp.widget, - XmNvalue, cval, - NULL); - - ret = XSaveContext(XtDisplay(tdata->comp.widget), (XID)tdata->comp.widget, - tdata->echoContextID, (XPointer)dp); - if (ret == 0) { - XtAddCallback(tdata->comp.widget, XmNmodifyVerifyCallback, - (XtCallbackProc) echoChar, NULL); - } - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: setFont - * Signature: (Ljava/awt/Font;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_setFont - (JNIEnv *env, jobject this, jobject f) -{ - struct TextFieldData *tdata; - struct FontData *fdata; - XmFontListEntry fontentry; - XmFontList fontlist; - char *err; - - AWT_LOCK(); - if (JNU_IsNull(env, f)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - fdata = awtJNI_GetFontData(env, f, &err); - if (fdata == NULL) { - JNU_ThrowInternalError(env, err); - AWT_UNLOCK(); - return; - } - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (awtJNI_IsMultiFont(env, f)) { - if (fdata->xfs == NULL) { - fdata->xfs = awtJNI_MakeFontSet(env, f); - } - if (fdata->xfs != NULL) { - fontentry = XmFontListEntryCreate("labelFont", - XmFONT_IS_FONTSET, - (XtPointer) (fdata->xfs)); - fontlist = XmFontListAppendEntry(NULL, fontentry); - /* - * Some versions of motif have a bug in - * XmFontListEntryFree() which causes it to free more than it - * should. Use XtFree() instead. See O'Reilly's - * Motif Reference Manual for more information. - */ - XmFontListEntryFree(&fontentry); - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - } else { - fontlist = XmFontListCreate(fdata->xfont, "labelFont"); - } - - if (fontlist != NULL) { - XtVaSetValues(tdata->comp.widget, XmNfontList, fontlist, NULL); - XmFontListFree(fontlist); - } else { - JNU_ThrowNullPointerException(env, "NullPointerException"); - } - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: setCaretPosition - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MTextFieldPeer_setCaretPosition - (JNIEnv *env, jobject this, jint pos) -{ - struct TextFieldData *tdata; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XmTextSetInsertionPosition(tdata->comp.widget, (XmTextPosition) pos); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MTextFieldPeer - * Method: getCaretPosition - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_awt_motif_MTextFieldPeer_getCaretPosition - (JNIEnv *env, jobject this) -{ - struct TextFieldData *tdata; - XmTextPosition pos; - - AWT_LOCK(); - - tdata = (struct TextFieldData *) - JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return 0; - } - pos = XmTextGetInsertionPosition(tdata->comp.widget); - AWT_UNLOCK(); - - return (jint) pos; -} - - -/* To be fully implemented in a future release - * - * Class: sun_awt_windows_MTextFieldPeer - * Method: getIndexAtPoint - * Signature: (Ljava/awt/Point;)I - * -JNIEXPORT jint JNICALL -Java_sun_awt_motif_MTextFieldPeer_getIndexAtPoint(JNIEnv *env, jobject self, - jint x, jint y) -{ - struct ComponentData *tdata; - XmTextPosition pos; - - AWT_LOCK(); - - tdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,self,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return -1; - } - pos = XmTextFieldXYToPos(tdata->widget, x, y); - AWT_UNLOCK(); - - return (jint) pos; -} -*/ - -/* To be fully implemented in a future release - * - * Class: sun_awt_windows_MTextFieldPeer - * Method: getCharacterBounds - * Signature: (I)Ljava/awt/Rectangle; - * -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MTextFieldPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i) -{ -#define TextF_FontAscent(tfg) (((XmTextFieldWidget)(tfg)) -> \ - text.font_ascent) -#define TextF_FontDescent(tfg) (((XmTextFieldWidget)(tfg)) -> \ - text.font_descent) - - struct ComponentData *tdata; - jobject rect=NULL; - Position x=0, y=0; - Position next_x=0, next_y=0; - int32_t w=0, h=0; - - AWT_LOCK(); - - tdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env,self,mComponentPeerIDs.pData); - - if (tdata == NULL || tdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return (jobject) NULL; - } - - XmTextFieldPosToXY(tdata->widget, i, &x, &y); - y -= TextF_FontAscent(tdata->widget); - XmTextFieldPosToXY(tdata->widget, i+1, &next_x, &next_y); - w = next_x - x; - h = TextF_FontAscent(tdata->widget) + TextF_FontDescent(tdata->widget); - - AWT_UNLOCK(); - - if (w>0) { - jclass clazz; - jmethodID mid; - - clazz = (*env)->FindClass(env, "java/awt/Rectangle"); - mid = (*env)->GetMethodID(env, clazz, "", "(IIII)V"); - if (mid != NULL) { - rect = (*env)->NewObject(env, clazz, mid, x, y, w, h); - if ((*env)->ExceptionOccurred(env)) { - return NULL; - } - } - } - return rect; -} -*/ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_TextField.h --- a/jdk/src/solaris/native/sun/awt/awt_TextField.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright 2003 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. - */ - -#include "jni_util.h" - -/* fieldIDs for TextField fields that may be accessed from C */ -static struct TextFieldIDs { - jfieldID echoChar; -}; - -/* fieldIDs for MTextFieldPeer fields that may be accessed from C */ -struct MTextFieldPeerIDs { - jfieldID firstChangeSkipped; -}; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_TopLevel.c --- a/jdk/src/solaris/native/sun/awt/awt_TopLevel.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5095 +0,0 @@ -/* - * Copyright 1999-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include "VDrawingArea.h" - -#ifdef DEBUG -# include -#endif - -#include -#include - -/* JNI headers */ -#include "java_awt_Color.h" -#include "java_awt_Component.h" -#include "java_awt_Dialog.h" -#include "java_awt_Font.h" -#include "java_awt_Frame.h" -#include "java_awt_Image.h" -#include "java_awt_Insets.h" -#include "java_awt_Insets.h" -#include "java_awt_MenuBar.h" -#include "java_awt_Window.h" -#include "java_awt_event_FocusEvent.h" -#include "java_awt_TrayIcon.h" -#include "sun_awt_EmbeddedFrame.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MDialogPeer.h" -#include "sun_awt_motif_MEmbeddedFramePeer.h" -#include "sun_awt_motif_MFramePeer.h" -#include "sun_awt_motif_MMenuBarPeer.h" -#include "sun_awt_motif_MWindowPeer.h" - -/* JNI field and method ids */ -#include "awt_Component.h" -#include "awt_GraphicsEnv.h" -#include "awt_Insets.h" -#include "awt_MenuBar.h" -#include "awt_Window.h" -#include "awt_KeyboardFocusManager.h" -#include "awt_MToolkit.h" -#include "awt_Plugin.h" - -#include "color.h" -#include "canvas.h" -#include "awt_util.h" -#include "img_util.h" -#include "awt_wm.h" -#include "awt_util.h" -#include "awt_xembed.h" - - -#ifdef __linux__ -void adjustStatusWindow(Widget shell); -#endif -/* For the moment only InputMethodWindow is taking advantage of -** the posibility for different decor styles -** values could be passed are the MWM_DECOR defines -** for the moment we are full on or full off. -*/ -#define AWT_NO_DECOR 0x0 -#define AWT_FULL_DECOR MWM_DECOR_ALL - -static void reshape(JNIEnv *env, jobject this, struct FrameData *wdata, - jint x, jint y, jint w, jint h, Boolean setXY); -Widget findTopLevelByShell(Widget widget); - -extern EmbeddedFrame *theEmbeddedFrameList; -extern struct ComponentIDs componentIDs; -extern struct MMenuBarPeerIDs mMenuBarPeerIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; -struct WindowIDs windowIDs; -struct MWindowPeerIDs mWindowPeerIDs; -extern struct InsetsIDs insetsIDs; -extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; -extern struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; -extern struct X11GraphicsDeviceIDs x11GraphicsDeviceIDs; - -#ifndef NOMODALFIX -extern Boolean awt_isModal(); -extern Boolean awt_isWidgetModal(Widget w); -extern void awt_shellPoppedUp(Widget shell, XtPointer c, XtPointer d); -extern void awt_shellPoppedDown(Widget shell, XtPointer c, XtPointer d); -#endif //NOMODALFIX - -static jclass inputMethodWindowClass = NULL; - -static int32_t globalTopGuess = 0; -static int32_t globalLeftGuess = 0; -static int32_t globalBottomGuess = 0; -static int32_t globalRightGuess = 0; - - -// Atom used for otlogenniy top-level disposal -static Atom _XA_JAVA_DISPOSE_PROPERTY_ATOM = 0; - -/* - * Fix for bug 4141361 - * - * We keep a linked list of the FrameData information for - * every top level window. - */ -struct FrameDataList { - struct FrameData* wdata; - struct FrameDataList* next; -}; - -static struct FrameDataList* allTopLevel = NULL; - -extern void checkNewXineramaScreen(JNIEnv* env, jobject peer, - struct FrameData* wdata, - int32_t newX, int32_t newY, - int32_t newWidth, int32_t newHeight); - -// Returns false if this Window is non-focusable -// or its nearest decorated parent is non-focusable. -Boolean isFocusableWindowByPeer(JNIEnv * env, jobject peer) { - jobject target, decoratedParent; - struct FrameData *wdata; - Boolean focusable; - - wdata = (struct FrameData *)JNU_GetLongFieldAsPtr(env, peer, mComponentPeerIDs.pData); - DASSERT(wdata != NULL); - - target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - DASSERT(target != NULL); - - decoratedParent = getOwningFrameOrDialog(target, env); - (*env)->DeleteLocalRef(env, target); - - if (decoratedParent == NULL) { - return wdata->isFocusableWindow; - } else { - jobject parentPeer = (*env)->GetObjectField(env, decoratedParent, componentIDs.peer); - DASSERT(parentPeer != NULL); - focusable = wdata->isFocusableWindow && isFocusableWindowByPeer(env, parentPeer); - - (*env)->DeleteLocalRef(env, decoratedParent); - (*env)->DeleteLocalRef(env, parentPeer); - } - return focusable; -} - -// Returns false if this shell's Java Window is non-focusable -// or its nearest decorated parent is non-focusable. -// Returns true otherwise or if any of parameters is NULL -Boolean isFocusableWindowByShell(JNIEnv* env, Widget shell) { - Widget toplevel; - jobject peer; - Boolean focusable; - - DASSERT(shell != NULL && XtIsShell(shell)); - if (shell == NULL) return True; - if (!XtIsShell(shell)) return True; - - toplevel = findTopLevelByShell(shell); - if (toplevel == NULL) { - return True; - } - peer = findPeer(&toplevel); - DASSERT(peer != NULL); - - if (env == NULL) { - env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - } - return isFocusableWindowByPeer(env, peer); -} - - -// Returns Shell widget - the parent of this child -Widget getShellWidget(Widget child) { - - while (child != NULL && !XtIsShell(child)) { - child = XtParent(child); - } - return child; -} - -// Returns false if the parent shell of this widget is non-focusable Java Window. -// Returns false otherwise. -// Doesn't accept NULL parameters. -Boolean isFocusableComponentTopLevelByWidget(JNIEnv * env, Widget child) { - Widget shell = NULL; - shell = getShellWidget(child); - DASSERT(shell); - return isFocusableWindowByShell(env, shell); -} - - -/* - * Add a new element into the top level window list - */ -void addTopLevel(struct FrameData* wdata) { - struct FrameDataList* newNode; - newNode = (struct FrameDataList*) - malloc(sizeof(struct FrameDataList)); - newNode->wdata = wdata; - newNode->next = allTopLevel; - allTopLevel = newNode; -} - -/* - * Remove an element from the top level window list - * (recursive) - */ -Boolean removeTopLevelR(struct FrameDataList** ptr, - struct FrameData* wdata) { - struct FrameDataList* node = *ptr; - if (node == NULL) { - return False; - } - if (node->wdata == wdata) { - *ptr = node->next; - free(node); - return True; - } - return removeTopLevelR(&(node->next), wdata); -} - -Boolean removeTopLevel(struct FrameData* wdata) { - return removeTopLevelR(&allTopLevel, wdata); -} - -/* - * Return the Widget ID of the top level window underneath the - * mouse pointer. - */ -Widget awt_GetWidgetAtPointer() { - struct FrameDataList* ptr = allTopLevel; - Window rootWindow, childWindow, mainWindow; - int32_t xw, yw, xr, yr; - uint32_t keys; - while (ptr != NULL) { - mainWindow = XtWindow(ptr->wdata->mainWindow); - XQueryPointer(awt_display, mainWindow, - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &keys); - if (childWindow != None) { - return ptr->wdata->winData.comp.widget; - } - ptr = ptr->next; - } - return NULL; -} - -Widget findFocusProxy(Widget widget) { - struct FrameDataList* ptr = allTopLevel; - for (ptr = allTopLevel; ptr != NULL; ptr = ptr->next) { - if (ptr->wdata->winData.comp.widget == widget) { - return ptr->wdata->focusProxy; - } - } - return NULL; -} - -Widget findTopLevelByShell(Widget widget) { - struct FrameDataList* ptr; - for (ptr = allTopLevel; ptr != NULL; ptr = ptr->next) { - if (ptr->wdata->winData.shell == widget) { - return ptr->wdata->winData.comp.widget; - } - } - return NULL; -} - -void -awt_Frame_guessInsets(struct FrameData *wdata) -{ - if (wdata->decor == AWT_NO_DECOR ) { - wdata->top = wdata->topGuess = 0; - wdata->left = wdata->leftGuess = 0; - wdata->bottom = wdata->bottomGuess = 0; - wdata->right = wdata->rightGuess = 0; - return; - } - - if (globalTopGuess == 0) { - char *insets_env; - - if (wdata->top >= 0) { - /* insets were set on wdata by System Properties */ - globalTopGuess = wdata->top; - globalLeftGuess = wdata->left; - globalBottomGuess = wdata->bottom; - globalRightGuess = wdata->right; - } - else switch (awt_wm_getRunningWM()) { - case ENLIGHTEN_WM: - globalTopGuess = 19; - globalLeftGuess = 4; - globalBottomGuess = 4; - globalRightGuess = 4; - break; - - case CDE_WM: - globalTopGuess = 28; - globalLeftGuess = 6; - globalBottomGuess = 6; - globalRightGuess = 6; - break; - - case MOTIF_WM: - case OPENLOOK_WM: - default: - globalTopGuess = 25; - globalLeftGuess = 5; - globalBottomGuess = 5; - globalRightGuess = 5; - break; - } - - if ((insets_env = getenv("AWT_INSETS")) != NULL) { - int guess = atoi(insets_env); - globalTopGuess = (guess & 0xff00) >> 8; - globalLeftGuess = guess & 0x00ff; - globalBottomGuess = wdata->leftGuess; - globalRightGuess = wdata->leftGuess; - } - - /* don't allow bizarly large insets */ - if ((globalTopGuess > 64) || (globalTopGuess < 0)) - globalTopGuess = 28; - if ((globalLeftGuess > 32) || (globalLeftGuess < 0)) - globalLeftGuess = 6; - if ((globalBottomGuess > 32) || (globalBottomGuess < 0)) - globalBottomGuess = 6; - if ((globalRightGuess > 32) || (globalRightGuess < 0)) - globalRightGuess = 6; - } - - wdata->top = wdata->topGuess = globalTopGuess; - wdata->left = wdata->leftGuess = globalLeftGuess; - wdata->bottom = wdata->bottomGuess = globalBottomGuess; - wdata->right = wdata->rightGuess = globalRightGuess; -} - -/* - * To keep input method windows floating, maintain a list of all - * input method windows here. When some top level window gets - * activated, moved, or resized, these input method windows need - * to be brought on top. - */ -static struct FrameDataList* allInputMethodWindow = NULL; - -/* - * Add a new element into the input method window list - */ -void addInputMethodWindow(struct FrameData* wdata) { - struct FrameDataList* newNode; - newNode = (struct FrameDataList*) - malloc(sizeof(struct FrameDataList)); - newNode->wdata = wdata; - newNode->next = allInputMethodWindow; - allInputMethodWindow = newNode; -} - -/* - * Remove an element from the top level window list - * (recursive) - */ -Boolean removeInputMethodWindowR(struct FrameDataList** ptr, - struct FrameData* wdata) { - struct FrameDataList* node = *ptr; - if (node == NULL) { - return False; - } - if (node->wdata == wdata) { - *ptr = node->next; - free(node); - return True; - } - return removeInputMethodWindowR(&(node->next), wdata); -} - -Boolean removeInputMethodWindow(struct FrameData* wdata) { - return removeInputMethodWindowR(&allInputMethodWindow, wdata); -} - -/* - * Raise input method windows - */ -void raiseInputMethodWindow(struct FrameData* wdata) { - struct FrameDataList* node = allInputMethodWindow; - - if (wdata->isInputMethodWindow) { - return; - } - - while (node != NULL) { - XRaiseWindow(awt_display, XtWindow(node->wdata->winData.shell)); - node = node->next; - } -} - -/* fieldIDs for Frame fields that may be accessed from C */ -static struct FrameIDs { - jfieldID resizable; - jfieldID state; -} frameIDs; - -/* - * Class: java_awt_Frame - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for Frame.java - to initialize the fieldIDs for fields that may be accessed from C */ -JNIEXPORT void JNICALL -Java_java_awt_Frame_initIDs - (JNIEnv *env, jclass cls) -{ - frameIDs.resizable = (*env)->GetFieldID(env, cls, "resizable", "Z"); - frameIDs.state = (*env)->GetFieldID(env, cls, "state", "I"); -} - -/* ******* */ -/* Dialogs */ -/* ******* */ -/* No longer have a need for unique fields for query */ -static struct DialogIDs { - jfieldID modal; - jfieldID resizable; -} dialogIDs; - -JNIEXPORT void JNICALL -Java_java_awt_Dialog_initIDs - (JNIEnv *env, jclass cls) -{ -#if 0 - dialogIDs.modal = (*env)->GetFieldID(env, cls, "modal", "Z"); - dialogIDs.resizable = (*env)->GetFieldID(env, cls, "resizable", "Z"); -#endif -} - -/* ******* */ -/* Windows */ -/* ******* */ - -JNIEXPORT void JNICALL -Java_java_awt_Window_initIDs - (JNIEnv *env, jclass cls) -{ - windowIDs.warningString = (*env)->GetFieldID(env, cls, "warningString", - "Ljava/lang/String;"); - windowIDs.resetGCMID = (*env)->GetMethodID(env, cls, "resetGC", - "()V"); - - windowIDs.locationByPlatform = (*env)->GetFieldID(env, cls, "locationByPlatform", - "Z"); - windowIDs.isAutoRequestFocus = (*env)->GetFieldID(env, cls, "autoRequestFocus", "Z"); - - DASSERT(windowIDs.resetGCMID); -} - -/* - * Class: sun_motif_awt_WindowAttributes - * Method: initIDs - * Signature: ()V - */ - -static struct MWindowAttributeIDs { - jfieldID nativeDecor; - jfieldID initialFocus; - jfieldID isResizable; - jfieldID initialState; - jfieldID visibilityState; - jfieldID decorations; -} mWindowAttributeIDs; - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowAttributes_initIDs - (JNIEnv *env, jclass cls) -{ - mWindowAttributeIDs.nativeDecor = - (*env)->GetFieldID(env, cls, "nativeDecor", "Z"); - mWindowAttributeIDs.initialFocus = - (*env)->GetFieldID(env, cls, "initialFocus", "Z"); - mWindowAttributeIDs.isResizable = - (*env)->GetFieldID(env, cls, "isResizable", "Z"); - mWindowAttributeIDs.initialState = - (*env)->GetFieldID(env, cls, "initialState", "I"); - mWindowAttributeIDs.visibilityState = - (*env)->GetFieldID(env, cls, "visibilityState", "I"); - mWindowAttributeIDs.decorations = - (*env)->GetFieldID(env, cls, "decorations", "I"); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: initIDs - * Signature: ()V - */ - -/* This function gets called from the static initializer for MWindowPeer.java - to initialize the fieldIDs for fields that may be accessed from C */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_initIDs - (JNIEnv *env, jclass cls) -{ - mWindowPeerIDs.insets = - (*env)->GetFieldID(env, cls, "insets", "Ljava/awt/Insets;"); - mWindowPeerIDs.winAttr = - (*env)->GetFieldID( env, - cls, - "winAttr", - "Lsun/awt/motif/MWindowAttributes;" - ); - mWindowPeerIDs.iconWidth = - (*env)->GetFieldID(env, cls, "iconWidth", "I"); - mWindowPeerIDs.iconHeight = - (*env)->GetFieldID(env, cls, "iconHeight", "I"); - mWindowPeerIDs.handleWindowFocusOut = - (*env)->GetMethodID(env, - cls, - "handleWindowFocusOut", - "(Ljava/awt/Window;)V"); - mWindowPeerIDs.handleWindowFocusIn = - (*env)->GetMethodID(env, - cls, - "handleWindowFocusIn", - "()V"); - mWindowPeerIDs.handleIconify = - (*env)->GetMethodID(env, - cls, - "handleIconify", - "()V"); - mWindowPeerIDs.handleDeiconify = - (*env)->GetMethodID(env, - cls, - "handleDeiconify", - "()V"); - mWindowPeerIDs.handleStateChange = - (*env)->GetMethodID(env, - cls, - "handleStateChange", - "(II)V"); - - mWindowPeerIDs.draggedToScreenMID = (*env)->GetMethodID(env, cls, - "draggedToNewScreen", - "(I)V"); - DASSERT(mWindowPeerIDs.draggedToScreenMID); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: wrapInSequenced - * Signature: (Ljava/awt/AWTEvent;)Ljava/awt/SequencedEvent; - */ - -/* This method gets called from MWindowPeer to wrap a FocusEvent in - a SequencedEvent. We have to do this in native code, because we - don't want to make SequencedEvent a public class. */ - -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MWindowPeer_wrapInSequenced - (JNIEnv *env, jobject this, jobject awtevent) -{ - jobject global = awt_canvas_wrapInSequenced(awtevent); - jobject local = (*env)->NewLocalRef(env, global); - (*env)->DeleteGlobalRef(env, global); - return local; -} - -extern jobject findTopLevelOpposite(); - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: findOpposite - * Signature: (Ljava/awt/AWTEvent;)Ljava/awt/Window; - */ - -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_MWindowPeer_findOpposite - (JNIEnv *env, jobject this, jint eventType) -{ -#ifdef HEADLESS - return NULL; -#else - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return NULL; - } - - return findTopLevelOpposite(env, eventType); -#endif -} - -/* changeInsets() sets target's insets equal to X/Motif values. */ - -static void -awtJNI_ChangeInsets(JNIEnv * env, jobject this, struct FrameData *wdata) -{ - jobject insets; - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) - return; - - insets = (*env)->GetObjectField(env, this, mWindowPeerIDs.insets); - - if (JNU_IsNull(env, insets)) { - return; - } - - (*env)->SetIntField(env, insets, insetsIDs.top, wdata->top); - (*env)->SetIntField(env, insets, insetsIDs.left, wdata->left); - (*env)->SetIntField(env, insets, insetsIDs.bottom, wdata->bottom); - (*env)->SetIntField(env, insets, insetsIDs.right, wdata->right); - - /* Fix for 4106068: don't do it, rely on the window */ - /* manager maximizing policy instead */ -#if 0 - /* when the insets get set, make sure we set the proper */ - /* max window size (since it's dependent on inset size) */ - if (wdata->isResizable) { - int32_t screenWidth = XWidthOfScreen( XDefaultScreenOfDisplay(awt_display)); - int32_t screenHeight= XHeightOfScreen(XDefaultScreenOfDisplay(awt_display)); - XtVaSetValues(wdata->winData.shell, - XmNmaxWidth, screenWidth - (wdata->left + wdata->right), - XmNmaxHeight, screenHeight - (wdata->top + wdata->bottom), - NULL); - } -#endif - (*env)->DeleteLocalRef(env, insets); -} - - -/* setMbAndWwHeightAndOffsets() attempts to establish the heights - of frame's menu bar and warning window (if present in frame). - setMbAndWwHeightAndOffsets() also adjusts appropriately the - X/Motif offsets and calls changeInsets() to set target insets. - A warning window, if present, is established during ...create(). - wdata->warningWindow is set there, wdata->wwHeight is set here. - Routine pSetMenuBar() sets value of the wdata->menuBar field. - This routine reads that value. If it is not null, a menubar - has been added. In this case, calculate the current height - of the menu bar. This may be a partial (incomplete) menubar - because ths routine may be called before the X/Motif menubar - is completely realized. In this case, the menubar height may - be adjusted incrementally. This routine may be called from - ...pSetMenuBar(), innerCanvasEH(), and ...pReshape(). It is - designed to (eventually) obtain the correct menubar height. - On the other hand, if wdata->menuBar is NULL and the stored - menubar height is not zero, then we subtract off the height. */ - -static void -awtJNI_setMbAndWwHeightAndOffsets(JNIEnv * env, - jobject this, - struct FrameData *wdata ) -{ - Dimension warningHeight, /* Motif warning window height */ - labelHeight; /* Motif warning label's height */ - - WidgetList warningChildrenWL; /* warning children widgets */ - - Dimension menuBarWidth, /* Motif menubar width */ - menuBarHeight, /* Motif menubar height */ - menuBarBorderSize, /* Motif menubar border size */ - marginHeight, /* Motif menubar margin height */ - menuHeight, /* Motif menubar's menu height */ - menuBorderSize, /* Motif menu border size */ - actualHeight; /* height: menu+margins+borders */ - - WidgetList menuBarChildrenWL; /* menubar children widgets */ - Cardinal numberChildren; /* number of menubar children */ - -#ifdef _pauly_debug - fprintf(stdout," ++ setMenuBar\n"); - fflush(stdout); -#endif /* _pauly_debug */ - - /* If warning window height not yet known, try to get it now. - It will be added to top or bottom (iff NETSCAPE) offset. */ - if (wdata->warningWindow != NULL) { - XtVaGetValues(wdata->warningWindow, - XmNheight, &warningHeight, - XmNchildren, &warningChildrenWL, - XmNnumChildren, &numberChildren, - NULL); - - /* We may be doing this before warning window is realized ! So, - check for a child label in the warning. If its height is not - yet accounted for in the warning height, then use it here. */ - if (numberChildren != 0) { - XtVaGetValues(warningChildrenWL[0], - XmNheight, &labelHeight, - NULL); -#ifdef _pauly_debug - fprintf(stdout," setMenuBar.... warning label found with height: %d\n", labelHeight); - fflush(stdout); -#endif /* _pauly_debug */ - if (warningHeight < labelHeight) { -#ifdef _pauly_debug - fprintf(stdout," setMenuBar.... !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); - fflush(stdout); -#endif /* _pauly_debug */ - warningHeight = labelHeight; - } - } - - if (wdata->wwHeight < warningHeight) { -#ifdef _pauly_debug - fprintf(stdout, " setMenuBar.... adding warning height: %d\n", warningHeight); - fflush(stdout); -#endif /* _pauly_debug */ -#ifdef NETSCAPE - wdata->bottom += (warningHeight - wdata->wwHeight); -#else - wdata->top += (warningHeight - wdata->wwHeight); -#endif /* NETSCAPE */ - awtJNI_ChangeInsets(env, this, wdata); - wdata->wwHeight = warningHeight; - } - } - - /* Now we adjust offsets for an added or removed menu bar */ - if (wdata->menuBar != NULL) { -#ifdef _pauly_debug - fprintf(stdout," setMenuBar. menu bar: %x\n", wdata->menuBar); - fflush(stdout); -#endif /* _pauly_debug */ - XtVaGetValues(wdata->menuBar, - XmNwidth, &menuBarWidth, - XmNheight, &menuBarHeight, - XmNchildren, &menuBarChildrenWL, - XmNnumChildren, &numberChildren, - XmNborderWidth, &menuBarBorderSize, - XmNmarginHeight, &marginHeight, - NULL); - - /* We may be doing this before menu bar is realized ! Hence, - check for a menu in the menu bar. If its height is not yet - accounted for in the menu bar height, then add it in here. */ - if (numberChildren != 0) { - XtVaGetValues(menuBarChildrenWL[0], - XmNheight, &menuHeight, - XmNborderWidth, &menuBorderSize, - NULL); -#ifdef _pauly_debug - fprintf(stdout," setMenuBar.... menu found with height: %d, border: %d, margin: %d, bar border: %d\n", menuHeight, menuBorderSize, marginHeight, menuBarBorderSize); - fflush(stdout); -#endif /* _pauly_debug */ - /* Calculate real height of menu bar by adding height of its - child menu and borders, margins, and the menu bar borders*/ - actualHeight = menuHeight + (2 * menuBorderSize) + - (2 * marginHeight) + (2 * menuBarBorderSize); -#ifdef __linux__ -#ifdef _pauly_debug - fprintf(stdout," actual height: %d mb height %d\n", actualHeight, menuBarHeight); - fflush(stdout); -#endif /* _pauly_debug */ -#endif - if (menuBarHeight < actualHeight) { -#ifdef _pauly_debug -fprintf(stdout," setMenuBar.... ****************************************\n"); -fflush(stdout); -#endif /* _pauly_debug */ - menuBarHeight = actualHeight; - } - } - - if (wdata->mbHeight < menuBarHeight) { - /* Adjust the (partially) added menu bar height, top offset.*/ -#ifdef _pauly_debug - fprintf(stdout, " setMenuBar.... added menuBar height: %d\n", menuBarHeight); - fflush(stdout); -#endif /* _pauly_debug */ - wdata->top += (menuBarHeight - wdata->mbHeight); - awtJNI_ChangeInsets(env, this, wdata); - wdata->mbHeight = menuBarHeight; - } - } else if ((wdata->menuBar == NULL) && (wdata->mbHeight > 0)) { - /* A menu bar has been removed; subtract height from top offset.*/ - wdata->top -= wdata->mbHeight; -#ifdef _pauly_debug - fprintf(stdout, " setMenuBar.... removed menuBar height: %d\n", wdata->mbHeight); - fflush(stdout); -#endif /* _pauly_debug */ - awtJNI_ChangeInsets(env, this, wdata); - wdata->mbHeight = 0; - } -} - - -/* outerCanvasResizeCB() is Motif resize callback for outer/child canvas. - It reads width, height of Motif widget, sets java target accordingly, - and then calls handleResize() to affect any changes. - This call is only done for a shell resize or inner/parent resize; - i.e., it may not be done for a ...pReshape() to avoid doing a loop. - - client_data is MWindowPeer instance -*/ -static void -outerCanvasResizeCB(Widget wd, XtPointer client_data, XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject target; - struct FrameData *wdata; - Position screenX; /* x position of the canvas, screen */ - Position screenY; /* y position of the canvas, screen */ - Dimension width; /* width of the canvas, target */ - Dimension height; /* height of the canvas, target */ - jint oldWidth; - jint oldHeight; - -#ifdef _pauly_debug - fprintf(stdout," ++ WindowResize.\n"); - fflush(stdout); -#endif /* _pauly_debug */ - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, (jobject) client_data, - mComponentPeerIDs.pData); - if (wdata == NULL) { - return; - } - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) - return; - - target = (*env)->GetObjectField(env, (jobject) client_data, - mComponentPeerIDs.target); - XtVaGetValues(wd, - XmNwidth, &width, - XmNheight, &height, - NULL); -#ifdef _pauly_debug - fprintf(stdout," outerCanvasResizeCB. width: %d, height: %d\n", width, height); - fflush(stdout); -#endif /* _pauly_debug */ - - - XtTranslateCoords(wd, 0, 0, &screenX, &screenY); - - if ((wdata->shellResized) || (wdata->canvasResized)) { -#ifdef _pauly_debug - fprintf(stdout," outerCanvasResizeCB\n"); - fflush(stdout); -#endif /* _pauly_debug */ - wdata->shellResized = False; - wdata->canvasResized = False; - /* - ** if you are not yet reparented, don't compute the size based on the - ** widgets, as the window manager shell containg the insets is not yet - ** there. Use the size the application has set. - ** If not reparented, we got here because the application set the size, - ** so just send them Component.RESIZED event with the size they set. - ** - ** If the reparenting causes a resize ( only when inset guess is wrong ) ** the new size will be sent in a Component.RESIZED event at that time. - */ - if (wdata->reparented) - { - (*env)->SetIntField(env, target, componentIDs.x, (jint) screenX); - (*env)->SetIntField(env, target, componentIDs.y, (jint) screenY); - } - - oldWidth = (*env)->GetIntField(env, target, componentIDs.width); - oldHeight = (*env)->GetIntField(env, target, componentIDs.height); - - if (oldWidth != width || oldHeight != height || wdata->need_reshape) - { - wdata->need_reshape = False; - (*env)->SetIntField(env, target, componentIDs.width, (jint)width); - (*env)->SetIntField(env, target, componentIDs.height, - (jint)height); - - /* only do this for Windows, not Canvases, btw */ - checkNewXineramaScreen(env, client_data, wdata, screenX, screenY, width, height); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, - "handleResize", "(II)V", width, height); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - } - - (*env)->DeleteLocalRef(env, target); - -#ifdef _pauly_debug - fprintf(stdout," WindowResize. Done.\n"); - fflush(stdout); -#endif /* _pauly_debug */ - -} /* outerCanvasResizeCB() */ - -static void reconfigureOuterCanvas ( JNIEnv *env, jobject target, - jobject this, struct FrameData *wdata ) -{ - Dimension innerDAWidth, /* width of inner Motif canvas */ - innerDAHeight, /* height of inner Motif canvas */ - outerDAWidth, /* width of outer Motif canvas */ - outerDAHeight; /* height of outer Motif canvas */ - int32_t targetWidth, /* java target object's width */ - targetHeight; /* java target's object height */ - Dimension width; /* width of the canvas, target */ - Dimension height; /* height of the canvas, target */ - - - Position innerX, /* x loc. of inner Motif canvas */ - innerY, /* y loc. of inner Motif canvas */ - x, y; - - /* canvasW is (visible) inner/parent drawing area (canvas) widget */ - XtVaGetValues(XtParent(wdata->winData.comp.widget), - XmNwidth, &innerDAWidth, - XmNheight, &innerDAHeight, - XmNx, &innerX, - XmNy, &innerY, - NULL); - - /* This resize may be due to the insertion or removal of a menu bar. - If so, we appropriately adjust the top offset in wdata, insets. */ - awtJNI_setMbAndWwHeightAndOffsets(env, this, wdata); - - outerDAWidth = innerDAWidth + wdata->left + wdata->right; - outerDAHeight = innerDAHeight + wdata->top + wdata->bottom; - - /* If it's a menu bar reset, do not do resize of outer/child canvas. - (Another thread problem; we arrest this now before damage done.) */ - if (wdata->menuBarReset) - { - targetWidth = (*env)->GetIntField(env, target, componentIDs.width); - targetHeight = (*env)->GetIntField(env, target, componentIDs.height); - if ((outerDAWidth != targetWidth) || (outerDAHeight != targetHeight)) - { - return; - } - } - - wdata->canvasResized = True; - - /* The outer/child drawing area (canvas) needs to be configured too. - If its size changes, its resize callback will thereby be invoked.*/ - x = -wdata->left; - y = -wdata->top; - width = innerDAWidth + wdata->left + wdata->right; - height = innerDAHeight + wdata->top + wdata->bottom; - - XtConfigureWidget(wdata->winData.comp.widget, x, y, width, height, 0 ); -} - - - -/* innerCanvasEH() is event handler for inner/parent canvas. It handles - map and configure notify events. It reads width and height, adjusts - for menubar insertion / removal and configures outer/child canvas. */ - -static void -innerCanvasEH(Widget canvasW, XtPointer client_data, XEvent *event, - Boolean* continueToDispatch) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) client_data; - jobject target; - struct FrameData *wdata; - - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL) { - return; - } - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) - return; - - target = (*env)->GetObjectField(env, (jobject) client_data, - mComponentPeerIDs.target); - - /* While inside ...pSetMenuBar(), don't react to incomplete resizing - events supplied by Xt toolkit. Wait for completion of the routine. */ - - - /* For a map or resize, we need to check for the addition or deletion - of a menu bar to the form which is the of this drawing area (canvas). - We also must then configure the outer/child canvas appropriately. */ - - if ( (event->xany.type == MapNotify) || - (event->xany.type == ConfigureNotify) ) - { - reconfigureOuterCanvas( env, target, this, wdata ); - } - - (*env)->DeleteLocalRef(env, target); - -} - -/* syncTopLevelPos() is necessary to insure that the window manager has in - * fact moved us to our final position relative to the reParented WM window. - * We have noted a timing window which our shell has not been moved so we - * screw up the insets thinking they are 0,0. Wait (for a limited period of - * time to let the WM hava a chance to move us - */ -void syncTopLevelPos( Display *d, Window w, XWindowAttributes *winAttr ) -{ - int32_t i = 0; - memset(winAttr, 0, sizeof(*winAttr)); - - do { - if (!XGetWindowAttributes(d, w, winAttr)) { - memset(winAttr, 0, sizeof(*winAttr)); - break; - } - /* Sometimes we get here before the WM has updated the - ** window data struct with the correct position. Loop - ** until we get a non-zero position. - */ - if ((winAttr->x != 0) || (winAttr->y != 0)) { - break; - } - else { - /* What we really want here is to sync with the WM, - ** but there's no explicit way to do this, so we - ** call XSync for a delay. - */ - XSync(d, False); - } - } while (i++ < 50); -} - -typedef struct FocusOutInfo_str { - XEvent * eventOut; - Window inWin; - Window inChild; - Widget defChild; - jobject childComp; -} FocusOutInfo_t; - -#define IsCanvasTypeWidget(w) \ - (XtIsSubclass(w, xmDrawingAreaWidgetClass) ||\ - XtIsSubclass(w, vDrawingAreaClass)) - -int isTopLevelPartWidget(Widget w) { - if (XtIsShell(w)) { - return TRUE; - } - if (XtIsSubclass(w, xmFormWidgetClass)) { - return TRUE; - } - if (IsCanvasTypeWidget(w)) { - Widget w1 = XtParent(w); - if (w1 != NULL) { - if (XtIsSubclass(w1, xmFormWidgetClass)) { - return TRUE; - } - if (IsCanvasTypeWidget(w1)) { - Widget w2 = XtParent(w1); - if (w2 != NULL) { - if (XtIsSubclass(w2, xmFormWidgetClass)) { - return TRUE; - } - } - } - - } - } - return FALSE; -} - -void -shellFocusEH(Widget w, XtPointer data, XEvent *event, Boolean *continueToDispatch) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) data; - jobject target; - struct FrameData *wdata; - - /* Any event handlers which take peer instance pointers as - * client_data should check to ensure the widget has not been - * marked as destroyed as a result of a dispose() call on the peer - * (which can result in the peer instance pointer already haven - * been gc'd by the time this event is processed) - */ - if (w->core.being_destroyed) { - return; - } - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL) { - return; - } - - switch (event->xany.type) { - case FocusOut: - // Will be handled by proxy automaticall since he is focus owner - break; - case FocusIn: - // Forward focus event to the proxy - XSetInputFocus(awt_display, XtWindow(wdata->focusProxy), RevertToParent, CurrentTime); - break; - } -} - -/** - * Fix for Alt-Tab problem. - * See coments on use semantics below. - */ -Boolean skipNextNotifyWhileGrabbed = False; -Boolean skipNextFocusIn = False; - -Boolean focusOnMapNotify = False; - -/* shellEH() is event handler for the Motif shell widget. It handles - focus change, map notify, configure notify events for the shell. - Please see internal comments pertaining to these specific events. - - data is MWindowPeer instance pointer -*/ -void -shellEH(Widget w, XtPointer data, XEvent *event, Boolean *continueToDispatch) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject) data; - jobject target; - struct FrameData *wdata; - int32_t setTargetX, - setTargetY, - getTargetX, - getTargetY; - /* Changed long to int for 64-bit */ - int32_t wwHeight; /* height of any warning window present */ - int32_t topAdjust; /* adjust top offset for menu, warning */ - jclass clazz; - int32_t x, y; - int32_t width, height; - enum wmgr_t runningWM; - jobject winAttrObj; - static jobject windowClass = NULL; - /* Any event handlers which take peer instance pointers as - * client_data should check to ensure the widget has not been - * marked as destroyed as a result of a dispose() call on the peer - * (which can result in the peer instance pointer already haven - * been gc'd by the time this event is processed) - */ - if (w->core.being_destroyed) { - return; - } - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL) { - return; - } - - switch (event->xany.type) { - - case FocusOut: { - int32_t res = 0; - int revert_to = 0; - Widget defChild = NULL; - Window focusOwner = None; - jobject oppositeWindow = NULL; - Widget oppositeShell = NULL; - XEvent inEvent; - Widget shell = NULL; -#ifdef DEBUG_FOCUS - fprintf(stderr, "Focusout on proxy; window = %x, mode %d, detail %d\n", - event->xfocus.window, event->xfocus.mode, event->xfocus.detail); -#endif - shell = wdata->winData.shell; - - if ((*env)->EnsureLocalCapacity(env, 3) < 0) { - break; - } - - /** - * Fix for Alt-Tab problem. We should process NotifyWhileGrabbed events - * only if they are due to the switch between top-levels. - * skipNextNotifyWhileGrabbed is set from Menu and PopupMenu code - * to prevent generation of focus events when user interact with these - * widget. - */ - if (event->xfocus.mode == NotifyWhileGrabbed) { - if (skipNextNotifyWhileGrabbed) { - skipNextNotifyWhileGrabbed = False; - break; - } - } else if (event->xfocus.mode != NotifyNormal) break; - - /** - * Fix for Alt-Tab problem. - * skipNextFocusIn is set in Choice code to avoid processing of - * next focus-in or focus-out generated by Choice as it is a fake - * event. - */ - if (skipNextFocusIn && event->xfocus.detail == NotifyPointer) { - break; - } - - XGetInputFocus( awt_display, &focusOwner, &revert_to); - - if (focusOwner != None) { - Widget inWidget = NULL; - jobject wpeer = NULL; - inWidget = XtWindowToWidget(awt_display, focusOwner); - if (inWidget != NULL && inWidget != shell) { - oppositeShell = getShellWidget(inWidget); - wpeer = findPeer(&inWidget); - if (wpeer == NULL) { - inWidget = findTopLevelByShell(inWidget); - if (inWidget != NULL) { - wpeer = findPeer(&inWidget); - } - } - if (wpeer != NULL) { - jobject peerComp = - (*env)->GetObjectField(env, - wpeer, - mComponentPeerIDs.target); - if (peerComp != NULL) { - // Check that peerComp is top-level - - // load class - if (windowClass == NULL) { - jobject localWindowClass = (*env)->FindClass(env, "java/awt/Window"); - windowClass = (*env)->NewGlobalRef(env, localWindowClass); - (*env)->DeleteLocalRef(env, localWindowClass); - } - if ((*env)->IsInstanceOf(env, peerComp, windowClass)) { - oppositeWindow = peerComp; - } else { // Opposite object is not Window - there is no opposite window. - (*env)->DeleteLocalRef(env, peerComp); - peerComp = NULL; - oppositeShell = NULL; - } - } - } - } - } else { - // If there is no opposite shell but we have active popup - this popup is actually - // the oppposite. This should mean that this focus out is due to popup - and thus - // should be skipped. Fix for 4478780. - if (skipNextNotifyWhileGrabbed) { - break; - } - } - - // If current window is not focusable and opposite window is not focusable - do nothing - // If current window is focusable and opposite is not - do not clear focus variables like - // focus didn't leave this window(but it will in terms of X). When we later switch to either - // - back to this window: variables are already here - // - another focusable window: variables point to focusable window and "focus lost" events - // will be generated for it - // - non-java window: variables point to focusable window and "focus lost" events - // will be generated for it, not for non-focusable. - // If current window is non-focusable and opposite is focusable then do not generate anything - // as if we didn't leave previous focusable window so Java events will generated for it. - // - // Fix for 6547951. - // Also do cleaning when switching to non-java window (opposite is null). - if (isFocusableWindowByShell(env, shell) && shell != oppositeShell && - ((oppositeShell != NULL && isFocusableWindowByShell(env, oppositeShell)) || - oppositeShell == NULL)) - { - // The necessary FOCUS_LOST event will be generated by DKFM. - // So we need to process focus list like we received FocusOut - // for the desired component - shell's current focus widget - defChild = XmGetFocusWidget(shell); - if (defChild != NULL) { - jobject peer = findPeer(&defChild); - if (peer == NULL) { - defChild = findTopLevelByShell(defChild); - if (defChild != NULL) { - peer = findPeer(&defChild); - } - } - if (peer != NULL) { - jobject comp = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - if (focusList != NULL) { - jobject last = (*env)->NewLocalRef(env, focusList->requestor); - if ((*env)->IsSameObject(env, comp, last)) { - FocusListElt * temp = focusList; - forGained = focusList->requestor; - focusList = focusList->next; - free(temp); - if (focusList == NULL) { - focusListEnd = NULL; - } - } - if (!JNU_IsNull(env, last)) { - (*env)->DeleteLocalRef(env, last); - } - } - (*env)->DeleteLocalRef(env, comp); - } - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - processTree(defChild, findWindowsProxy(target, env), False); - XtSetKeyboardFocus(shell, NULL); - (*env)->DeleteLocalRef(env, target); - } -#ifndef NOMODALFIX - if (!awt_isModal() || awt_isWidgetModal(shell)) { -#endif //NOMODALFIX - if ( oppositeShell != NULL - && isFocusableWindowByShell(env, oppositeShell) - && isFocusableWindowByShell(env, shell) - || (oppositeShell == NULL)) - { - /* - * Fix for 5095117. - * Check if current native focused window is the same as source. - * Sometimes it is not - we must not however clean reference to - * actual native focused window. - */ - jobject currentFocusedWindow = awt_canvas_getFocusedWindowPeer(); - if ((*env)->IsSameObject(env, this, currentFocusedWindow)) { - awt_canvas_setFocusedWindowPeer(NULL); - } - (*env)->DeleteLocalRef(env, currentFocusedWindow); - - JNU_CallMethodByName(env, NULL, this, "handleWindowFocusOut", "(Ljava/awt/Window;)V", - oppositeWindow); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } -#ifndef NOMODALFIX - } -#endif //NOMODALFIX - if (oppositeWindow != NULL) { - (*env)->DeleteLocalRef(env, oppositeWindow); - } - - break; - } /* FocusOut */ - - case FocusIn: { - Widget shell = wdata->winData.shell; -#ifdef DEBUG_FOCUS - fprintf(stderr, "FocusIn on proxy; window = %x, mode %d, detail %d\n", event->xfocus.window, - event->xfocus.mode, event->xfocus.detail); -#endif - if (/* event->xfocus.mode == NotifyNormal */ 1) { - - /** - * Fix for Alt-Tab problem. We should process NotifyWhileGrabbed events to detect - * switch between top-levels using alt-tab, but avoid processing these type of event - * when they are originated from other sources. - */ - if (event->xfocus.mode == NotifyWhileGrabbed) { - /** - * skipNextNotifyWhileGrabbed is set from Menu and PopupMenu code to - * skip next focus-in event with NotifyWhileGrabbed as it is generated - * in result of closing of the Menu's shell. - * Event will also have NotifyInferior if uses clicked on menu bar in the - * space where there is not menu items. - */ - if (skipNextNotifyWhileGrabbed || event->xfocus.detail == NotifyInferior) { - skipNextNotifyWhileGrabbed = False; - break; - } - } else if (event->xfocus.mode != NotifyNormal) { - break; - } - - /** - * Fix for Alt-Tab problem. - * skipNextFocusIn is set from Choice code to avoid processing next focus-in - * as it is a fake event. - */ - if (skipNextFocusIn == True) { - /** - * There could be the set of fake events, the last one - * will have detail == NotifyPointer - */ - if (event->xfocus.detail != NotifyPointer) { - skipNextFocusIn = False; - } - break; - } -#ifndef NOMODALFIX - if (!awt_isModal() || awt_isWidgetModal(shell)) { -#endif //NOMODALFIX - if (isFocusableWindowByShell(env, shell)) { - jobject currentFocusedWindow = awt_canvas_getFocusedWindowPeer(); - // Check if focus variables already point to this window. If so, - // it means there were transfer to non-focusable window and now we - // are back to origianl focusable window. No need to generate Java events - // in this case. - if (!(*env)->IsSameObject(env, this, currentFocusedWindow)) { - awt_canvas_setFocusedWindowPeer(this); - awt_canvas_setFocusOwnerPeer(this); - - /* - * Fix for 6465038. - * Restore focus on the toplevel widget if it's broken. - */ - Widget widgetToFocus = getFocusWidget(findTopLevelByShell(shell)); - Widget currentOwner = XmGetFocusWidget(shell); - - if (widgetToFocus != currentOwner) { -#ifdef DEBUG_FOCUS - fprintf(stderr, "Wrong Xm focus; resetting Xm focus from %x to toplevel %x...\n", - currentOwner != NULL ? XtWindow(currentOwner) : 0, - widgetToFocus != NULL ? XtWindow(widgetToFocus) : 0); -#endif - if ( !XmProcessTraversal(widgetToFocus, XmTRAVERSE_CURRENT) ) { - XtSetKeyboardFocus(shell, widgetToFocus); - } -#ifdef DEBUG_FOCUS - Widget _w = XmGetFocusWidget(shell); - fprintf(stderr, " ...focus resulted on window %x\n", _w != NULL ? XtWindow(_w) : 0); -#endif - } - - JNU_CallMethodByName(env, NULL, this, "handleWindowFocusIn", "()V"); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - (*env)->DeleteLocalRef(env, currentFocusedWindow); - } -#ifndef NOMODALFIX - } -#endif //NOMODALFIX - } - raiseInputMethodWindow(wdata); - break; - } /* FocusIn */ - - case VisibilityNotify: { - winAttrObj = (*env)->GetObjectField(env, this, mWindowPeerIDs.winAttr); - (*env)->SetIntField(env, winAttrObj, - mWindowAttributeIDs.visibilityState, - event->xvisibility.state); - if (event->xvisibility.state == VisibilityUnobscured) { - raiseInputMethodWindow(wdata); - } - break; - } /* VisibilityNotify */ - - case MapNotify: { - /* Your body seems to unfade */ - if (wdata->initialFocus == False) { - XtVaSetValues(wdata->winData.shell, XmNinput, True, NULL); - - // We have to to evidently move the window to the front here. - Window shellWindow; - if ((shellWindow = XtWindow(wdata->winData.shell)) != None) { - XRaiseWindow(awt_display, shellWindow); - } - } - if (awt_wm_isStateNetHidden(XtWindow(wdata->winData.shell))) { - focusOnMapNotify = True; - } - /* - * TODO: perhaps we need this putback only for simple Window. - * For Frame/Dialog XmNinput==True would be enough. The native - * system will focus it itself. - */ - if (wdata->isFocusableWindow && focusOnMapNotify) { - XEvent ev; - memset(&ev, 0, sizeof(ev)); - - ev.type = FocusIn; - ev.xany.send_event = True; - ev.xany.display = awt_display; - ev.xfocus.mode = NotifyNormal; - ev.xfocus.detail = NotifyNonlinear; - ev.xfocus.window = XtWindow(wdata->winData.shell); - awt_put_back_event(env, &ev); - } - focusOnMapNotify = False; - - break; - } - - case UnmapNotify: { - /* Gee! All of a sudden, you can't see yourself */ - if (wdata->initialFocus == False) { - XtVaSetValues(wdata->winData.shell, XmNinput, False, NULL); - } - if (awt_wm_isStateNetHidden(XtWindow(wdata->winData.shell))) { - focusOnMapNotify = True; - } - break; - } - - case DestroyNotify: { /* Foul play! ICCCM forbids WM to do this! */ - /* Your window is killed by the WM */ - JNU_CallMethodByName(env, NULL, this, "handleDestroy", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - break; - } - - case PropertyNotify: { - jint state, old_state, changed; - - /* - * Let's see if this is a window state protocol message, and - * if it is - decode a new state in terms of java constants. - */ - if (!awt_wm_isStateChange(wdata, (XPropertyEvent *)event, &state)) { - /* Pakka Pakka seems not interested */ - break; - } - - changed = wdata->state ^ state; - if (changed == 0) { - /* You feel dizzy for a moment, but nothing happens... */ - DTRACE_PRINTLN("TL: >>> state unchanged"); - break; - } - - old_state = wdata->state; - wdata->state = state; - -#ifdef DEBUG - DTRACE_PRINT("TL: >>> State Changed:"); - if (changed & java_awt_Frame_ICONIFIED) { - if (state & java_awt_Frame_ICONIFIED) { - DTRACE_PRINT(" ICON"); - } else { - DTRACE_PRINT(" !icon"); - } - } - if (changed & java_awt_Frame_MAXIMIZED_VERT) { - if (state & java_awt_Frame_MAXIMIZED_VERT) { - DTRACE_PRINT(" MAX_VERT"); - } else { - DTRACE_PRINT(" !max_vert"); - } - } - if (changed & java_awt_Frame_MAXIMIZED_HORIZ) { - if (state & java_awt_Frame_MAXIMIZED_HORIZ) { - DTRACE_PRINT(" MAX_HORIZ"); - } else { - DTRACE_PRINT(" !max_horiz"); - } - } - DTRACE_PRINTLN(""); -#endif - - if (changed & java_awt_Frame_ICONIFIED) { - /* Generate window de/iconified event for old clients */ - if (state & java_awt_Frame_ICONIFIED) { - DTRACE_PRINTLN("TL: ... handleIconify"); - JNU_CallMethodByName(env, NULL, - this, "handleIconify", "()V"); - } - else { - DTRACE_PRINTLN("TL: ... handleDeiconify"); - JNU_CallMethodByName(env, NULL, - this, "handleDeiconify", "()V"); - } - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - - DTRACE_PRINTLN("TL: ... handleStateChange"); - JNU_CallMethodByName(env, NULL, - this, "handleStateChange", "(II)V", - old_state, state); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - break; - } /* PropertyNotify */ - - case ReparentNotify: { - Window root = RootWindowOfScreen(XtScreen(wdata->winData.shell)); - -#ifdef DEBUG - DTRACE_PRINT2("TL: ReparentNotify(0x%x/0x%x) to ", - wdata->winData.shell, XtWindow(wdata->winData.shell)); - if (event->xreparent.parent == root) { - DTRACE_PRINTLN("root"); - } else { - DTRACE_PRINTLN1("window 0x%x", event->xreparent.parent); - } -#endif - - if (wdata->winData.flags & W_IS_EMBEDDED) { - DTRACE_PRINTLN("TL: embedded frame - nothing to do"); - break; - } - -#ifdef __linux__ - if (!wdata->fixInsets) { - DTRACE_PRINTLN("TL: insets already fixed"); - break; - } - else { - wdata->fixInsets = False; - } -#endif - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) - break; - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - x = (*env)->GetIntField(env, target, componentIDs.x); - y = (*env)->GetIntField(env, target, componentIDs.y); - width = (*env)->GetIntField(env, target, componentIDs.width); - height = (*env)->GetIntField(env, target, componentIDs.height); - - /* The insets were literally hardcoded in the MWindowPeer. - But they are dependent upon both the window manager (WM) - and the hardware display. So, these are usually wrong. - This leads to problems with shell positioning and size. - Furthermore, there is not a published interface or way - to obtain from any given window manager the dimensions - of its decoration windows (i.e., borders and title bar). - So, given this problem in design, we must workaround. - N.B. (0) This works. But there is one functional caveat: - the frame.insets() function will usually return - the wrong values until AFTER the frame is shown. - It always did this before; it's just that now, - the values will become correct after rendering, - whereas before the values were never corrected. - (I believe this unavoidable given this design.) - (1) Note that we must/have to do this exactly once. - (2) The hardcoded values of ...create() (25,5) - are also utilized here and must be consistent. - This of course could be reworked as desired. - (3) Assume top border (title bar) is one width, - and other three borders are another width. - This, however, could be easily reworked below. */ - - /* - * The above comment is no longer completely true. - * The insets are no longer hardcoded but are retrieved from - * guessInsets(), either from a per-window manager default, - * set in the awt.properties file, or overwritten by the - * actual values determined from a previous frames - * reparenting. - */ - - if (wdata->decor == AWT_NO_DECOR) { - if (!wdata->isResizable && !wdata->isFixedSizeSet) { - reshape(env, this, wdata, x, y, width, height, False); - if (wdata->warningWindow != NULL) - awtJNI_ChangeInsets(env, this, wdata); - } - } - else if (event->xreparent.parent == root) { - wdata->reparented = False; - wdata->configure_seen = False; - - /* - * We can be repareted to root for two reasons: - * . setVisible(false) - * . WM exited - */ - if (wdata->isShowing) { /* WM exited */ - /* Work around 4775545 */ - awt_wm_unshadeKludge(wdata); - } - } - else { /* reparented to WM frame, figure out our insets */ - XWindowAttributes winAttr, actualAttr; - int32_t correctWMTop = -1; - int32_t correctWMLeft = -1; - int32_t correctWMBottom; - int32_t correctWMRight; - int32_t topCorrection; - int32_t leftCorrection; - int32_t bottomCorrection = 0; - int32_t rightCorrection = 0; - int32_t screenX, screenY; - int32_t i; - int32_t actualWidth, actualHeight; - int32_t t, l, b, r; - Window containerWindow; - - /* Dummies for XQueryTree */ - Window ignore_Window, *ignore_WindowPtr; - uint32_t ignore_uint; - - Boolean setXY = True; - XSizeHints* hints = XAllocSizeHints(); - - wdata->reparented = True; - - if (hints != NULL) { - long ignore = 0; - XGetWMNormalHints(awt_display, XtWindow(wdata->winData.shell), - hints, &ignore); - setXY = (hints->flags & (USPosition|PPosition)) != 0; - XFree(hints); - } - - /* - * Unfortunately the concept of "insets" borrowed to AWT - * from Win32 is *absolutely*, *unbelievably* foreign to - * X11. Few WMs provide the size of frame decor - * (i.e. insets) in a property they set on the client - * window, so we check if we can get away with just - * peeking at it. [Future versions of wm-spec might add a - * standardized hint for this]. - * - * Otherwise we do some special casing. Actually the - * fallback code ("default" case) seems to cover most of - * the existing WMs (modulo Reparent/Configure order - * perhaps?). - * - * Fallback code tries to account for the two most common cases: - * - * . single reparenting - * parent window is the WM frame - * [twm, olwm, sawfish] - * - * . double reparenting - * parent is a lining exactly the size of the client - * grandpa is the WM frame - * [mwm, e!, kwin, fvwm2 ... ] - */ - - if (awt_wm_getInsetsFromProp(event->xreparent.window, - &t, &l, &b, &r)) - { - correctWMTop = t; - correctWMLeft = l; - correctWMBottom = b; - correctWMRight = r; - setXY = False; - } - else - switch (awt_wm_getRunningWM()) { - - /* should've been done in awt_wm_getInsetsFromProp */ - case ENLIGHTEN_WM: { - DTRACE_PRINTLN("TL: hmm, E! insets should have been read" - " from _E_FRAME_SIZE"); - /* enlightenment does double reparenting */ - syncTopLevelPos(XtDisplay(wdata->winData.shell), - event->xreparent.parent, &winAttr); - - XQueryTree(XtDisplay(wdata->winData.shell), - event->xreparent.parent, - &ignore_Window, - &containerWindow, /* actual WM frame */ - &ignore_WindowPtr, - &ignore_uint); - if (ignore_WindowPtr) - XFree(ignore_WindowPtr); - - correctWMLeft = winAttr.x; - correctWMTop = winAttr.y; - - /* - * Now get the actual dimensions of the parent window - * resolve the difference. We can't rely on the left - * to be equal to right or bottom... Enlightment - * breaks that assumption. - */ - XGetWindowAttributes(XtDisplay(wdata->winData.shell), - containerWindow, &actualAttr); - correctWMRight = actualAttr.width - - (winAttr.width + correctWMLeft); - correctWMBottom = actualAttr.height - - (winAttr.height + correctWMTop) ; - break; - } - - case ICE_WM: - case KDE2_WM: /* should've been done in awt_wm_getInsetsFromProp */ - case CDE_WM: - case MOTIF_WM: { - /* these are double reparenting too */ - syncTopLevelPos(XtDisplay(wdata->winData.shell), - event->xreparent.parent, &winAttr); - - correctWMTop = winAttr.y; - correctWMLeft = winAttr.x; - correctWMRight = correctWMLeft; - correctWMBottom = correctWMLeft; - - XTranslateCoordinates(awt_display, event->xreparent.window, - root, 0,0, &screenX, &screenY, - &containerWindow); - - if ((screenX != x + wdata->leftGuess) - || (screenY != y + wdata->topGuess)) - { - /* - * looks like the window manager has placed us somewhere - * other than where we asked for, lets respect the window - * and go where he put us, not where we tried to put us - */ - x = screenX - correctWMLeft; - y = screenY - correctWMTop; - } - break; - } - - case SAWFISH_WM: - case OPENLOOK_WM: { - /* single reparenting */ - syncTopLevelPos(XtDisplay(wdata->winData.shell), - event->xreparent.window, &winAttr); - - correctWMTop = winAttr.y; - correctWMLeft = winAttr.x; - correctWMRight = correctWMLeft; - correctWMBottom = correctWMLeft; - break; - } - - case OTHER_WM: - default: { /* this is very similar to the E! case above */ - Display *dpy = event->xreparent.display; - Window w = event->xreparent.window; - Window parent = event->xreparent.parent; - XWindowAttributes wattr, pattr; - - XGetWindowAttributes(dpy, w, &wattr); - XGetWindowAttributes(dpy, parent, &pattr); - - DTRACE_PRINTLN5("TL: window attr +%d+%d+%dx%d (%d)", - wattr.x, wattr.y, wattr.width, wattr.height, - wattr.border_width); - DTRACE_PRINTLN5("TL: parent attr +%d+%d+%dx%d (%d)", - pattr.x, pattr.y, pattr.width, pattr.height, - pattr.border_width); - - /* - * Check for double-reparenting WM. - * - * If the parent is exactly the same size as the - * top-level assume taht it's the "lining" window and - * that the grandparent is the actual frame (NB: we - * have already handled undecorated windows). - * - * XXX: what about timing issues that syncTopLevelPos - * is supposed to work around? - */ - if (wattr.x == 0 && wattr.y == 0 - && wattr.width + 2*wattr.border_width == pattr.width - && wattr.height + 2*wattr.border_width == pattr.height) - { - Window ignore_root, grandparent, *children; - unsigned int ignore_nchildren; - - DTRACE_PRINTLN("TL: double reparenting WM detected"); - XQueryTree(dpy, parent, - &ignore_root, - &grandparent, - &children, - &ignore_nchildren); - if (children) - XFree(children); - - /* take lining window into account */ - wattr.x = pattr.x; - wattr.y = pattr.y; - wattr.border_width += pattr.border_width; - - parent = grandparent; - XGetWindowAttributes(dpy, parent, &pattr); - DTRACE_PRINTLN5("TL: window attr +%d+%d+%dx%d (%d)", - wattr.x, wattr.y, - wattr.width, wattr.height, - wattr.border_width); - DTRACE_PRINTLN5("TL: parent attr +%d+%d+%dx%d (%d)", - pattr.x, pattr.y, - pattr.width, pattr.height, - pattr.border_width); - } - - /* - * XXX: To be absolutely correct, we'd need to take - * parent's border-width into account too, but the - * rest of the code is happily unaware about border - * widths and inner/outer distinction, so for the time - * being, just ignore it. - */ - correctWMTop = wattr.y + wattr.border_width; - correctWMLeft = wattr.x + wattr.border_width; - correctWMBottom = pattr.height - - (wattr.y + wattr.height + 2*wattr.border_width); - correctWMRight = pattr.width - - (wattr.x + wattr.width + 2*wattr.border_width); - DTRACE_PRINTLN4("TL: insets = top %d, left %d, bottom %d, right %d", - correctWMTop, correctWMLeft, - correctWMBottom, correctWMRight); - break; - } /* default */ - - } /* switch (runningWM) */ - - - /* - * Ok, now see if we need adjust window size because - * initial insets were wrong (most likely they were). - */ - topCorrection = correctWMTop - wdata->topGuess; - leftCorrection = correctWMLeft - wdata->leftGuess; - bottomCorrection = correctWMBottom - wdata->bottomGuess; - rightCorrection = correctWMRight - wdata->rightGuess; - - DTRACE_PRINTLN3("TL: top: computed=%d, guess=%d, correction=%d", - correctWMTop, wdata->topGuess, topCorrection); - DTRACE_PRINTLN3("TL: left: computed=%d, guess=%d, correction=%d", - correctWMLeft, wdata->leftGuess, leftCorrection); - DTRACE_PRINTLN3("TL: bottom: computed=%d, guess=%d, correction=%d", - correctWMBottom, wdata->bottomGuess, bottomCorrection); - DTRACE_PRINTLN3("TL: right: computed=%d, guess=%d, correction=%d", - correctWMRight, wdata->rightGuess, rightCorrection); - - if (topCorrection != 0 || leftCorrection != 0 - || bottomCorrection != 0 || rightCorrection != 0) - { - jboolean isPacked; - - DTRACE_PRINTLN("TL: insets need correction"); - wdata->need_reshape = True; - - globalTopGuess = correctWMTop; - globalLeftGuess = correctWMLeft; - globalBottomGuess = correctWMBottom; - globalRightGuess = correctWMRight; - - /* guesses are for WM decor *only* */ - wdata->topGuess = correctWMTop; - wdata->leftGuess = correctWMLeft; - wdata->bottomGuess = correctWMBottom; - wdata->rightGuess = correctWMRight; - - /* - * Actual insets account for menubar/warning label, - * so we can't assign directly but must adjust them. - */ - wdata->top += topCorrection; - wdata->left += leftCorrection; - wdata->bottom += bottomCorrection; - wdata->right += rightCorrection; - - awtJNI_ChangeInsets(env, this, wdata); - - /* - * If this window has been sized by a pack() we need - * to keep the interior geometry intact. Since pack() - * computed width and height with wrong insets, we - * must adjust the target dimensions appropriately. - */ - isPacked = (*env)->GetBooleanField(env, target, - componentIDs.isPacked); - if (isPacked) { - int32_t correctTargetW; - int32_t correctTargetH; - - DTRACE_PRINTLN("TL: window is packed, " - "adjusting size to preserve layout"); - - correctTargetW = width + (leftCorrection + rightCorrection); - correctTargetH = height +(topCorrection + bottomCorrection); - - (*env)->SetIntField(env, target, componentIDs.width, - (jint) correctTargetW); - (*env)->SetIntField(env, target, componentIDs.height, - (jint) correctTargetH); - /* - ** Normally you only reconfigure the outerCanvas due to - ** handling the ReconfigureNotify on the innerCanvas. - ** However, in this case the innerCanvas may not have - ** changed, but outterCanvas may still need to, since the - ** insets have changed. - */ - reshape(env, this, wdata, x, y, - correctTargetW, correctTargetH, setXY); - reconfigureOuterCanvas(env, target, this, wdata); - } else { - reshape(env, this, wdata, x, y, width, height, setXY); - JNU_CallMethodByName(env, NULL, this, - "handleResize", "(II)V", width, height); - } - } -/* NEW for dialog */ /* XXX: what this comment is supposed to mean? */ - else { - wdata->need_reshape = False; - /* fix for 4976337 - son@sparc.spb.su */ - /* we should find better fix later if needed */ - if (wdata->isResizable || !wdata->isFixedSizeSet) { - reshape(env, this, wdata, x, y, width, height, setXY); - } - } - } - (*env)->DeleteLocalRef(env, target); - break; - } /* ReparentNotify */ - - case ConfigureNotify: { - DTRACE_PRINTLN2("TL: ConfigureNotify(0x%x/0x%x)", - wdata->winData.shell, XtWindow(wdata->winData.shell)); - - /* - * Some window managers configure before we are reparented and - * the send event flag is set! ugh... (Enlighetenment for one, - * possibly MWM as well). If we haven't been reparented yet - * this is just the WM shuffling us into position. Ignore - * it!!!! or we wind up in a bogus location. - */ - runningWM = awt_wm_getRunningWM(); - if (!wdata->reparented && wdata->isShowing && - runningWM != NO_WM && wdata->decor != AWT_NO_DECOR) { - break; - } - - /* - * Notice that we have seen a ConfigureNotify after being - * reparented. We should really check for it being a - * synthetic event, but metacity doesn't send one. - */ - if (wdata->reparented) - wdata->configure_seen = 1; - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - break; - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - /* - * We can detect the difference between a move and a resize by - * checking the send_event flag on the event; if it's true, - * then it's indeed a move, if it's false, then this is a - * resize and we do not want to process it as a "move" (for - * resizes the x,y values are misleadingly set to 0,0 and so - * just checking for an x,y delta won't work). - */ - - getTargetX = (*env)->GetIntField(env, target, componentIDs.x); - getTargetY = (*env)->GetIntField(env, target, componentIDs.y); - - DTRACE_PRINTLN2("TL: target thinks (%d, %d)", - getTargetX, getTargetY); - DTRACE_PRINTLN3("TL: event is (%d, %d)%s", - event->xconfigure.x, event->xconfigure.y, - (event->xconfigure.send_event ? " synthetic" : "")); - - /* - * N.B. The wdata top offset is the offset from the outside of - * the entire (bordered window) to the inner/parent drawing - * area (canvas), NOT to the shell. Thus, if a menubar is - * present and/or a warning window at the top (not NETSCAPE), - * the top offset will also include space for these. In order - * to position the abstract java window relative to the shell, - * we must add back in the appropriate space for these when we - * subtract off the wdata top field. - */ -#ifdef NETSCAPE - wwHeight = 0; -#else /* NETSCAPE */ - if (wdata->warningWindow != NULL) - wwHeight = wdata->wwHeight; - else - wwHeight = 0; -#endif /* NETSCAPE */ - topAdjust = wdata->mbHeight + wwHeight; - - /* - * Coordinates in Component.setLocation() are treated as the - * upper-left corner of the outer shell. The x and y in the - * ConfigureNotify event, however, are the upper-left corner - * of the inset CLIENT window. Therefore, the coordinates - * from the event are massaged using the inset values in order - * to determine if the top-level shell has moved. In the - * event of a user- generated move event (i.e. dragging the - * window itself), these coordinates are written back into the - * Window object. - * - * Neat X/CDE/Native bug: - * If an attempt is made to move the shell in the y direction - * by an amount equal to the top inset, the Window isn't - * moved. This can be seen here by examining event->xconfigure.y - * before and after such a request is made: the value remains - * unchanged. This wrecks a little havoc here, as the x and y - * in the Component have already been set to the new location - * (in Component.reshape()), but the Window doesn't end up in - * the new location. What's more, if a second request is - * made, the window will be relocated by TWICE the requested - * amount, sort of "catching up" it would seem. - * - * For a test case of this, see bug 4234645. - */ - setTargetX = event->xconfigure.x - wdata->left; - setTargetY = event->xconfigure.y - wdata->top + topAdjust; - - width = (*env)->GetIntField(env, target, componentIDs.width); - height = (*env)->GetIntField(env, target, componentIDs.height); - checkNewXineramaScreen(env, this, wdata, setTargetX, setTargetY, - width, height); - - if ((getTargetX != setTargetX || getTargetY != setTargetY) - && (event->xconfigure.send_event || runningWM == NO_WM)) - { - (*env)->SetIntField(env, target, componentIDs.x, (jint)setTargetX); - (*env)->SetIntField(env, target, componentIDs.y, (jint)setTargetY); -#ifdef _pauly_debug - fprintf(stdout, " ++ shell move. Xevent x,y: %d, %d.\n", - event->xconfigure.x, event->xconfigure.y); - fprintf(stdout, " shell move. left: %d, top: %d, but offset: %d\n", wdata->left, wdata->top, topAdjust); - fprintf(stdout," shell move. target x: %d, target y: %d\n", setTargetX, setTargetY); - fprintf(stdout," shell move. ww height: %d\n", wwHeight); - fflush(stdout); -#endif /* _pauly_debug */ - - DTRACE_PRINTLN2("TL: handleMoved(%d, %d)", - setTargetX, setTargetY); - JNU_CallMethodByName(env, NULL, - this, "handleMoved", "(II)V", - setTargetX, setTargetY); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - else if (event->xconfigure.send_event == False) { -#ifdef _pauly_debug - fprintf(stdout, - " ++ shell resize. Xevent x,y,w,h: %d, %d, %d, %d.\n", - event->xconfigure.x, event->xconfigure.y, - event->xconfigure.width, event->xconfigure.height); - fflush(stdout); -#endif /* _pauly_debug */ - - wdata->shellResized = True; - } - - - (*env)->DeleteLocalRef(env, target); - raiseInputMethodWindow(wdata); -#ifdef __linux__ - adjustStatusWindow(wdata->winData.shell); -#endif - break; - } /* ConfigureNotify */ - - default: - break; - } -} - - -static void -Frame_quit(Widget w, - XtPointer client_data, - XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - JNU_CallMethodByName(env, NULL, (jobject) client_data, "handleQuit", "()V"); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - - -static void -setDeleteCallback(jobject this, struct FrameData *wdata) -{ - Atom xa_WM_DELETE_WINDOW; - Atom xa_WM_TAKE_FOCUS; - Atom xa_WM_PROTOCOLS; - - XtVaSetValues(wdata->winData.shell, - XmNdeleteResponse, XmDO_NOTHING, - NULL); - xa_WM_DELETE_WINDOW = XmInternAtom(XtDisplay(wdata->winData.shell), - "WM_DELETE_WINDOW", False); - xa_WM_TAKE_FOCUS = XmInternAtom(XtDisplay(wdata->winData.shell), - "WM_TAKE_FOCUS", False); - xa_WM_PROTOCOLS = XmInternAtom(XtDisplay(wdata->winData.shell), - "WM_PROTOCOLS", False); - - XmAddProtocolCallback(wdata->winData.shell, - xa_WM_PROTOCOLS, - xa_WM_DELETE_WINDOW, - Frame_quit, (XtPointer) this); -} - - -extern AwtGraphicsConfigDataPtr -copyGraphicsConfigToPeer(JNIEnv *env, jobject this); - -extern AwtGraphicsConfigDataPtr -getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject this); - -// Returns true if this shell has some transient shell chidlren -// which are either Dialogs or Windows. -// Returns false otherwise. -Boolean hasTransientChildren(Widget shell) { - int childIndex; - - // Enumerate through the popups - for (childIndex = 0; childIndex < shell->core.num_popups; childIndex++) { - Widget childShell = shell->core.popup_list[childIndex]; - // Find all transient shell which are either Dialog or Window - if (XtIsTransientShell(childShell)) { - Widget toplevel = findTopLevelByShell(childShell); - if (toplevel != NULL) { - // It is Dialog or Window - return true. - return True; - } - } - } - return False; -} - -extern Widget grabbed_widget; -/** - * Disposes top-level component and its widgets - */ -static -void disposeTopLevel(JNIEnv * env, jobject this) { - - struct FrameData *wdata; - Widget parentShell; - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->mainWindow == NULL - || wdata->winData.shell == NULL) - { - /* do nothing */ - return; - } - - // Save parent shell for later disposal. - parentShell = XtParent(wdata->winData.shell); - - removeTopLevel(wdata); - if (wdata->isInputMethodWindow) { - removeInputMethodWindow(wdata); - } - - XtRemoveEventHandler(wdata->focusProxy, FocusChangeMask, - False, shellEH, this); - XtUnmanageChild(wdata->focusProxy); - awt_util_consumeAllXEvents(wdata->focusProxy); - awt_util_cleanupBeforeDestroyWidget(wdata->focusProxy); - XtDestroyWidget(wdata->focusProxy); - - XtUnmanageChild(wdata->winData.comp.widget); - awt_delWidget(wdata->winData.comp.widget); - awt_util_consumeAllXEvents(wdata->winData.comp.widget); - awt_util_cleanupBeforeDestroyWidget(wdata->winData.comp.widget); - XtDestroyWidget(wdata->winData.comp.widget); - - XtUnmanageChild(wdata->mainWindow); - awt_util_consumeAllXEvents(wdata->mainWindow); - awt_util_consumeAllXEvents(wdata->winData.shell); - XtDestroyWidget(wdata->mainWindow); - XtDestroyWidget(wdata->winData.shell); - if (wdata->iconPixmap) { - XFreePixmap(awt_display, wdata->iconPixmap); - } - - if (grabbed_widget == wdata->winData.shell) { - XUngrabPointer(awt_display, CurrentTime); - XUngrabKeyboard(awt_display, CurrentTime); - grabbed_widget = NULL; - } - - free((void *) wdata); - - (*env)->SetLongField(env, this, mComponentPeerIDs.pData, 0); - awtJNI_DeleteGlobalRef(env, this); - - // Check if parent shell was scheduled for disposal. - // If it doesn't have window then we have to dispose it - // by ourselves right now. - // We can dispose shell only if it doesn't have "transient" children. - { - struct FrameData *pdata; - struct WidgetInfo* winfo; - Widget toplevel = findTopLevelByShell(parentShell); - if (toplevel == NULL) { - // Has already been deleted or it is top shell - return; - } - winfo = findWidgetInfo(toplevel); - DASSERT(winfo != NULL); - if (winfo == NULL) { - // Huh - has already been deleted? - return; - } - pdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, winfo->peer, mComponentPeerIDs.pData); - DASSERT(pdata != NULL); - if (pdata == NULL) { - // Huh - has already been deleted? - return; - } - // 1) scheduled 2) no children 3) no window - if (pdata->isDisposeScheduled - && !hasTransientChildren(parentShell) - && XtWindow(parentShell) == None) - { - disposeTopLevel(env, winfo->peer); - } - } -} - - -/** - * Property change listener. Listens to _XA_JAVA_DISPOSE_PROPERTY_ATOM, - * disposes the top-level when this property has been changed. - */ -static void -shellDisposeNotifyHandler(Widget w, XtPointer client_data, - XEvent* event, Boolean* continue_to_dispatch) { - struct FrameData *wdata; - - *continue_to_dispatch = True; - - if (event->type == PropertyNotify && - event->xproperty.atom == _XA_JAVA_DISPOSE_PROPERTY_ATOM) - { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, (jobject)client_data, - mComponentPeerIDs.pData); - if (wdata != NULL && wdata->isDisposeScheduled) { - disposeTopLevel(env, (jobject)client_data); - - // We've disposed top-level, no more actions on it - *continue_to_dispatch = False; - } - } -} - -/** - * Schedules top-level for later dispose - when all events - * on it will be processed. - */ -static -void scheduleDispose(JNIEnv * env, jobject peer) { - - struct FrameData *wdata; - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, peer, mComponentPeerIDs.pData); - - if (wdata->isDisposeScheduled) { - return; - } - - wdata->isDisposeScheduled = True; - if (XtWindow(wdata->winData.shell) != None) { - XChangeProperty(awt_display, XtWindow(wdata->winData.shell), - _XA_JAVA_DISPOSE_PROPERTY_ATOM, XA_ATOM, 32, PropModeAppend, - (unsigned char *)"", 0); - XFlush(awt_display); - XSync(awt_display, False); - } else { - // If this top-level has children which are still visible then - // their disposal could have been scheduled. We shouldn't allow this widget -// to destroy its children top-levels. For this purpose we postpone the disposal - // of this toplevel until after all its children are disposed. - if (!hasTransientChildren(wdata->winData.shell)) { - disposeTopLevel(env, peer); - } - } -} - - -/* sun_awt_motif_MWindowPeer_pCreate() is native (X/Motif) create routine */ -static char* focusProxyName = "FocusProxy"; - -Widget createFocusProxy(jobject globalRef, Widget parent) { - Widget proxy; -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - int32_t argc; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - if (parent == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return NULL; - } - argc = 0; - XtSetArg(args[argc], XmNwidth, 1); - argc++; - XtSetArg(args[argc], XmNheight, 1); - argc++; - XtSetArg(args[argc], XmNx, -1); - argc++; - XtSetArg(args[argc], XmNy, -1); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNspacing, 0); - argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); - argc++; - - DASSERT(!(argc > MAX_ARGC)); - proxy = XmCreateDrawingArea(parent, focusProxyName, args, argc); - XtAddEventHandler(proxy, - FocusChangeMask, - False, shellEH, globalRef); - XtManageChild(proxy); -#undef MAX_ARGC - return proxy; -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pCreate - * Signature: (Lsun/awt/motif/MComponentPeer;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pCreate(JNIEnv *env, jobject this, - jobject parent, jstring target_class_name, jboolean isFocusableWindow) -{ -#define MAX_ARGC 50 - Arg args[MAX_ARGC]; - int32_t argc; - struct FrameData *wdata; - struct FrameData *pdata = NULL; - char *shell_name = NULL; - WidgetClass shell_class; - Widget parent_widget; - jobject target; - jobject insets; - jobject winAttr; - jstring warningString; - jboolean resizable; - jboolean isModal; - jboolean initialFocus; - jint state; - jclass clazz; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - - uint32_t runningWM; /* the running Window Manager */ - Widget innerCanvasW; /* form's child, parent of the - outer canvas (drawing area) */ - Position x,y; - Dimension w,h; - AwtGraphicsConfigDataPtr adata; - AwtGraphicsConfigDataPtr defConfig; - jobject gd = NULL; - jobject gc = NULL; - char *cname = NULL; - jstring jname; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "null target"); - AWT_UNLOCK(); - return; - } - - wdata = ZALLOC(FrameData); - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, wdata); - if (wdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - - adata = copyGraphicsConfigToPeer(env, this); - defConfig = getDefaultConfig(adata->awt_visInfo.screen); - - - /* Retrieve the specified characteristics for this window */ - winAttr = (*env)->GetObjectField(env, this, mWindowPeerIDs.winAttr); - resizable = (*env)->GetBooleanField( env, - winAttr, - mWindowAttributeIDs.isResizable); - state = (*env)->GetIntField( env, - winAttr, - mWindowAttributeIDs.initialState); - initialFocus = (*env)->GetBooleanField( env, - winAttr, - mWindowAttributeIDs.initialFocus); - - /* As of today decor is either on or off... except the InputMethodWindow */ - if ((*env)->GetBooleanField(env, winAttr, mWindowAttributeIDs.nativeDecor)) { - wdata->decor = (*env)->GetIntField(env, winAttr, mWindowAttributeIDs.decorations); - } else { - wdata->decor = AWT_NO_DECOR; - } - - insets = (*env)->GetObjectField(env, this, mWindowPeerIDs.insets); - - /* The insets will be corrected upon the reparent - event in shellEH(). For now, use bogus values. */ - wdata->top = (*env)->GetIntField(env, insets, insetsIDs.top); - wdata->left = (*env)->GetIntField(env, insets, insetsIDs.left); - wdata->bottom = (*env)->GetIntField(env, insets, insetsIDs.bottom); - wdata->right = (*env)->GetIntField(env, insets, insetsIDs.right); - awt_Frame_guessInsets(wdata); - awtJNI_ChangeInsets(env, this, wdata); - wdata->reparented = False; - wdata->configure_seen = False; - x = (*env)->GetIntField(env, target, componentIDs.x) + wdata->left; - y = (*env)->GetIntField(env, target, componentIDs.y) + wdata->top; - - w = (*env)->GetIntField(env, target, componentIDs.width) - - (wdata->left + wdata->right); - h = (*env)->GetIntField(env, target, componentIDs.height) - - (wdata->top + wdata->bottom); - if (w < 0) w = 0; - if (h < 0) h = 0; - - DTRACE_PRINTLN1("TL: pCreate: state = 0x%X", state); - - wdata->isModal = 0; - wdata->initialFocus = (Boolean)initialFocus; - wdata->isShowing = False; - wdata->shellResized = False; - wdata->canvasResized = False; - wdata->menuBarReset = False; - wdata->need_reshape = False; - wdata->focusProxy = NULL; -#ifdef __linux__ - wdata->fixInsets = True; -#endif - wdata->state = state; - - /* initialize screen to screen number in GraphicsConfig's device */ - /* can the Window's GC ever be null? */ - gc = (*env)->GetObjectField(env, target, componentIDs.graphicsConfig); - DASSERT(gc); - - gd = (*env)->GetObjectField(env, gc, x11GraphicsConfigIDs.screen); - DASSERT(gd); - - wdata->screenNum = (*env)->GetIntField(env, gd, x11GraphicsDeviceIDs.screen); - - wdata->isFocusableWindow = (Boolean)isFocusableWindow; - - /* - * Create a top-level shell widget. - */ - argc = 0; - XtSetArg(args[argc], XmNsaveUnder, False); argc++; - if (resizable) { - XtSetArg(args[argc], XmNallowShellResize, True); argc++; - } else { - XtSetArg(args[argc], XmNallowShellResize, False); argc++; - } - XtSetArg(args[argc], XmNvisual, defConfig->awt_visInfo.visual); argc++; - XtSetArg(args[argc], XmNcolormap, defConfig->awt_cmap); argc++; - XtSetArg(args[argc], XmNdepth, defConfig->awt_depth); argc++; - XtSetArg(args[argc], XmNmappedWhenManaged, False); argc++; - XtSetArg(args[argc], XmNx, x); argc++; - XtSetArg(args[argc], XmNy, y); argc++; - XtSetArg(args[argc], XmNwidth, w); argc++; - XtSetArg(args[argc], XmNheight, h); argc++; - - XtSetArg(args[argc], XmNbuttonFontList, getMotifFontList()); argc++; - XtSetArg(args[argc], XmNlabelFontList, getMotifFontList()); argc++; - XtSetArg(args[argc], XmNtextFontList, getMotifFontList()); argc++; - - XtSetArg(args[argc], XmNmwmDecorations, wdata->decor); argc++; - XtSetArg(args[argc], XmNscreen, - ScreenOfDisplay(awt_display, defConfig->awt_visInfo.screen)); argc++; - - if (wdata->initialFocus == False || !isFocusableWindowByPeer(env, this)) { - XtSetArg(args[argc], XmNinput, False); argc++; - } - - if (wdata->decor == AWT_NO_DECOR) { - /* this is heinous but it can not be avoided for now. - ** this is the only known way to eliminate all decorations - ** for openlook, which btw, is a bug as ol theoretically - ** supports MWM_HINTS - */ -#ifndef DO_FULL_DECOR - if (awt_wm_getRunningWM() == OPENLOOK_WM) { - XtSetArg(args[argc], XmNoverrideRedirect, True); - argc++; - } -#endif - } - - /* 4334958: Widget name is set to the Java class name */ - shell_name = - (char *)JNU_GetStringPlatformChars(env, target_class_name, NULL); - - if (parent) { - pdata = (struct FrameData *) - (*env)->GetLongField(env, parent, mComponentPeerIDs.pData); - } - - /* Parenting tells us whether we wish to be transient or not */ - if (pdata == NULL) { - if (!shell_name) - shell_name = "AWTapp"; - shell_class = topLevelShellWidgetClass; - parent_widget = awt_root_shell; - } - else { - if (!shell_name) - shell_name = "AWTdialog"; - shell_class = transientShellWidgetClass; - parent_widget = pdata->winData.shell; - XtSetArg(args[argc], XmNtransient, True); argc++; - XtSetArg(args[argc], XmNtransientFor, parent_widget); argc++; - - /* Fix Forte Menu Bug. If Window name is "###overrideRedirect###", - * then set XmNoverrideRedirect to prevent Menus from getting focus. - * In JDK 1.2.2 we created Windows as xmMenuShellWidgetClass, - * so we did not need to do this. Swing DefaultPopupFactory's - * createHeavyWeightPopup sets Window name to "###overrideRedirect###". - */ - /** - * Fix for 4476629. Allow Swing to create heavyweight popups which will - * not steal focus from Frame. - */ - jname = (*env)->GetObjectField(env, target, componentIDs.name); - if (!JNU_IsNull(env, jname)) { - cname = (char *)JNU_GetStringPlatformChars(env, jname, NULL); - } - if ( (cname != NULL && strcmp(cname, "###overrideRedirect###") == 0) - || (!isFrameOrDialog(target, env) - && !isFocusableWindowByPeer(env, this) - ) - ) - { /* mbron */ - XtSetArg(args[argc], XmNoverrideRedirect, True); - argc++; - } - if (cname) { - JNU_ReleaseStringPlatformChars(env, jname, (const char *) cname); - } - (*env)->DeleteLocalRef(env, jname); - } - DASSERT(!(argc > MAX_ARGC)); - wdata->winData.shell = XtCreatePopupShell(shell_name, shell_class, - parent_widget, args, argc); - if (shell_name) { - JNU_ReleaseStringPlatformChars(env, target_class_name, shell_name); - } - -#ifdef DEBUG - /* Participate in EditRes protocol to facilitate debugging */ - XtAddEventHandler(wdata->winData.shell, (EventMask)0, True, - _XEditResCheckMessages, NULL); -#endif - - setDeleteCallback(globalRef, wdata); - - /* Establish resizability. For the case of not resizable, do not - yet set a fixed size here; we must wait until in the routine - sun_awt_motif_MWindowPeer_pReshape() after insets have been fixed. - This is because correction of the insets may affect shell size. - (See comments in shellEH() concerning correction of the insets. */ - /* - * Fix for BugTraq ID 4313607. - * Initial resizability will be set later in MWindowPeer_setResizable() - * called from init(). - */ - wdata->isResizable = True; - wdata->isFixedSizeSet = False; - - XtAddEventHandler(wdata->winData.shell, - (StructureNotifyMask | PropertyChangeMask - | VisibilityChangeMask), - False, shellEH, globalRef); - - XtAddEventHandler(wdata->winData.shell, - FocusChangeMask, - False, shellFocusEH, globalRef); - - - /** - * Installing property change handler for DISPOSE property. - * This property will be changed when we need to dispose the whole - * top-level. The nature of PropertyNotify will guarantee that it is - * the latest event on the top-level so we can freely dispose it. - */ - wdata->isDisposeScheduled = False; - if (_XA_JAVA_DISPOSE_PROPERTY_ATOM == 0) { - _XA_JAVA_DISPOSE_PROPERTY_ATOM = XInternAtom(awt_display, "_SUNW_JAVA_AWT_DISPOSE", False); - } - XtAddEventHandler(wdata->winData.shell, PropertyChangeMask, False, - shellDisposeNotifyHandler, globalRef); - - /* - * Create "main" form. - */ - argc = 0; - XtSetArg(args[argc], XmNmarginWidth, 0); argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); argc++; - XtSetArg(args[argc], XmNhorizontalSpacing, 0); argc++; - XtSetArg(args[argc], XmNverticalSpacing, 0); argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); argc++; - - XtSetArg(args[argc], XmNbuttonFontList, getMotifFontList()); argc++; - XtSetArg(args[argc], XmNlabelFontList, getMotifFontList()); argc++; - XtSetArg(args[argc], XmNtextFontList, getMotifFontList()); argc++; - - DASSERT(!(argc > MAX_ARGC)); - wdata->mainWindow = XmCreateForm(wdata->winData.shell, "main", args, argc); - - /* The widget returned by awt_canvas_create is a drawing area - (i.e., canvas) which is the child of another drawing area - parent widget. The parent is the drawing area within the - form just created. The child is an drawing area layer over - the entire frame window, including the form, any menu bar - and warning windows present, and also window manager stuff. - The top, bottom, left, and right fields in wdata maintain - the respective offsets between these two drawing areas. */ - - wdata->winData.comp.widget = awt_canvas_create((XtPointer)globalRef, - wdata->mainWindow, - "frame_", - -1, - -1, - True, - wdata, - adata); - XtAddCallback(wdata->winData.comp.widget, - XmNresizeCallback, outerCanvasResizeCB, - globalRef); - - innerCanvasW = XtParent(wdata->winData.comp.widget); - XtVaSetValues(innerCanvasW, - XmNleftAttachment, XmATTACH_FORM, - XmNrightAttachment, XmATTACH_FORM, - NULL); - - XtAddEventHandler(innerCanvasW, StructureNotifyMask, FALSE, - innerCanvasEH, globalRef); - - wdata->focusProxy = createFocusProxy((XtPointer)globalRef, - wdata->mainWindow); - - /* No menu bar initially */ - wdata->menuBar = NULL; - wdata->mbHeight = 0; - - /* If a warning window (string) is needed, establish it now.*/ - warningString = - (*env)->GetObjectField(env, target, windowIDs.warningString); - if (!JNU_IsNull(env, warningString) ) { - char *wString; - /* Insert a warning window. It's height can't be set yet; - it will later be set in setMbAndWwHeightAndOffsets().*/ - wString = (char *) JNU_GetStringPlatformChars(env, warningString, NULL); - wdata->warningWindow = awt_util_createWarningWindow(wdata->mainWindow, wString); - JNU_ReleaseStringPlatformChars(env, warningString, (const char *) wString); - - wdata->wwHeight = 0; - XtVaSetValues(wdata->warningWindow, - XmNleftAttachment, XmATTACH_FORM, - XmNrightAttachment, XmATTACH_FORM, - NULL); - -#ifdef NETSCAPE - /* For NETSCAPE, warning window is at bottom of the form*/ - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_FORM, - NULL); - XtVaSetValues(wdata->warningWindow, - XmNtopAttachment, XmATTACH_WIDGET, - XmNtopWidget, innerCanvasW, - XmNbottomAttachment, XmATTACH_FORM, - NULL); -#else /* NETSCAPE */ - /* Otherwise (not NETSCAPE), warning is at top of form */ - XtVaSetValues(wdata->warningWindow, - XmNtopAttachment, XmATTACH_FORM, - NULL); - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_WIDGET, - XmNtopWidget, wdata->warningWindow, - XmNbottomAttachment, XmATTACH_FORM, - NULL); -#endif /* NETSCAPE */ - - } else { - /* No warning window present */ - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_FORM, - XmNbottomAttachment, XmATTACH_FORM, - NULL); - wdata->warningWindow = NULL; - wdata->wwHeight = 0; - } - - awt_util_show(wdata->winData.comp.widget); - - AWT_FLUSH_UNLOCK(); - - addTopLevel(wdata); - - /* Check whether this is an instance of InputMethodWindow or not */ - if (inputMethodWindowClass == NULL) { - jclass localClass = (*env)->FindClass(env, "sun/awt/im/InputMethodWindow"); - inputMethodWindowClass = (jclass)(*env)->NewGlobalRef(env, localClass); - (*env)->DeleteLocalRef(env, localClass); - } - if ((*env)->IsInstanceOf(env, target, inputMethodWindowClass)) { - wdata->isInputMethodWindow = True; - addInputMethodWindow(wdata); - } -} /* MWindowPeer_pCreate() */ - - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pSetTitle - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pSetTitle(JNIEnv *env, jobject this, - jstring title) -{ - char *ctitle; - char *empty_string = " "; - struct FrameData *wdata; - XTextProperty text_prop; - char *c[1]; - int32_t conv_result; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "null wdata or shell"); - AWT_UNLOCK(); - return; - } - - /* TODO: uwe: set _NET_WM_NAME property to utf-8 name */ - - ctitle = (JNU_IsNull(env, title)) ? empty_string - : (char *) JNU_GetStringPlatformChars(env, title, NULL); - - if (strcmp(ctitle, "") == 0) - ctitle = empty_string; - - c[0] = ctitle; - - /* need to convert ctitle to CompoundText */ - conv_result = XmbTextListToTextProperty(awt_display, c, 1, - XStdICCTextStyle, - &text_prop); - - /* - * XmbTextListToTextProperty returns value that is greater - * than Success if the supplied text is not fully convertible - * to specified encoding. In this case, the return value is - * the number of inconvertible characters. But convertibility - * is guaranteed for XCompoundTextStyle, so it will actually - * never be greater than Success. Errors handled below are - * represented by values that are lower than Success. - */ - if (conv_result >= Success) { - XtVaSetValues(wdata->winData.shell, - XmNtitle, text_prop.value, - XmNtitleEncoding, text_prop.encoding, - XmNiconName, text_prop.value, - XmNiconNameEncoding, text_prop.encoding, - XmNname, ctitle, - NULL); - } - - if (ctitle != empty_string) - JNU_ReleaseStringPlatformChars(env, title, (const char *) ctitle); - - if (conv_result == XNoMemory) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - if (conv_result == XLocaleNotSupported) { - JNU_ThrowInternalError(env, "Current locale is not supported"); - AWT_UNLOCK(); - return; - } - - XFree(text_prop.value); - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pToFront - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pToFront(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - jobject target; - Window shellWindow; - Boolean autoRequestFocus; - Boolean isModal = FALSE; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL - || wdata->winData.comp.widget == NULL - || wdata->winData.shell == NULL - || wdata->mainWindow == NULL - || JNU_IsNull(env, target)) - { - JNU_ThrowNullPointerException(env, "null widget/target data"); - AWT_UNLOCK(); - return; - } - - if ((shellWindow = XtWindow(wdata->winData.shell)) != None) { - XRaiseWindow(awt_display, shellWindow); - - autoRequestFocus = (*env)->GetBooleanField(env, target, windowIDs.isAutoRequestFocus); - - if (isDialog(target, env)) { - isModal = (*env)->GetBooleanField(env, target, dialogIDs.modal); - } - - // In contrast to XToolkit/WToolkit modal dialog can be unfocused. - // So we should also ask for modality in addition to 'autoRequestFocus'. - if (wdata->isFocusableWindow && (autoRequestFocus || isModal)) { - XSetInputFocus(awt_display, XtWindow(wdata->focusProxy), RevertToPointerRoot, CurrentTime); - } - } - - (*env)->DeleteLocalRef(env, target); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pShow - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pShow(JNIEnv *env, jobject this) -{ - Java_sun_awt_motif_MWindowPeer_pShowModal(env, this, JNI_FALSE); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pShowModal - * Signature: (Z)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pShowModal(JNIEnv *env, jobject this, - jboolean isModal) -{ - struct FrameData *wdata; - Boolean iconic; - jobject target; - Boolean locationByPlatform; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL - || wdata->winData.comp.widget == NULL - || wdata->winData.shell == NULL - || wdata->mainWindow == NULL - || (wdata->winData.flags & W_IS_EMBEDDED) - || JNU_IsNull(env, target)) - { - JNU_ThrowNullPointerException(env, "null widget/target data"); - AWT_UNLOCK(); - return; - } - - DTRACE_PRINTLN2("TL: pShowModal(modal = %s) state = 0x%X", - isModal ? "true" : "false", - wdata->state); - - wdata->isModal = isModal; - - /* - * A workaround for bug 4062589 that is really a motif problem - * (see bug 4064803). Before popping up a modal dialog, if a - * pulldown menu has the input focus (i.e. user has pulled the - * menu down), we send a fake click event and make sure the click - * event is processed. With this simulation of user clicking, X - * server will not get confused about the modality and a - * subsequent click on the popup modal dialog will not cause - * system lockup. - */ - if (wdata->isModal && awt_util_focusIsOnMenu(awt_display) - && awt_util_sendButtonClick(awt_display, InputFocus)) - { - for (;;) { - XEvent ev; - XtAppPeekEvent(awt_appContext, &ev); - if ((ev.type == ButtonRelease) - && (*(XButtonEvent *)&ev).send_event) - { - XtAppProcessEvent(awt_appContext, XtIMAll); - break; - } else { - XtAppProcessEvent(awt_appContext, XtIMAll); - } - } - } - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - // 4488209: kdm@sparc.spb.su - // wdata->isShowing is True when toFront calls pShow. - // We do not need to do some things if wdata->isShowing is True. - if (!wdata->isShowing) { - XtVaSetValues(wdata->winData.comp.widget, - XmNx, -(wdata->left), - XmNy, -(wdata->top), - NULL); - - /* But see below! */ - iconic = (wdata->state & java_awt_Frame_ICONIFIED) ? True : False; - XtVaSetValues(wdata->winData.shell, - XmNinitialState, iconic ? IconicState : NormalState, - NULL); - - if (wdata->menuBar != NULL) { - awt_util_show(wdata->menuBar); - } - XtManageChild(wdata->mainWindow); - XtRealizeWidget(wdata->winData.shell); /* but not map it yet */ - -/* fprintf(stderr, "*** proxy window %x\n", XtWindow(wdata->focusProxy)); */ - XStoreName(awt_display, XtWindow(wdata->focusProxy), "FocusProxy"); - /* - * Maximization and other stuff that requires a live Window to set - * properties on to communicate with WM. - */ - awt_wm_setExtendedState(wdata, wdata->state); - awt_wm_setShellDecor(wdata, wdata->isResizable); - - if (wdata->isModal) { - removePopupMenus(); -#ifndef NOMODALFIX - /* - * Fix for 4078176 Modal dialogs don't act modal - * if addNotify() is called before setModal(true). - * Moved from Java_sun_awt_motif_MDialogPeer_create. - */ - if (!wdata->callbacksAdded) { - XtAddCallback(wdata->winData.shell, - XtNpopupCallback, awt_shellPoppedUp, - NULL); - XtAddCallback(wdata->winData.shell, - XtNpopdownCallback, awt_shellPoppedDown, - NULL); - wdata->callbacksAdded = True; - } -#endif /* !NOMODALFIX */ - /* - * Set modality on the Shell, not the BB. The BB expects that - * its parent is an xmDialogShell, which as the result of - * coalescing is now a transientShell... This has resulted in - * a warning message generated under fvwm. The shells are - * virtually identical and a review of Motif src suggests that - * setting dialog style on BB is a convenience not functional - * for BB so set Modality on shell, not the BB(form) widget. - */ - XtVaSetValues(wdata->winData.shell, - XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, - NULL); - XtManageChild(wdata->winData.comp.widget); - } - else { /* not modal */ - XtVaSetValues(wdata->winData.shell, - XmNmwmInputMode, MWM_INPUT_MODELESS, NULL); - XtManageChild(wdata->winData.comp.widget); - XtSetMappedWhenManaged(wdata->winData.shell, True); - } - if (wdata->isResizable) { - /* REMINDER: uwe: will need to revisit for setExtendedStateBounds */ - awt_wm_removeSizeHints(wdata->winData.shell, PMinSize|PMaxSize); - } - locationByPlatform = - (*env)->GetBooleanField(env, target, windowIDs.locationByPlatform); - if (locationByPlatform) { - awt_wm_removeSizeHints(wdata->winData.shell, USPosition|PPosition); - } - } - - /* - * 4261047: always pop up with XtGrabNone. Motif notices the - * modal input mode and perform the grab for us, doing its - * internal book-keeping as well. - */ - XtPopup(wdata->winData.shell, XtGrabNone); - wdata->isShowing = True; - - wdata->initialFocus = (*env)->GetBooleanField(env, target, windowIDs.isAutoRequestFocus); - - if (wdata->isFocusableWindow) { - if (wdata->initialFocus || wdata->isModal) { - focusOnMapNotify = True; - } else { - XtVaSetValues(wdata->winData.shell, XmNinput, False, NULL); - } - } - - (*env)->DeleteLocalRef(env, target); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: getState - * Signature: ()I - */ -JNIEXPORT jint JNICALL -Java_sun_awt_motif_MWindowPeer_getState(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - jint state; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return java_awt_Frame_NORMAL; - } - - state = wdata->state; - - AWT_FLUSH_UNLOCK(); - return state; -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: setState - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_setState(JNIEnv *env, jobject this, - jint state) -{ - struct FrameData *wdata; - Widget shell; - Window shell_win; - jint changed; - Boolean changeIconic, iconic; - - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - shell = wdata->winData.shell; - shell_win = XtWindow(shell); - - DTRACE_PRINTLN4("TL: setState(0x%x/0x%x, 0x%X -> 0x%X)", - shell, shell_win, - wdata->state, state); - - if (!wdata->isShowing) { - /* - * Not showing, so just record requested state; pShow will set - * initial state hints/properties appropriately before poping - * us up again. - */ - DTRACE_PRINTLN("TL: NOT showing (just record the new state)"); - wdata->state = state; - AWT_UNLOCK(); - return; - } - - /* - * Request the state transition from WM here and do java upcalls - * in shell event handler when WM actually changes our state. - */ - changed = wdata->state ^ state; - - changeIconic = changed & java_awt_Frame_ICONIFIED; - iconic = (state & java_awt_Frame_ICONIFIED) ? True : False; - - if (changeIconic && iconic) { - DTRACE_PRINTLN("TL: set iconic = True"); - XIconifyWindow(XtDisplay(shell), shell_win, - XScreenNumberOfScreen(XtScreen(shell))); - } - - /* - * If a change in both iconic and extended states requested, do - * changes to extended state when we are in iconic state. - */ - if ((changed & ~java_awt_Frame_ICONIFIED) != 0) { - awt_wm_setExtendedState(wdata, state); - } - - if (changeIconic && !iconic) { - DTRACE_PRINTLN("TL: set iconic = False"); - XMapWindow(XtDisplay(shell), shell_win); - } - - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pHide - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pHide(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL - || wdata->winData.comp.widget == NULL - || wdata->winData.shell == NULL) - { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - /** - * Disable proxy mechanism when Window's shell is being hidden - */ - clearFocusPath(wdata->winData.shell); - - wdata->isShowing = False; /* ignore window state events */ - - if (XtIsRealized(wdata->winData.shell)) { - /* XXX: uwe: this is bogus */ - /* - * Make sure we withdraw a window in an unmaximized state, or - * we'll lose out normal bounds (pShow will take care of - * hinting maximization, so when the window is shown again it - * will be correctly shown maximized). - */ - if (wdata->state & java_awt_Frame_MAXIMIZED_BOTH) { - awt_wm_setExtendedState(wdata, - wdata->state & ~java_awt_Frame_MAXIMIZED_BOTH); - } - XtUnmanageChild(wdata->winData.comp.widget); - XtPopdown(wdata->winData.shell); - } - - AWT_FLUSH_UNLOCK(); -} - - -/* sun_awt_motif_MWindowPeer_pReshape() is native (X/Motif) routine that - is called to effect a reposition and / or resize of the target frame. - The parameters x,y,w,h specify target's x, y position, width, height.*/ - -/* - * This functionality is invoked from both java and native code, and - * we only want to lock when invoking it from java, so wrap the native - * method version with the locking. - */ - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pReshape - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_pReshape(JNIEnv *env, jobject this, - jint x, jint y, jint w, jint h) -{ - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - // See if our new location is on a new screen - if (wdata->reparented) { - checkNewXineramaScreen(env, this, wdata, x, y, w, h); - } - - /** - * Fix for 4652685. - * Avoid setting position for embedded frames, since this conflicts with the - * fix for 4419207. We assume that the embedded frame never changes its - * position relative to the parent. - */ - if (wdata->winData.flags & W_IS_EMBEDDED) { - x = 0; - y = 0; - } - - reshape(env, this, wdata, x, y, w, h, True); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MEmbeddedFramePeer - * Method: pReshapePrivate - * Signature: (IIII)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_pReshapePrivate(JNIEnv *env, jobject this, - jint x, jint y, jint w, jint h) -{ - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - reshape(env, this, wdata, x, y, w, h, True); - - AWT_FLUSH_UNLOCK(); -} - -static void -reshape(JNIEnv *env, jobject this, struct FrameData *wdata, - jint x, jint y, jint w, jint h, Boolean setXY) -{ - int32_t topAdjust, /* top adjustment of offset */ - bottomAdjust; /* bottom adjustment of offset */ - int32_t width, /* of X/Motif shell and form */ - height; /* of X/Motif shell and form */ - int32_t w1, h1; - enum wmgr_t wm; /* window manager */ - XWindowAttributes winAttr; - - DTRACE_PRINTLN7("TL: reshape(0x%x/0x%x,\n"/**/ - "TL: x = %d, y = %d, w = %d, h = %d, %s)", - wdata->winData.shell, XtWindow(wdata->winData.shell), - x, y, w, h, - setXY ? "setXY" : "false"); - - wm = awt_wm_getRunningWM(); - - /* Make adjustments in case of a dynamically added/removed menu bar */ - awtJNI_setMbAndWwHeightAndOffsets(env, this, wdata); - -#ifdef _pauly_debug - fprintf(stdout," reshape. offsets - top: %d, bottom: %d, left: %d, right: %d\n", - wdata->top, wdata->bottom, wdata->left, wdata->right); - fflush(stdout); -#endif /* _pauly_debug */ - - /* The abstract java (target) position coordinates (x,y) - are for the bordered window. Eventually(!), the Motif - (shell) coordinates (XmNx, XmNy) will exclude borders. - (This is true only AFTER shell is massaged by the WM.) */ - - /* The abstract java (target) width and height includes any WM - borders. But the Motif width and height excludes WM borders. - The wdata top and bottom fields may include space for menu bar, - warning window, etc. We must adjust by these values for shell. */ - topAdjust = 0; - bottomAdjust = 0; - /* Surprise - do not(!) check for nonNull MenuBar because that can - occur separately (in ...pSetMenubar()) from calculation of the - menu bar height and offsets (in setMbAndWwHeightAndOffsets()). - In any event, the offsets and wdata mbHeight field should jive. */ - topAdjust += wdata->mbHeight; - if (wdata->warningWindow != NULL) { -#ifdef NETSCAPE - bottomAdjust += wdata->wwHeight; -#else /* NETSCAPE */ - topAdjust += wdata->wwHeight; -#endif /* NETSCAPE */ - } - if (wdata->hasTextComponentNative) { - bottomAdjust += wdata->imHeight; - } -#ifdef _pauly_debug - fprintf(stdout," reshape. adjustments - top: %d, bottom: %d\n", topAdjust, bottomAdjust); - fflush(stdout); -#endif /* _pauly_debug */ - - width = w - (wdata->left + wdata->right); - height = h - (wdata->top + wdata->bottom) + (topAdjust + bottomAdjust); - - /* - * Shell size. - * 4033151. If nonpositive size specified (e.g., if no size - * given), establish minimum allowable size. Note: Motif shell - * can not be sized 0. - */ - w1 = (width > 0) ? width : 1; - h1 = (height > 0) ? height : 1; - - if (awt_wm_configureGravityBuggy() /* WM ignores window gravity */ - && wdata->reparented && wdata->isShowing) - { - /* - * Buggy WM places client window at (x,y) ignoring the window - * gravity. All our windows are NorthWestGravity, so adjust - * (x,y) by insets appropriately. - */ - x += wdata->left; - y += wdata->top; - DTRACE_PRINTLN2("TL: work around WM gravity bug: x += %d, y += %d", - wdata->left, wdata->top); - } - - if (wdata->imRemove) { - XtVaSetValues(XtParent(wdata->winData.comp.widget), - XmNheight, (((h - (wdata->top + wdata->bottom)) > 0) ? - (h - (wdata->top + wdata->bottom)) : 1), - NULL); - wdata->imRemove = False; - } - -#if 0 /* XXX: this screws insets calculation under KDE2 in the case of - negative x, y */ - /* - * Without these checks, kwm places windows slightly off the screen, - * when there is a window underneath at (0,0) and empty space below, - * but not to the right. - */ - if (x < 0) x = 0; - if (y < 0) y = 0; -#endif - if ((wdata->winData.flags & W_IS_EMBEDDED) == 0) { - if ((wm == MOTIF_WM) || (wm == CDE_WM)) { - /* - * By default MWM has "usePPosition: nonzero" and so ignores - * windows with PPosition (0,0). Work around (should we???). - */ - if ((x == 0) && (y == 0)) { - x = y = 1; - } - } - } - - if ( wdata->decor == AWT_NO_DECOR ) { - if (setXY) - XtConfigureWidget(wdata->winData.shell, x, y, w1, h1, 0 ); - else - XtResizeWidget(wdata->winData.shell, w1, h1, 0); - } - else { - /* - * 5006248, workaround for OpenLook WM. - * Thread gets stuck at XtVaSetValues call awaiting for first - * ConfigureNotify to come. For OpenLook it looks like a showstopper. - * We put dummy ConfigureNotify to satisfy the requirements. - */ - if (awt_wm_getRunningWM() == OPENLOOK_WM) { - XEvent xev; - xev.xconfigure.type = ConfigureNotify; - xev.xconfigure.display = awt_display; - xev.xconfigure.window = XtWindow(wdata->winData.shell); - xev.xconfigure.event = xev.xconfigure.window; - xev.xconfigure.x = x; - xev.xconfigure.y = y; - xev.xconfigure.height = h1; - xev.xconfigure.width = w1; - xev.xconfigure.serial = NextRequest(awt_display) + 1; // see isMine() Xt inner function code. - - XPutBackEvent(awt_display, &xev); - } - - if (wdata->isResizable) { - XtVaSetValues(wdata->winData.shell, - XmNwidth, w1, - XmNheight, h1, - NULL); - } - else { - /* - * Fix for BugTraq ID 4313607 - call awt_wm_setShellNotResizable - * regardless of wdata->isFixedSizeSet and wdata->reparented values. - */ - DTRACE_PRINTLN("TL: set fixed size from reshape"); - awt_wm_setShellNotResizable(wdata, w1, h1, True); - if (wdata->reparented && (w1 > 0) && (h1 > 0)) { - wdata->isFixedSizeSet = True; - } - } - if (setXY) - XtVaSetValues(wdata->winData.shell, - XmNx, x, - XmNy, y, - NULL); - } - /* inner/parent drawing area (parent is form) */ - h1 = h - (wdata->top + wdata->bottom); - h1 = ( h1 > 0 ) ? h1 : 1; -#if 0 - XtConfigureWidget(XtParent(wdata->winData.comp.widget), - 0, topAdjust, w1, h1, 0 ); -#else - XtVaSetValues(XtParent(wdata->winData.comp.widget), - XmNx, 0, - XmNy, topAdjust, - XmNwidth, w1, - XmNheight, h1, - NULL); -#endif - -#ifdef _pauly_debug - fprintf(stdout," reshape. setting inner canvas to: %d,%d,%d,%d\n", - 0, topAdjust, w1, h1 ); - fflush(stdout); -#endif /* _pauly_debug */ - - wdata->menuBarReset = False; - - /* DTRACE_PRINTLN("TL: reshape -> returning"); */ - return; -} - -/* - * Class: sun_awt_motif_MEmbeddedFramePeer - * Method: getBoundsPrivate - * Signature: ()Ljava/awt/Rectangle - */ -JNIEXPORT jobject JNICALL Java_sun_awt_motif_MEmbeddedFramePeer_getBoundsPrivate - (JNIEnv * env, jobject this) -{ - jobject bounds = NULL; - struct FrameData *cdata; - XWindowAttributes attr; - - AWT_LOCK(); - - cdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (cdata == NULL || cdata->mainWindow == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - if (!XtIsRealized(cdata->mainWindow) || !XtIsRealized(cdata->winData.shell)) { - JNU_ThrowInternalError(env, "widget not visible on screen"); - AWT_UNLOCK(); - return NULL; - } - - memset(&attr, 0, sizeof(XWindowAttributes)); - XGetWindowAttributes(awt_display, XtWindow(cdata->winData.shell), &attr); - - bounds = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V", - (jint)attr.x, (jint)attr.y, (jint)attr.width, (jint)attr.height); - if (((*env)->ExceptionOccurred(env)) || JNU_IsNull(env, bounds)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return NULL; - } - - AWT_UNLOCK(); - - return bounds; -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pDispose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_pDispose -(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || wdata->mainWindow == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (wdata->winData.flags & W_IS_EMBEDDED) { - awt_util_delEmbeddedFrame(wdata->winData.shell); - deinstall_xembed(wdata); - } - scheduleDispose(env, this); - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MFramePeer - * Method: pGetIconSize - * Signature: (II)Z - */ -JNIEXPORT jboolean JNICALL Java_sun_awt_motif_MFramePeer_pGetIconSize -(JNIEnv *env, jobject this, jint widthHint, jint heightHint) -{ - struct FrameData *wdata; - uint32_t width, height, border_width, depth; - Window win; - int32_t x, y; - uint32_t mask; - XSetWindowAttributes attrs; - uint32_t saveWidth = 0; - uint32_t saveHeight = 0; - uint32_t dist = 0xffffffff; - int32_t diff = 0; - int32_t closestWidth; - int32_t closestHeight; - int32_t newDist; - int32_t found = 0; - AwtGraphicsConfigDataPtr adata; - - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return FALSE; - } - XtVaGetValues(wdata->winData.shell, - XmNiconWindow, &win, - NULL); - if (!win) { - int32_t count; - int32_t i; - XIconSize *sizeList; - - adata = getGraphicsConfigFromComponentPeer(env, this); - - if (!XGetIconSizes(awt_display, - RootWindow(awt_display, adata->awt_visInfo.screen), - &sizeList, &count)) { - /* No icon sizes so can't set it -- Should we throw an exception?*/ - /* [jk] I don't think so: simply fall back to 16x16 */ - saveWidth = saveHeight = 16; - goto top; - } - for (i=0; i < count; i++) { - if (widthHint >= sizeList[i].min_width && - widthHint <= sizeList[i].max_width && - heightHint >= sizeList[i].min_height && - heightHint <= sizeList[i].max_height) { - found = 1; - if ((((widthHint-sizeList[i].min_width) - % sizeList[i].width_inc) == 0) && - (((heightHint-sizeList[i].min_height) - % sizeList[i].height_inc) ==0)) { - /* Found an exact match */ - saveWidth = widthHint; - saveHeight = heightHint; - dist = 0; - break; - } - diff = widthHint - sizeList[i].min_width; - if (diff == 0) { - closestWidth = widthHint; - } else { - diff = diff%sizeList[i].width_inc; - closestWidth = widthHint - diff; - } - diff = heightHint - sizeList[i].min_height; - if (diff == 0) { - closestHeight = heightHint; - } else { - diff = diff%sizeList[i].height_inc; - closestHeight = heightHint - diff; - } - newDist = closestWidth*closestWidth + - closestHeight*closestHeight; - if (dist > newDist) { - saveWidth = closestWidth; - saveHeight = closestHeight; - dist = newDist; - } - } - } - - if (!found) { -#if 1 - /* [sbb] this code should work better than the original Solaris - code */ - if (widthHint >= sizeList[0].max_width || - heightHint >= sizeList[0].max_height) { - /* determine which way to scale */ - int32_t wdiff = widthHint - sizeList[0].max_width; - int32_t hdiff = heightHint - sizeList[0].max_height; - if (wdiff >= hdiff) { /* need to scale width more */ - saveWidth = sizeList[0].max_width; - saveHeight = (int32_t)(((double)sizeList[0].max_width/widthHint) * - heightHint); - } else { - saveWidth = (int32_t)(((double)sizeList[0].max_height/heightHint) * - widthHint); - saveHeight = sizeList[0].max_height; - } - } else if (widthHint < sizeList[0].min_width || - heightHint < sizeList[0].min_height) { - saveWidth = (sizeList[0].min_width+sizeList[0].max_width)/2; - saveHeight = (sizeList[0].min_height+sizeList[0].max_height)/2; - } else { /* it fits within the right size */ - saveWidth = widthHint; - saveHeight = heightHint; - } - -#else /* XXX: old Solaris code */ - /* REMIND: Aspect ratio */ - if (widthHint >= sizeList[0].max_width && - heightHint >= sizeList[0].max_height) { - saveWidth = sizeList[0].max_width; - saveHeight = sizeList[0].max_height; - } else if (widthHint >= sizeList[0].min_width && - heightHint >= sizeList[0].min_height) { - saveWidth = sizeList[0].min_width; - saveHeight = sizeList[0].min_height; - } else { - saveWidth = (sizeList[0].min_width+sizeList[0].max_width)/2; - saveHeight = (sizeList[0].min_height+sizeList[0].max_height)/2; - } -#endif - } - free((void *) sizeList); - } else { - Window root; - if (XGetGeometry(awt_display, - win, - &root, - &x, - &y, - (uint32_t *)&saveWidth, - (uint32_t *)&saveHeight, - (uint32_t *)&border_width, - (uint32_t *)&depth)) { - } - } - - top: - (*env)->SetIntField(env, this, mWindowPeerIDs.iconWidth, (jint)saveWidth); - (*env)->SetIntField(env, this, mWindowPeerIDs.iconHeight, (jint)saveHeight); - - AWT_UNLOCK(); - return TRUE; -} - -/* - * Class: sun_awt_motif_MFramePeer - * Method: pSetIconImage - * Signature: ([B[I[SII)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MFramePeer_pSetIconImage___3B_3I_3SII -(JNIEnv *env, jobject this, - jbyteArray jbyteData, jintArray jintData, jshortArray jushortData, - jint iconWidth, jint iconHeight) -{ - struct FrameData *wdata; - Window win; - GC gc; - int32_t x, y; - XImage *dst; - uint32_t mask; - XSetWindowAttributes attrs; - jobject jbuf = NULL; - void *buf = NULL; - int32_t len = 0; - int32_t bpp, slp, bpsl; - AwtGraphicsConfigDataPtr adata; - - if (JNU_IsNull(env, jbyteData)) { - if (JNU_IsNull(env, jintData)) { - if (JNU_IsNull(env, jushortData)) { - /* [jk] Don't throw an exception here, it breaks - * programs that run correctly on Windows - * JNU_ThrowNullPointerException(env, "NullPointerException"); - */ - return; - } else { - jbuf = jushortData; - } - } else { - jbuf = jintData; - } - } else { - jbuf = jbyteData; - len = (*env)->GetArrayLength(env, jbyteData); - } - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - /* REMIND: Need to figure out how to display image on a pixmap */ - - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - adata = getGraphicsConfigFromComponentPeer(env, this); - - /* [jk] we need a new pixmap everytime: - * Test case: src/share/test/awt/FrameTest.html Look at the icon, - * select Operations/Change IconImage, you should see a different - * icon now. - */ - if (wdata->iconPixmap) { - XFreePixmap(awt_display, wdata->iconPixmap); - wdata->iconPixmap = None; - } - - if (wdata->iconPixmap == None) { - if ((wdata->iconPixmap = - XCreatePixmap(awt_display, - RootWindow(awt_display, adata->awt_visInfo.screen), - iconWidth, iconHeight, - adata->awtImage->Depth)) == None) { - /* REMIND: How to warn that there was a problem? */ - AWT_UNLOCK(); - return; - } - wdata->iconWidth = iconWidth; - wdata->iconHeight = iconHeight; - } - - buf = (void *) (*env)->GetPrimitiveArrayCritical(env, jbuf, NULL); - if (jbyteData != NULL) { - int32_t i; - unsigned char *ubuf = (unsigned char *) buf; - /* Need to map from ICM lut to cmap */ - for (i=0; i < len; i++) { - ubuf[i] = (ubuf[i] >= adata->color_data->awt_numICMcolors) - ? 0 - : adata->color_data->awt_icmLUT2Colors[ubuf[i]]; - } - } - - bpp = adata->awtImage->wsImageFormat.bits_per_pixel; - slp = adata->awtImage->wsImageFormat.scanline_pad; - bpsl = paddedwidth(iconWidth * bpp, slp) >> 3; - if (((bpsl << 3) / bpp) < iconWidth) { - (*env)->ReleasePrimitiveArrayCritical(env, jbuf, buf, JNI_ABORT); - AWT_UNLOCK(); - return; - } - dst = XCreateImage(awt_display, adata->awt_visInfo.visual, - adata->awtImage->Depth, ZPixmap, 0, - buf, iconWidth, iconHeight, 32, bpsl); - if (dst == NULL) { - /* REMIND: How to warn that there was a problem? */ - (*env)->ReleasePrimitiveArrayCritical(env, jbuf, buf, JNI_ABORT); - AWT_UNLOCK(); - return; - } - - if ((gc = XCreateGC(awt_display, wdata->iconPixmap, 0, 0)) == NULL) { - XDestroyImage (dst); - (*env)->ReleasePrimitiveArrayCritical(env, jbuf, buf, JNI_ABORT); - AWT_UNLOCK(); - return; - } - - XPutImage(awt_display, wdata->iconPixmap, gc, dst, - 0, 0, 0, 0, iconWidth, iconHeight); - (*env)->ReleasePrimitiveArrayCritical(env, jbuf, buf, JNI_ABORT); - dst->data=NULL; - XDestroyImage(dst); - XFreeGC(awt_display, gc); - - XtVaGetValues(wdata->winData.shell, - XmNiconWindow, &win, - NULL); - if (!win) { - mask = CWBorderPixel | CWColormap | CWBackPixmap; - attrs.border_pixel = awt_defaultFg; - attrs.colormap = adata->awt_cmap; - attrs.background_pixmap = wdata->iconPixmap; - if (!(win = XCreateWindow(awt_display, - RootWindow(awt_display, - adata->awt_visInfo.screen), - 0, 0, iconWidth, iconHeight, - (uint32_t) 0, - adata->awtImage->Depth, - InputOutput, - adata->awt_visInfo.visual, - mask, &attrs))) { - /* Still can't create the window so try setting iconPixmap */ - XtVaSetValues(wdata->winData.shell, - XmNiconPixmap, wdata->iconPixmap, - NULL); - AWT_FLUSH_UNLOCK(); - return; - } - } - - XtVaSetValues(wdata->winData.shell, - XmNiconPixmap, wdata->iconPixmap, - XmNiconWindow, win, - NULL); - - XSetWindowBackgroundPixmap(awt_display, win, wdata->iconPixmap); - XClearWindow(awt_display, win); - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: setResizable - * Signature: (Z)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_setResizable(JNIEnv *env, jobject this, - jboolean resizable) -{ - struct FrameData *wdata; - jobject target; - int32_t targetWidth, - targetHeight; - int32_t width, /* fixed width if not resizable */ - height; /* fixed height if not resizable*/ - int32_t verticalAdjust; /* menubar, warning window, etc.*/ - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL - || wdata->winData.comp.widget == NULL - || wdata->winData.shell == NULL - || JNU_IsNull(env, target)) - { - JNU_ThrowNullPointerException(env, "NullPointerException"); - if (!JNU_IsNull(env, target)) - (*env)->DeleteLocalRef(env, target); - AWT_UNLOCK(); - return; - } - - DTRACE_PRINTLN3("TL: setResizable(0x%x/0x%x, %s)", - wdata->winData.shell, XtWindow(wdata->winData.shell), - resizable ? "true" : "false"); - - if ((!wdata->isResizable) && (resizable)) { - awt_wm_setShellResizable(wdata); - wdata->isFixedSizeSet = False; - } - else if ((wdata->isResizable) && (!resizable)) { - /* - * To calculate fixed window width, height, we must subtract - * off the window manager borders as stored in the wdata - * structure. But note that the wdata top and bottom fields - * may include space for warning window, menubar, IM status; - * this IS part of shell. - */ - verticalAdjust = wdata->mbHeight; - if (wdata->warningWindow != NULL) { - verticalAdjust += wdata->wwHeight; - } - if (wdata->hasTextComponentNative) { - verticalAdjust += wdata->imHeight; - } - - targetWidth = (*env)->GetIntField(env, target, componentIDs.width); - targetHeight = (*env)->GetIntField(env, target, componentIDs.height); - width = targetWidth - (wdata->left + wdata->right); - height = targetHeight - (wdata->top + wdata->bottom) + verticalAdjust; -#ifdef __linux__ - width = (width > 0) ? width : 1; - height = (height > 0) ? height : 1; -#endif - DTRACE_PRINTLN2("TL: setting fixed size %ld x %ld", width, height); - awt_wm_setShellNotResizable(wdata, width, height, False); - if ((width > 0) && (height > 0)) { - wdata->isFixedSizeSet = True; - } - } - - wdata->isResizable = (Boolean)resizable; - - (*env)->DeleteLocalRef(env, target); - AWT_FLUSH_UNLOCK(); -} - - -/* sun_awt_motif_MWindowPeer_pSetMenuBar() is native (X/Motif) routine - which handles insertion or deletion of a menubar from this frame. */ - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: pSetMenuBar - * Signature: (Lsun/awt/motif/MMenuBarPeer;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_pSetMenuBar -(JNIEnv *env, jobject this, jobject mb) -{ - struct FrameData *wdata; - struct ComponentData *mdata; - jobject target; - Widget innerCanvasW; /* Motif inner canvas */ -#ifdef _pauly_debug - Dimension mbHeight; /* Motif menubar height */ -#endif /* _pauly_debug */ - -#ifdef _pauly_debug - fprintf(stdout," ++ ...pSetMenuBar.\n"); - fflush(stdout); -#endif /* _pauly_debug */ - - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (JNU_IsNull(env, target) || wdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - if (!JNU_IsNull(env, target)) { - (*env)->DeleteLocalRef(env, target); - } - AWT_UNLOCK(); - return; - } - - if (mb == NULL) { -#ifdef _pauly_debug - fprintf(stdout," ...pSetMenuBar. mb is null.\n"); - fflush(stdout); -#endif /* _pauly_debug */ - if (wdata->menuBar != NULL) { - /* Redo attachments of other form widgets appropriately now */ - innerCanvasW = XtParent(wdata->winData.comp.widget); - - if (wdata->warningWindow == NULL) { - /* no warning window: canvas is now attached to form */ - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_FORM, - NULL); - } else { - /* warning window present - conditional on #define NETSCAPE: - if NETSCAPE, warning window is at bottom, so canvas is - attached to the form (as above); otherwise (not NETSCAPE), - warning window itself is instead attached to form. */ -#ifdef NETSCAPE - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_FORM, - NULL); -#else /* NETSCAPE */ - XtVaSetValues(wdata->warningWindow, - XmNtopAttachment, XmATTACH_FORM, - NULL); -#endif /* NETSCAPE */ - } - - wdata->menuBarReset = True; - } - wdata->menuBar = NULL; - awtJNI_setMbAndWwHeightAndOffsets(env, this, wdata); - (*env)->DeleteLocalRef(env, target); - AWT_FLUSH_UNLOCK(); -#ifdef _pauly_debug - fprintf(stdout," ...pSetMenuBar. Done.\n"); - fflush(stdout); -#endif /* _pauly_debug */ - return; - } - - mdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, mb, mMenuBarPeerIDs.pData); - if (mdata == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - (*env)->DeleteLocalRef(env, target); - AWT_UNLOCK(); - return; - } - - /* OK - insert the new menu bar into the form (at the top). - Redo the attachments of other form widgets appropriately.*/ - - if (wdata->menuBar == NULL) - wdata->menuBarReset = True; - wdata->menuBar = mdata->widget; - -#ifdef _pauly_debug - XtVaGetValues(mdata->widget, XmNheight, &mbHeight, NULL); - fprintf(stdout," ...pSetMenuBar. new menu bar (widget %x, parent: %x) - menu bar height: %d\n", wdata->menuBar, XtParent(wdata->menuBar), mbHeight); - fflush(stdout); -#endif /* _pauly_debug */ - - XtVaSetValues(mdata->widget, - XmNtopAttachment, XmATTACH_FORM, - XmNleftAttachment, XmATTACH_FORM, - XmNrightAttachment, XmATTACH_FORM, - NULL); - - innerCanvasW = XtParent(wdata->winData.comp.widget); - - if (wdata->warningWindow == NULL) { - /* no warning window: menu bar at top, canvas attached to it */ - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_WIDGET, - XmNtopWidget, mdata->widget, - NULL); - } else { - /* warning window present - conditional on #define NETSCAPE: - if NETSCAPE, warning window is at bottom, so canvas is - attached to menu bar (as above); otherwise (not NETSCAPE), - the warning window is attached just below the menu bar. */ -#ifdef NETSCAPE - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_WIDGET, - XmNtopWidget, mdata->widget, - NULL); -#else /* NETSCAPE */ - XtVaSetValues(wdata->warningWindow, - XmNtopAttachment, XmATTACH_WIDGET, - XmNtopWidget, mdata->widget, - NULL); -#endif /* NETSCAPE */ - } - - XtManageChild(mdata->widget); - XtMapWidget(mdata->widget); - XSync(awt_display, False); - awtJNI_setMbAndWwHeightAndOffsets(env, this, wdata); - -#ifdef _pauly_debug - XtVaGetValues(mdata->widget, XmNheight, &mbHeight, NULL); - fprintf(stdout," ...pSetMenuBar. with menu bar: menu bar height: %d, top offset: %d, bottom offset: %d\n", mbHeight, wdata->top, wdata->bottom); - fflush(stdout); -#endif /* _pauly_debug */ - - (*env)->DeleteLocalRef(env, target); - - AWT_FLUSH_UNLOCK(); - -#ifdef _pauly_debug - fprintf(stdout," ...pSetMenuBar. Done\n"); - fflush(stdout); -#endif /* _pauly_debug */ -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: toBack - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_toBack -(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (XtWindow(wdata->winData.shell) != 0) { - XLowerWindow(awt_display, XtWindow(wdata->winData.shell)); - } - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: updateAlwaysOnTop - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_updateAlwaysOnTop -(JNIEnv *env, jobject this, jboolean isOnTop) -{ - struct FrameData *wdata; - AWT_LOCK(); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - awt_wm_updateAlwaysOnTop(wdata, isOnTop); - AWT_FLUSH_UNLOCK(); -} - -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_addTextComponentNative -(JNIEnv *env, jobject this, jobject tc) -{ - struct FrameData *wdata; - jobject target; - - if (JNU_IsNull(env, this)) { - return; - } - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget==NULL || - wdata->winData.shell==NULL || - JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if ( !wdata->hasTextComponentNative) { - wdata->hasTextComponentNative = True; - wdata->imHeight = awt_motif_getIMStatusHeight(wdata->winData.shell, tc); - wdata->bottom += wdata->imHeight; - awtJNI_ChangeInsets(env, this, wdata); - reshape(env, this, wdata, - (*env)->GetIntField(env, target, componentIDs.x), - (*env)->GetIntField(env, target, componentIDs.y), - (*env)->GetIntField(env, target, componentIDs.width), - (*env)->GetIntField(env, target, componentIDs.height), - True); - } - AWT_UNLOCK(); -} - -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_removeTextComponentNative -(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - jobject target; - - if (JNU_IsNull(env, this)) { - return; - } - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget== NULL || - wdata->winData.shell== NULL || - JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - if (!wdata->hasTextComponentNative) { - AWT_UNLOCK(); - return; - } - - wdata->bottom -= wdata->imHeight; - awtJNI_ChangeInsets(env, this, wdata); - wdata->imRemove = True; - reshape(env, this, wdata, - (*env)->GetIntField(env, target, componentIDs.x), - (*env)->GetIntField(env, target, componentIDs.y), - (*env)->GetIntField(env, target, componentIDs.width), - (*env)->GetIntField(env, target, componentIDs.height), - True); - - wdata->hasTextComponentNative = False; - wdata->imHeight = 0; - - AWT_UNLOCK(); -} /* ...removeTextComponentPeer() */ - -static Atom java_protocol = None; -static Atom motif_wm_msgs = None; - -static void im_callback(Widget shell, XtPointer client_data, XtPointer call_data) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - JNU_CallMethodByName(env, NULL, - (jobject)client_data, - "notifyIMMOptionChange", - "()V"); -} - -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_pSetIMMOption -(JNIEnv *env, jobject this, jstring option) -{ - char *coption; - char *empty = "InputMethod"; - char *menuItem; - jobject globalRef; - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - globalRef = (jobject)JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.jniGlobalRef); - coption = (JNU_IsNull(env, option)) ? empty : (char *) JNU_GetStringPlatformChars(env, option, NULL); - if (java_protocol == None || motif_wm_msgs == None) { - java_protocol = XmInternAtom(awt_display, "_JAVA_IM_MSG", False); - motif_wm_msgs = XmInternAtom(awt_display, "_MOTIF_WM_MESSAGES", False); - } - XmAddProtocols (wdata->winData.shell, motif_wm_msgs, &java_protocol, 1); - XmAddProtocolCallback(wdata->winData.shell, motif_wm_msgs, java_protocol, im_callback, (XtPointer)globalRef); - - if ((menuItem = awt_util_makeWMMenuItem(coption, java_protocol))) { - XtVaSetValues(wdata->winData.shell, - XmNmwmMenu, - menuItem, - NULL); - free(menuItem); - } - if (coption != empty) - JNU_ReleaseStringPlatformChars(env, option, (const char *) coption); - AWT_FLUSH_UNLOCK(); -} - - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_synthesizeFocusInOut(JNIEnv *env, jobject this, - jboolean b) -{ - EmbeddedFrame *ef; - Boolean dummy; - - AWT_LOCK(); - ef = theEmbeddedFrameList; - while (ef != NULL) { - if ((*env)->IsSameObject(env, ef->javaRef, this)) { - XFocusChangeEvent xev; - xev.display = awt_display; - xev.serial = 0; - xev.type = b ? FocusIn : FocusOut; - xev.send_event = False; - xev.window = XtWindow(ef->embeddedFrame); - xev.mode = NotifyNormal; - xev.detail = NotifyNonlinear; - shellEH(ef->embeddedFrame, this, (XEvent*)&xev, &dummy); - break; - } - ef = ef->next; - } - AWT_UNLOCK(); -} - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_traverseOut(JNIEnv *env, jobject this, jboolean direction) -{ - struct FrameData *wdata; - - if (JNU_IsNull(env, this)) { - return; - } - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget== NULL || - wdata->winData.shell== NULL) - { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - xembed_traverse_out(wdata, direction); - AWT_UNLOCK(); -} - - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_NEFcreate(JNIEnv *env, jobject this, - jobject parent, jlong handle) -{ -#undef MAX_ARGC -#define MAX_ARGC 40 - Arg args[MAX_ARGC]; - int32_t argc; - struct FrameData *wdata; - jobject target; - jstring warningString; - jboolean resizable; - jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this); - Widget innerCanvasW; /* form's child, parent of the outer canvas - drawing area */ - AwtGraphicsConfigDataPtr adata; - AwtGraphicsConfigDataPtr defConfig; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - if (JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - wdata = ZALLOC(FrameData); - JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.pData, wdata); - if (wdata == NULL) { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - AWT_UNLOCK(); - return; - } - - adata = getGraphicsConfigFromComponentPeer(env, this); - defConfig = getDefaultConfig(adata->awt_visInfo.screen); - - /* A variation on Netscape's hack for embedded frames: the client area - * of the browser is a Java Frame for parenting purposes, but really a - * Motif child window - */ - wdata->winData.flags |= W_IS_EMBEDDED; - - wdata->top = 0; - wdata->left = 0; - wdata->bottom = 0; - wdata->right = 0; - awtJNI_ChangeInsets(env, this, wdata); - - - wdata->isModal = 0; - wdata->isShowing = False; - wdata->shellResized = False; - wdata->canvasResized = False; - wdata->menuBarReset = False; - - resizable = (*env)->GetBooleanField(env, target, frameIDs.resizable); - - wdata->winData.shell = (Widget)handle; - awt_util_addEmbeddedFrame(wdata->winData.shell, globalRef); - - install_xembed((Widget)handle, wdata); - - setDeleteCallback(globalRef, wdata); - /* Establish resizability. For the case of not resizable, do not - yet set a fixed size here; we must wait until in the routine - sun_awt_motif_MWindowPeer_pReshape() after insets have been fixed. - This is because correction of the insets may affect shell size. - (See comments in shellEH() concerning correction of the insets. */ - /* - * Fix for BugTraq ID 4313607. - * Initial resizability will be set later in MWindowPeer_setResizable() - * called from init(). But the real changes will be made only if the new - * and old resizability values are different at that point, so we - * initialize isResizable with inverse value here to get the job done. - */ - wdata->isResizable = !resizable; - wdata->isFixedSizeSet = False; -#if 0 - if (resizable) { - awt_wm_setShellResizable(wdata); - } -#endif - - XtAddEventHandler(wdata->winData.shell, StructureNotifyMask | FocusChangeMask, - FALSE, (XtEventHandler)shellEH, globalRef); - - - argc = 0; - XtSetArg(args[argc], XmNvisual, defConfig->awt_visInfo.visual); argc++; - XtSetArg(args[argc], XmNcolormap, defConfig->awt_cmap); argc++; - XtSetArg(args[argc], XmNdepth, defConfig->awt_depth); argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); argc++; - XtSetArg(args[argc], XmNhorizontalSpacing, 0); argc++; - XtSetArg(args[argc], XmNverticalSpacing, 0); argc++; - XtSetArg(args[argc], XmNscreen, - ScreenOfDisplay(awt_display, defConfig->awt_visInfo.screen)); argc++; - - - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); argc++; - - DASSERT(!(argc > MAX_ARGC)); - wdata->mainWindow = XmCreateForm(wdata->winData.shell, "main", args, argc); - - /* The widget returned by awt_canvas_create is a drawing area - (i.e., canvas) which is the child of another drawing area - parent widget. The parent is the drawing area within the - form just created. The child is an drawing area layer over - the entire frame window, including the form, any menu bar - and warning windows present, and also window manager stuff. - The top, bottom, left, and right fields in wdata maintain - the respective offsets between these two drawing areas. */ - - wdata->winData.comp.widget = awt_canvas_create((XtPointer)globalRef, - wdata->mainWindow, - "frame_", - -1, - -1, - True, - wdata, - defConfig); - - XtAddCallback(wdata->winData.comp.widget, - XmNresizeCallback, - outerCanvasResizeCB, - globalRef); - - - innerCanvasW = XtParent(wdata->winData.comp.widget); - XtVaSetValues(innerCanvasW, - XmNleftAttachment, XmATTACH_FORM, - XmNrightAttachment, XmATTACH_FORM, - NULL); - - - XtAddEventHandler(innerCanvasW, StructureNotifyMask, FALSE, - (XtEventHandler)innerCanvasEH, globalRef); - - /* No menu bar initially */ - wdata->menuBar = NULL; - wdata->mbHeight = 0; - - /* If a warning window (string) is needed, establish it now.*/ - warningString = - (*env)->GetObjectField(env, target, windowIDs.warningString); - - /* No warning window present */ - XtVaSetValues(innerCanvasW, - XmNtopAttachment, XmATTACH_FORM, - XmNbottomAttachment, XmATTACH_FORM, - NULL); - wdata->warningWindow = NULL; - wdata->wwHeight = 0; - - - awt_util_show(wdata->winData.comp.widget); - - AWT_FLUSH_UNLOCK(); -} /* MEmbeddedFramePeer_NEFcreate() */ - - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_pShowImpl(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - wdata->mainWindow == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - XtVaSetValues(wdata->winData.comp.widget, - XmNx, -(wdata->left), - XmNy, -(wdata->top), NULL); - - if (wdata->menuBar != 0) { - awt_util_show(wdata->menuBar); - } - - XtManageChild(wdata->mainWindow); - if (XtWindow(wdata->winData.shell) == None) { - XtRealizeWidget(wdata->winData.shell); - } - XtManageChild(wdata->winData.comp.widget); - XtSetMappedWhenManaged(wdata->winData.shell, True); - XtPopup(wdata->winData.shell, XtGrabNone); - wdata->isShowing = True; - - AWT_FLUSH_UNLOCK(); -} - -/* - * Create a local managed widget inside a given X window. - * We allocate a top-level shell and then reparent it into the - * given window id. - * - * This is used to take the X11 window ID that has been passed - * to us by our parent Navigator plugin and return a widget - * that can be used as the base for our Java EmbeddeFrame. - * - * Note that the ordering of the various calls is tricky here as - * we have to cope with the variations between 1.1.3, 1.1.6, - * and 1.2. - */ -JNIEXPORT jlong JNICALL -Java_sun_awt_motif_MEmbeddedFrame_getWidget( - JNIEnv *env, jclass clz, jlong winid) -{ - Arg args[40]; - int argc; - Widget w; - Window child, parent; - Visual *visual; - Colormap cmap; - int depth; - int ncolors; - - /* - * Create a top-level shell. Note that we need to use the - * AWT's own awt_display to initialize the widget. If we - * try to create a second X11 display connection the Java - * runtimes get very confused. - */ - AWT_LOCK(); - - argc = 0; - XtSetArg(args[argc], XtNsaveUnder, False); argc++; - XtSetArg(args[argc], XtNallowShellResize, False); argc++; - - /* the awt initialization should be done by now (awt_GraphicsEnv.c) */ - - getAwtData(&depth,&cmap,&visual,&ncolors,NULL); - - XtSetArg(args[argc], XtNvisual, visual); argc++; - XtSetArg(args[argc], XtNdepth, depth); argc++; - XtSetArg(args[argc], XtNcolormap, cmap); argc++; - - XtSetArg(args[argc], XtNwidth, 1); argc++; - XtSetArg(args[argc], XtNheight, 1); argc++; - /* The shell has to have relative coords of O,0? */ - XtSetArg(args[argc], XtNx, 0); argc++; - XtSetArg(args[argc], XtNy, 0); argc++; - - /* The shell widget starts out as a top level widget. - * Without intervention, it will be managed by the window - * manager and will be its own widow. So, until it is reparented, - * we don't map it. - */ - XtSetArg(args[argc], XtNmappedWhenManaged, False); argc++; - - w = XtAppCreateShell("AWTapp","XApplication", - vendorShellWidgetClass, - awt_display, - args, - argc); - XtRealizeWidget(w); - - /* - * Now reparent our new Widget into our Navigator window - */ - parent = (Window) winid; - child = XtWindow(w); - XReparentWindow(awt_display, child, parent, 0, 0); - XFlush(awt_display); - XSync(awt_display, False); - XtVaSetValues(w, XtNx, 0, XtNy, 0, NULL); - XFlush(awt_display); - XSync(awt_display, False); - - AWT_UNLOCK(); - - return (jlong)w; -} - -/* - * Make sure the given widget is mapped. - * - * This isn't necessary on JDK 1.1.5 but is needed on JDK 1.1.4 - */ -JNIEXPORT jint JNICALL -Java_sun_awt_motif_MEmbeddedFrame_mapWidget(JNIEnv *env, jclass clz, jlong widget) -{ - Widget w = (Widget)widget; - /* - * this is what JDK 1.1.5 does in MFramePeer.pShow. - */ - AWT_LOCK(); - XtSetMappedWhenManaged(w, True); - XtPopup(w, XtGrabNone); - AWT_UNLOCK(); - return (jint) 1; -} - - -JNIEXPORT jboolean JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedActive(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - Boolean res; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - wdata->mainWindow == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return False; - } - - res = isXEmbedActive(wdata); - AWT_UNLOCK(); - return res; - -} - -JNIEXPORT jboolean JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_isXEmbedApplicationActive(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - Boolean res; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - wdata->mainWindow == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return False; - } - - res = isXEmbedApplicationActive(wdata); - AWT_UNLOCK(); - return res; - -} - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MEmbeddedFramePeer_requestXEmbedFocus(JNIEnv *env, jobject this) -{ - struct FrameData *wdata; - - AWT_LOCK(); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - wdata->mainWindow == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - requestXEmbedFocus(wdata); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: setSaveUnder - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_setSaveUnder -(JNIEnv *env, jobject this, jboolean state) -{ - struct FrameData *wdata; - jobject target; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - if (!JNU_IsNull(env, target)) - (*env)->DeleteLocalRef(env, target); - AWT_UNLOCK(); - return; - } - - XtVaSetValues(wdata->winData.shell, XmNsaveUnder, state, NULL); - - AWT_FLUSH_UNLOCK(); -} - - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: setFocusableWindow - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_setFocusableWindow -(JNIEnv *env, jobject this, jboolean isFocusableWindow) -{ - struct FrameData *wdata; - jobject target; - - AWT_LOCK(); - - target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target); - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || - wdata->winData.comp.widget == NULL || - wdata->winData.shell == NULL || - JNU_IsNull(env, target)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - if (!JNU_IsNull(env, target)) - (*env)->DeleteLocalRef(env, target); - AWT_UNLOCK(); - return; - } - - wdata->isFocusableWindow = isFocusableWindow; - - AWT_FLUSH_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: resetTargetGC - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MWindowPeer_resetTargetGC - (JNIEnv * env, jobject this, jobject target) -{ - (*env)->CallVoidMethod(env, target, windowIDs.resetGCMID); -} - - -/* - * Old, compatibility, backdoor for DT. This is a different - * implementation. It keeps the signature, but acts on - * awt_root_shell, not the frame passed as an argument. Note, that - * the code that uses the old backdoor doesn't work correctly with - * gnome session proxy that checks for WM_COMMAND when the window is - * firts mapped, because DT code calls this old backdoor *after* the - * frame is shown or it would get NPE with old AWT (previous - * implementation of this backdoor) otherwise. Old style session - * managers (e.g. CDE) that check WM_COMMAND only during session - * checkpoint should work fine, though. - * - * NB: The function name looks deceptively like a JNI native method - * name. It's not! It's just a plain function. - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_XsessionWMcommand(JNIEnv *env, jobject this, - jobject frame, jstring jcommand) -{ - const char *command; - XTextProperty text_prop; - char *c[1]; - int32_t status; - - AWT_LOCK(); - - if (awt_root_shell == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - if (XtWindow(awt_root_shell) == None) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - /* need to convert ctitle to CompoundText */ - command = (char *) JNU_GetStringPlatformChars(env, jcommand, NULL); - c[0] = (char *)command; - status = XmbTextListToTextProperty(awt_display, c, 1, - XStdICCTextStyle, &text_prop); - - if (status == Success || status > 0) { - XSetTextProperty(awt_display, XtWindow(awt_root_shell), - &text_prop, XA_WM_COMMAND); - if (text_prop.value != NULL) - XFree(text_prop.value); - } - - JNU_ReleaseStringPlatformChars(env, jcommand, command); - - AWT_UNLOCK(); - return; -} - - -/* - * New DT backdoor to set WM_COMMAND. New code should use this - * backdoor and call it *before* the first frame is shown so that - * gnome session proxy can correctly handle it. - * - * NB: The function name looks deceptively like a JNI native method - * name. It's not! It's just a plain function. - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_XsessionWMcommand_New(JNIEnv *env, jobjectArray jargv) -{ - static const char empty[] = ""; - - int argc; - const char **cargv; - XTextProperty text_prop; - int status; - int i; - - AWT_LOCK(); - - if (awt_root_shell == NULL) { - JNU_ThrowNullPointerException(env, "AWT root shell"); - AWT_UNLOCK(); - return; - } - - if (XtWindow(awt_root_shell) == None) { - JNU_ThrowNullPointerException(env, "AWT root shell is unrealized"); - AWT_UNLOCK(); - return; - } - - argc = (int)(*env)->GetArrayLength(env, jargv); - if (argc == 0) { - /* nothing to do */ - AWT_UNLOCK(); - return; - } - - /* array of C strings */ - cargv = (const char **)calloc(argc, sizeof(char *)); - if (cargv == NULL) { - JNU_ThrowOutOfMemoryError(env, "Unable to allocate cargv"); - AWT_UNLOCK(); - return; - } - - /* fill C array with platform chars of java strings */ - for (i = 0; i < argc; ++i) { - jstring js; - const char *cs; - - cs = NULL; - js = (*env)->GetObjectArrayElement(env, jargv, i); - if (js != NULL) { - cs = JNU_GetStringPlatformChars(env, js, NULL); - } - if (cs == NULL) { - cs = empty; - } - - cargv[i] = cs; - (*env)->DeleteLocalRef(env, js); - } - - /* grr, X prototype doesn't declare cargv as const, thought it really is */ - status = XmbTextListToTextProperty(awt_display, (char **)cargv, argc, - XStdICCTextStyle, &text_prop); - if (status < 0) { - switch (status) { - case XNoMemory: - JNU_ThrowOutOfMemoryError(env, - "XmbTextListToTextProperty: XNoMemory"); - break; - case XLocaleNotSupported: - JNU_ThrowInternalError(env, - "XmbTextListToTextProperty: XLocaleNotSupported"); - break; - case XConverterNotFound: - JNU_ThrowNullPointerException(env, - "XmbTextListToTextProperty: XConverterNotFound"); - break; - default: - JNU_ThrowInternalError(env, - "XmbTextListToTextProperty: unknown error"); - } - } else { - /* - * status == Success (i.e. 0) or - * status > 0 - a number of unconvertible characters - * (cannot happen for XStdICCTextStyle). - */ - XSetTextProperty(awt_display, XtWindow(awt_root_shell), - &text_prop, XA_WM_COMMAND); - } - - /* release platform chars */ - for (i = 0; i < argc; ++i) { - jstring js; - - if (cargv[i] == empty) - continue; - - js = (*env)->GetObjectArrayElement(env, jargv, i); - JNU_ReleaseStringPlatformChars(env, js, cargv[i]); - (*env)->DeleteLocalRef(env, js); - } - if (text_prop.value != NULL) - XFree(text_prop.value); - - AWT_UNLOCK(); - return; -} - -/* - * Class: java_awt_TrayIcon - * Method: initIDs - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_java_awt_TrayIcon_initIDs(JNIEnv *env , jclass clazz) -{ -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_XmDnD.c --- a/jdk/src/solaris/native/sun/awt/awt_XmDnD.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2282 +0,0 @@ -/* - * Copyright 1997-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include -#include - -#include "jvm.h" -#include "jni.h" -#include "jni_util.h" -#include "jlong.h" - -#include "awt_DataTransferer.h" -#include "awt_XmDnD.h" - -#include "awt_p.h" - -#include "java_awt_Cursor.h" -#include "java_awt_dnd_DnDConstants.h" -#include "java_awt_event_MouseEvent.h" -#include "sun_awt_dnd_SunDragSourceContextPeer.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "sun_awt_motif_MDragSourceContextPeer.h" -#include "sun_awt_motif_MDropTargetContextPeer.h" - -#include -#include -/* - * Fix for 4285634. - * Include the private Motif header to enable access to lastEventState. - */ -#include - -#include "awt_Component.h" -#include "awt_Cursor.h" -#include "awt_AWTEvent.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct CursorIDs cursorIDs; -extern struct ContainerIDs containerIDs; - -/* globals */ - - -/* forwards */ - -static void awt_XmDropProc(Widget, XtPointer, XmDropProcCallbackStruct*); -static void awt_XmDragProc(Widget, XtPointer, XmDragProcCallbackStruct*); - -static void awt_XmTransferProc(Widget, XtPointer, Atom*, Atom*, XtPointer, - unsigned long*, int32_t*); - -/* for XmDragContext callbacks etc ... */ -static void awt_XmDragEnterProc(Widget, XtPointer, - XmDropSiteEnterCallbackStruct*); -static void awt_XmDragMotionProc(Widget, XtPointer, - XmDragMotionCallbackStruct*); -static void awt_XmDragLeaveProc(Widget, XtPointer, - XmDropSiteLeaveCallbackStruct*); -static void awt_XmDropOperationChangedProc(Widget, XtPointer, - XmDropStartCallbackStruct*); -static void awt_XmDropFinishProc(Widget, XtPointer, - XmDropFinishCallbackStruct*); - -static unsigned char DnDConstantsToXm(jint operations); -static jint XmToDnDConstants(unsigned char operations); -static unsigned char selectOperation(unsigned char operations); - -static void flush_cache(JNIEnv* env); -static void cacheDropDone(Boolean dropDone); -static Boolean isDropDone(); - -static void setCursor(JNIEnv* env, Display* d, jobject c, jint type, Time t); - -static Atom MOTIF_DROP_ATOM = None; - -/* in canvas.c */ -extern jint getModifiers(uint32_t state, jint button, jint keyCode); - -/** - * static cache of DropTarget related info. - */ - -static struct { - Widget w; /* if NULL, cache invalid */ - - jobject peer; - jobject component; - - jobject dtcpeer; - - Widget dt; - - jlongArray targets; - Cardinal nTargets; - - Boolean dropDone; - int32_t transfersPending; - Widget transfer; - - jint dropAction; /* used only on JVM transfers */ - - Boolean flushPending; - - Window win; - uint32_t state; -} _cache; - -uint32_t -buttonToMask(uint32_t button) { - switch (button) { - case Button1: - return Button1Mask; - case Button2: - return Button2Mask; - case Button3: - return Button3Mask; - case Button4: - return Button4Mask; - case Button5: - return Button5Mask; - default: - return 0; - } -} - -/* Fix for 4215643: extract the values cached on drag start and send - ButtonRelease event to the window which originated the drag */ - -void -dragsource_track_release(Widget w, XtPointer client_data, - XEvent * event, Boolean * cont) -{ - DASSERT (event != NULL); - - if (_cache.win != None && - (buttonToMask(event->xbutton.button) & _cache.state)) { - - JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2); - Window win = event->xbutton.window; - event->xbutton.window = _cache.win; - awt_put_back_event(env, event); - event->xbutton.window = win; - _cache.win = None; - _cache.state = 0; - XtRemoveEventHandler(w, ButtonReleaseMask, False, - dragsource_track_release, NULL); - } -} - -static void -cancel_drag(XtPointer client_data, XtIntervalId* id) { - Time time = awt_util_getCurrentServerTime(); - Widget dc = XmGetDragContext(awt_root_shell, time); - - if (dc != NULL) { - Boolean sourceIsExternal = True; - XtVaGetValues(dc, XmNsourceIsExternal, &sourceIsExternal, NULL); - if (!sourceIsExternal) { - XEvent xevent; - XmDragCancel(dc); - - /* - * When running the internal drag-and-drop event loop - * (see DragC.c:InitiatorMainLoop) Motif DnD uses XtAppNextEvent, - * that processes all timer callbacks and then returns the next X - * event from the queue. Motif DnD doesn't check if the drag - * operation is cancelled after XtAppNextEvent returns and processes - * the returned event. When the drag operation is cancelled the - * XmDragContext widget is destroyed and Motif will crash if the new - * event is dispatched to the destroyed XmDragContext. - * We cancel the drag operation in the timer callback, so we putback - * a dummy X event. This event will be returned from XtAppNextEvent - * and Motif DnD will safely exit from the internal event loop. - */ - xevent.type = LASTEvent; - xevent.xany.send_event = True; - xevent.xany.display = awt_display; - xevent.xany.window = XtWindow(awt_root_shell); - XPutBackEvent(awt_display, &xevent); - } - } -} - -#define DONT_CARE -1 - -static void -awt_popupCallback(Widget shell, XtPointer closure, XtPointer call_data) { - XtGrabKind grab_kind = XtGrabNone; - - if (call_data != NULL) { - grab_kind = *((XtGrabKind*)call_data); - } - - if (XmIsVendorShell(shell)) { - int input_mode; - XtVaGetValues(shell, XmNmwmInputMode, &input_mode, NULL); - switch (input_mode) { - case DONT_CARE: - case MWM_INPUT_MODELESS: - grab_kind = XtGrabNonexclusive; break; - case MWM_INPUT_PRIMARY_APPLICATION_MODAL: - case MWM_INPUT_SYSTEM_MODAL: - case MWM_INPUT_FULL_APPLICATION_MODAL: - grab_kind = XtGrabExclusive; break; - } - } - - if (grab_kind == XtGrabExclusive) { - /* - * We should cancel the drag on the toolkit thread. Otherwise, it can be - * called while the toolkit thread is waiting inside some drag callback. - * In this case Motif will crash when the drag callback returns. - */ - XtAppAddTimeOut(awt_appContext, 0L, cancel_drag, NULL); - } -} - -static XtInitProc xt_shell_initialize = NULL; - -static void -awt_ShellInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args) { - XtAddCallback(new, XtNpopupCallback, awt_popupCallback, NULL); - (*xt_shell_initialize)(req, new, args, num_args); -} - -/* - * Fix for 4484572. - * Modify the 'initialize' routine for all ShellWidget instances, so that it - * will install an XtNpopupCallback that cancels the current drag operation. - * It is needed, since AWT doesn't have full control over all ShellWidget - * instances (e.g. XmPopupMenu internally creates and popups an XmMenuShell). - */ -static void -awt_set_ShellInitialize() { - static Boolean inited = False; - - DASSERT(!inited); - if (inited) { - return; - } - - xt_shell_initialize = shellWidgetClass->core_class.initialize; - shellWidgetClass->core_class.initialize = (XtInitProc)awt_ShellInitialize; - inited = True; -} - -/** - * global function to initialize this client as a Dynamic-only app. - * - * gets called once during toolkit initialization. - */ - -void awt_initialize_Xm_DnD(Display* dpy) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jclass clazz; - - XtVaSetValues(XmGetXmDisplay(dpy), - XmNdragInitiatorProtocolStyle, XmDRAG_DYNAMIC, - XmNdragReceiverProtocolStyle, XmDRAG_DYNAMIC, - NULL - ); - - MOTIF_DROP_ATOM = XInternAtom(dpy, _XA_MOTIF_DROP, False); - if (XSaveContext(dpy, MOTIF_DROP_ATOM, awt_convertDataContext, - (XPointer)NULL) == XCNOMEM) { - JNU_ThrowInternalError(env, ""); - return; - } - - /* No drop in progress. */ - cacheDropDone(True); - - /* - * Fix for BugTraq ID 4407057. - * Have to disable Motif default drag support, since it doesn't work - * reliably with our event dispatch mechanism. To do this we allow a drag - * operation only if it is registered on the awt_root_shell. - */ - awt_motif_enableSingleDragInitiator(awt_root_shell); - - awt_set_ShellInitialize(); - - /* - * load the Cursor stuff - */ - - clazz = (*env)->FindClass(env, "sun/awt/motif/MCustomCursor"); - - if (!JNU_IsNull(env, ((*env)->ExceptionOccurred(env)))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -typedef struct DSInfoRec { - Widget widget; - - Pixmap animation_mask; - Pixmap animation_pixmap; - int32_t animation_pixmap_depth; - unsigned char animation_style; - XtPointer client_data; - XtCallbackProc drag_proc; - XtCallbackProc drop_proc; - XRectangle *drop_rectangles; - unsigned char drop_site_activity; - unsigned char drop_site_operations; - unsigned char drop_site_type; - Atom *import_targets; - Cardinal num_drop_rectangles; - Cardinal num_import_targets; - - struct DSInfoRec* next; -} DSInfoRec, * DSInfoPtr; - -#define ARG_COUNT 14 - -/* - * Allocates DSInfoRect structure, retrieves all attributes of a Motif drop site - * registered on the specified widget and puts them into the allocated storage. - * The caller should free the storage after use. - */ -DSInfoPtr get_drop_site_info(Widget w) { - Arg arglist[ARG_COUNT]; - Cardinal argcount = 0; - DSInfoPtr info = ZALLOC(DSInfoRec); - - if (info == NULL) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - return NULL; - } - - XtSetArg(arglist[argcount], XmNanimationMask, - (XtArgVal)&info->animation_mask); argcount++; - XtSetArg(arglist[argcount], XmNanimationPixmap, - (XtArgVal)&info->animation_pixmap); argcount++; - XtSetArg(arglist[argcount], XmNanimationPixmapDepth, - (XtArgVal)&info->animation_pixmap_depth); argcount++; - XtSetArg(arglist[argcount], XmNanimationStyle, - (XtArgVal)&info->animation_style); argcount++; - XtSetArg(arglist[argcount], XmNclientData, - (XtArgVal)&info->client_data); argcount++; - XtSetArg(arglist[argcount], XmNdragProc, - (XtArgVal)&info->drag_proc); argcount++; - XtSetArg(arglist[argcount], XmNdropProc, - (XtArgVal)&info->drop_proc); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteActivity, - (XtArgVal)&info->drop_site_activity); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteOperations, - (XtArgVal)&info->drop_site_operations); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteType, - (XtArgVal)&info->drop_site_type); argcount++; - XtSetArg(arglist[argcount], XmNnumDropRectangles, - (XtArgVal)&info->num_drop_rectangles); argcount++; - XtSetArg(arglist[argcount], XmNnumImportTargets, - (XtArgVal)&info->num_import_targets); argcount++; - DASSERT(argcount == ARG_COUNT - 2); - - XmDropSiteRetrieve(w, arglist, argcount); - - if (info->num_import_targets > 0) { - Atom *targets = NULL; - - info->import_targets = malloc(info->num_import_targets * sizeof(Atom)); - - if (info->import_targets == NULL) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - free(info); - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - return NULL; - } - - XtSetArg(arglist[0], XmNimportTargets, (XtArgVal)&targets); - XmDropSiteRetrieve(w, arglist, 1); - - memcpy(info->import_targets, targets, - info->num_import_targets * sizeof(Atom)); - } - - if (info->drop_site_type == XmDROP_SITE_SIMPLE && info->num_drop_rectangles > 0) { - XRectangle *rectangles = NULL; - info->drop_rectangles = - malloc(info->num_drop_rectangles * sizeof(XRectangle)); - - if (info->drop_rectangles == NULL) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - if (info->import_targets != NULL) { - free(info->import_targets); - } - free(info); - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - return NULL; - } - - XtSetArg(arglist[0], XmNdropRectangles, (XtArgVal)&rectangles); - XmDropSiteRetrieve(w, arglist, 1); - - memcpy(info->drop_rectangles, rectangles, - info->num_drop_rectangles * sizeof(XRectangle)); - } else /* if (info->drop_site_type == XmDROP_SITE_COMPOSITE) */ { - info->num_drop_rectangles = 1; - info->drop_rectangles = NULL; - } - - info->widget = w; - return info; -} - -/* - * Registers a Motif drop site on a widget given the information - * in the passed DSInfoRec structure. - */ -void restore_drop_site(DSInfoPtr info) { - Arg arglist[ARG_COUNT]; - Cardinal argcount = 0; - - if (info->drop_site_type == XmDROP_SITE_COMPOSITE) { - info->num_drop_rectangles = 1; - info->drop_rectangles = NULL; - } - - XtSetArg(arglist[argcount], XmNanimationMask, - (XtArgVal)info->animation_mask); argcount++; - XtSetArg(arglist[argcount], XmNanimationPixmap, - (XtArgVal)info->animation_pixmap); argcount++; - XtSetArg(arglist[argcount], XmNanimationPixmapDepth, - (XtArgVal)info->animation_pixmap_depth); argcount++; - XtSetArg(arglist[argcount], XmNanimationStyle, - (XtArgVal)info->animation_style); argcount++; - XtSetArg(arglist[argcount], XmNclientData, - (XtArgVal)info->client_data); argcount++; - XtSetArg(arglist[argcount], XmNdragProc, - (XtArgVal)info->drag_proc); argcount++; - XtSetArg(arglist[argcount], XmNdropProc, - (XtArgVal)info->drop_proc); argcount++; - XtSetArg(arglist[argcount], XmNdropRectangles, - (XtArgVal)info->drop_rectangles); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteActivity, - (XtArgVal)info->drop_site_activity); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteOperations, - (XtArgVal)info->drop_site_operations); argcount++; - XtSetArg(arglist[argcount], XmNdropSiteType, - (XtArgVal)info->drop_site_type); argcount++; - XtSetArg(arglist[argcount], XmNimportTargets, - (XtArgVal)info->import_targets); argcount++; - XtSetArg(arglist[argcount], XmNnumDropRectangles, - (XtArgVal)info->num_drop_rectangles); argcount++; - XtSetArg(arglist[argcount], XmNnumImportTargets, - (XtArgVal)info->num_import_targets); argcount++; - DASSERT(argcount == ARG_COUNT); - - XmDropSiteUnregister(info->widget); - XmDropSiteRegister(info->widget, arglist, argcount); - XmDropSiteConfigureStackingOrder(info->widget, (Widget)NULL, XmABOVE); -} - -#undef ARG_COUNT - -/* - * This routine ensures that hierarchy of Motif drop sites is not broken - * when a new drop site is registered or an existing drop site is - * unregistered. It unregisters all drop sites registered on the descendants of - * the specified widget, then registers or unregisters a Motif drop site on the - * root widget depending on the value of registerNewSite. After that the routine - * restores all the drop sites on the descendants. - * The routine recursively traverses through the hierarchy of descendant Motif - * drop sites and stores the info for all drop sites in a list. Then this list - * is used to restore all descendant drop sites. - * @param w current widget in the hierarchy traversal - * @param top root widget of the traversed hierarchy - the one to be inserted or - * removed - * @param list a list of DSInfoRec structures which keep drop site info for - * child drop sites - * @param registerNewSite if True a new Motif drop site should be registered on - * the root widget. If False an existing drop site of the root widget - * should be unregistered. - * @param isDropSite if True the widget being currently traversed has an - * associated Motif drop site. - */ -static DSInfoPtr -update_drop_site_hierarchy(Widget w, Widget top, DSInfoPtr list, - Boolean registerNewSite, Boolean isDropSite) { - - Widget parent = NULL; - Widget *children = NULL; - Cardinal num_children = 0; - - if (w == NULL || !XtIsObject(w) || w->core.being_destroyed) { - return NULL; - } - - /* Get the child drop sites of the widget.*/ - if (XmDropSiteQueryStackingOrder(w, &parent, &children, - &num_children) == 0) { - /* - * The widget is declared to be a drop site, but the query fails. - * The drop site must be corrupted. Truncate traversal. - */ - if (isDropSite) { - return NULL; - } - } else { - /* The query succeded, so the widget is definitely a drop site. */ - isDropSite = True; - } - - /* Traverse descendants of the widget, if it is composite. */ - if (XtIsComposite(w)) { - Cardinal i = 0; - - /* If it is not a drop site, check all its children. */ - if (!isDropSite) { - XtVaGetValues(w, XmNchildren, &children, - XmNnumChildren, &num_children, NULL); - } - - for (i = 0; i < num_children; i++) { - list = update_drop_site_hierarchy(children[i], top, list, - registerNewSite, isDropSite); - } - } - - /* The storage allocated by XmDropSiteQueryStackingOrder must be freed.*/ - if (isDropSite && children != NULL) { - XtFree((void*)children); - } - - if (w != top) { - if (isDropSite) { - /* Prepend drop site info to the list and unregister a drop site.*/ - DSInfoPtr info = get_drop_site_info(w); - - if (info != NULL) { - info->next = list; - list = info; - } - XmDropSiteUnregister(w); - } - } else { - /* Traversal is complete.*/ - DSInfoPtr info = list; - - if (isDropSite) { - XmDropSiteUnregister(w); - } - - if (registerNewSite) { - Arg args[10]; - unsigned int nargs = 0; - -#define SetArg(n, v) args[nargs].name = n; args[nargs++].value = (XtArgVal)(v); - - SetArg(XmNanimationStyle, XmDRAG_UNDER_NONE); - SetArg(XmNdragProc, awt_XmDragProc); - SetArg(XmNdropProc, awt_XmDropProc); - SetArg(XmNdropSiteActivity, XmDROP_SITE_ACTIVE); - - SetArg(XmNdropSiteOperations, - XmDROP_LINK | XmDROP_MOVE | XmDROP_COPY); - - SetArg(XmNimportTargets, NULL); - SetArg(XmNnumImportTargets, 0); - - SetArg(XmNdropSiteType, XmDROP_SITE_COMPOSITE); - SetArg(XmNdropRectangles, (XRectangle*)NULL); -#undef SetArg - - XmDropSiteRegister(w, args, nargs); - XmDropSiteConfigureStackingOrder(w, (Widget)NULL, XmABOVE); - } - - /* Go through the list and restore all child drop sites.*/ - while (info != NULL) { - restore_drop_site(info); - - info = info->next; - list->next = NULL; - if (list->import_targets != NULL) { - free(list->import_targets); - } - if (list->drop_rectangles != NULL) { - free(list->drop_rectangles); - } - free(list); - list = info; - } - } - return list; -} - -void -register_drop_site(Widget w) { - update_drop_site_hierarchy(w, w, NULL, True, False); -} - -void -unregister_drop_site(Widget w) { - update_drop_site_hierarchy(w, w, NULL, False, True); -} - -DECLARE_JAVA_CLASS(dSCClazz, "sun/awt/motif/MDragSourceContextPeer") -DECLARE_JAVA_CLASS(dTCClazz, "sun/awt/motif/MDropTargetContextPeer") - -static void -call_dSCenter(JNIEnv* env, jobject this, jint targetActions, - jint modifiers, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCenter, dSCClazz, "dragEnter", "(IIII)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCenter, targetActions, modifiers, x, y); -} - -static void -call_dSCmotion(JNIEnv* env, jobject this, jint targetActions, - jint modifiers, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCmotion, dSCClazz, "dragMotion", "(IIII)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCmotion, targetActions, - modifiers, x, y); -} - -static void -call_dSCchanged(JNIEnv* env, jobject this, jint targetActions, - jint modifiers, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCchanged, dSCClazz, "operationChanged", - "(IIII)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCchanged, targetActions, - modifiers, x, y); -} - -static void -call_dSCmouseMoved(JNIEnv* env, jobject this, jint targetActions, - jint modifiers, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCmouseMoved, dSCClazz, "dragMouseMoved", - "(IIII)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCmouseMoved, targetActions, - modifiers, x, y); -} - -static void -call_dSCexit(JNIEnv* env, jobject this, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCexit, dSCClazz, "dragExit", "(II)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCexit, x, y); -} - -static void -call_dSCddfinished(JNIEnv* env, jobject this, jboolean success, - jint operations, jint x, jint y) { - DECLARE_VOID_JAVA_METHOD(dSCddfinished, dSCClazz, "dragDropFinished", - "(ZIII)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dSCddfinished, success, operations, x, y); -} - -static jobject -call_dTCcreate(JNIEnv* env) { - DECLARE_STATIC_OBJECT_JAVA_METHOD(dTCcreate, dTCClazz, - "createMDropTargetContextPeer", - "()Lsun/awt/motif/MDropTargetContextPeer;"); - return (*env)->CallStaticObjectMethod(env, clazz, dTCcreate); -} - -static jint -call_dTCenter(JNIEnv* env, jobject this, jobject component, jint x, jint y, - jint dropAction, jint actions, jlongArray formats, - jlong nativeCtxt) { - DECLARE_JINT_JAVA_METHOD(dTCenter, dTCClazz, "handleEnterMessage", - "(Ljava/awt/Component;IIII[JJ)I"); - DASSERT(!JNU_IsNull(env, this)); - return (*env)->CallIntMethod(env, this, dTCenter, component, x, y, dropAction, - actions, formats, nativeCtxt); -} - -static void -call_dTCexit(JNIEnv* env, jobject this, jobject component, jlong nativeCtxt) { - DECLARE_VOID_JAVA_METHOD(dTCexit, dTCClazz, "handleExitMessage", - "(Ljava/awt/Component;J)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dTCexit, component, nativeCtxt); -} - -static jint -call_dTCmotion(JNIEnv* env, jobject this, jobject component, jint x, jint y, - jint dropAction, jint actions, jlongArray formats, - jlong nativeCtxt) { - DECLARE_JINT_JAVA_METHOD(dTCmotion, dTCClazz, "handleMotionMessage", - "(Ljava/awt/Component;IIII[JJ)I"); - DASSERT(!JNU_IsNull(env, this)); - return (*env)->CallIntMethod(env, this, dTCmotion, component, x, y, - dropAction, actions, formats, nativeCtxt); -} - -static void -call_dTCdrop(JNIEnv* env, jobject this, jobject component, jint x, jint y, - jint dropAction, jint actions, jlongArray formats, - jlong nativeCtxt) { - DECLARE_VOID_JAVA_METHOD(dTCdrop, dTCClazz, "handleDropMessage", - "(Ljava/awt/Component;IIII[JJ)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dTCdrop, component, x, y, - dropAction, actions, formats, nativeCtxt); -} - -static void -call_dTCnewData(JNIEnv* env, jobject this, jlong format, jobject type, - jbyteArray data) { - DECLARE_VOID_JAVA_METHOD(dTCnewData, dTCClazz, "newData", - "(JLjava/lang/String;[B)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dTCnewData, format, type, data); -} - -static void -call_dTCtxFailed(JNIEnv* env, jobject this, jlong format) { - DECLARE_VOID_JAVA_METHOD(dTCtxFailed, dTCClazz, "transferFailed", "(J)V"); - DASSERT(!JNU_IsNull(env, this)); - (*env)->CallVoidMethod(env, this, dTCtxFailed, format); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: addNativeDropTarget - * Signature: (Ljava/awt/dnd/DropTarget;)V - */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_addNativeDropTarget - (JNIEnv *env, jobject this, jobject droptarget) -{ - struct ComponentData* cdata = (struct ComponentData *)NULL; - DropSitePtr dropsite = (DropSitePtr)NULL; - - if (JNU_IsNull(env, droptarget)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - /* introduce a new Component as a root of a set of DropTargets */ - - if ((dropsite = cdata->dsi) == (DropSitePtr)NULL) { - dropsite = cdata->dsi = (DropSitePtr)ZALLOC(DropSiteInfo); - - if (dropsite == (DropSitePtr)NULL) { - JNU_ThrowOutOfMemoryError (env, "OutOfMemoryError"); - AWT_UNLOCK (); - return; - } - - dropsite->component = (*env)->NewGlobalRef - (env, (*env)->GetObjectField(env, this, - mComponentPeerIDs.target)); - dropsite->isComposite = True; - - /* - * Fix for Bug Id 4389284. - * Revalidate drop site hierarchy so that this drop site doesn't obscure - * drop sites that are already registered on its children. - */ - register_drop_site(cdata->widget); - } - - dropsite->dsCnt++; - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MComponentPeer - * Method: removeNativeDropTarget - * Signature: (Ljava/awt/dnd/DropTarget;)V - */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MComponentPeer_removeNativeDropTarget - (JNIEnv *env, jobject this, jobject droptarget) -{ - struct ComponentData* cdata; - DropSitePtr dropsite; - - if (JNU_IsNull(env, droptarget)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - AWT_LOCK(); - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (cdata == NULL || cdata->widget == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - if ((dropsite = cdata->dsi) == (DropSitePtr)NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - AWT_UNLOCK(); - return; - } - - dropsite->dsCnt--; - if (dropsite->dsCnt == 0) { - /* - * Fix for Bug Id 4411368. - * Revalidate drop site hierarchy to prevent crash when a composite drop - * site is unregistered before its child drop sites. - */ - unregister_drop_site(cdata->widget); - - (*env)->DeleteGlobalRef(env, dropsite->component); - - free((void *)(cdata->dsi)); - cdata->dsi = (DropSitePtr)NULL; - } - - AWT_UNLOCK(); -} - -/** - * - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MDragSourceContextPeer_setNativeCursor(JNIEnv *env, - jobject this, - jlong nativeCtxt, - jobject cursor, - jint type) { - /* - * NOTE: no need to synchronize on awt_lock here, since we should have - * already acquired it in MDragSourceContextPeer.setCursor(). - */ - setCursor(env, awt_display, cursor, type, CurrentTime); -} - -/** - * - */ - -JNIEXPORT jlong JNICALL -Java_sun_awt_motif_MDropTargetContextPeer_startTransfer(JNIEnv *env, - jobject this, - jlong dragContextVal, - jlong atom) { - XmDropTransferEntryRec trec; - Widget dropTransfer; - Arg args[3]; - Cardinal nargs = 0; - jboolean isCopy; - Widget dragContext = (Widget)jlong_to_ptr(dragContextVal); - - AWT_LOCK(); - - trec.target = (Atom) atom; - trec.client_data = (XtPointer)trec.target; - - -#define SetArg(n, v) args[nargs].name = n; args[nargs++].value = (XtArgVal)(v); - - SetArg(XmNdropTransfers, &trec); - SetArg(XmNnumDropTransfers, 1 ); - SetArg(XmNtransferProc, awt_XmTransferProc); - -#undef SetArg - - _cache.transfer = dropTransfer = - XmDropTransferStart(dragContext, args, nargs); - - _cache.transfersPending++; - - AWT_NOTIFY_ALL(); - AWT_UNLOCK(); - - return ptr_to_jlong(dropTransfer); -} - -/** - * - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MDropTargetContextPeer_addTransfer(JNIEnv *env, - jobject this, - jlong dropTransferVal, - jlong atom) { - XmDropTransferEntryRec trec; - jboolean isCopy; - Widget dropTransfer=(Widget)jlong_to_ptr(dropTransferVal); - trec.target = (Atom)atom; - trec.client_data = (XtPointer)trec.target; - - AWT_LOCK(); - - XmDropTransferAdd(dropTransfer, &trec, 1); - - _cache.transfersPending++; - - AWT_NOTIFY_ALL(); - AWT_UNLOCK(); -} - -/** - * - */ - -JNIEXPORT void JNICALL Java_sun_awt_motif_MDropTargetContextPeer_dropDone - (JNIEnv *env, jobject this, jlong dragContextVal, jlong dropTransferVal, - jboolean isLocal, jboolean success, jint dropAction) -{ - Widget dropTransfer = (Widget)jlong_to_ptr(dropTransferVal); - Widget dragContext = (Widget)jlong_to_ptr(dragContextVal); - - AWT_LOCK(); - - if (_cache.w == (Widget)NULL) { - AWT_UNLOCK(); - return; - } - - if (!isDropDone()) { - if (dropTransfer != (jlong)NULL) { - XtVaSetValues(dropTransfer, - XmNtransferStatus, - success == JNI_TRUE - ? XmTRANSFER_SUCCESS : XmTRANSFER_FAILURE, - NULL - ); - } else { - /* - * start a transfer that notifies failure - * this causes src side callbacks to be processed. - * However, you cannot pass an a success, so the workaround is - * to set _cache.transferSuccess to the proper value and read it - * on the other side. - */ - - - Arg arg; - - /* - * this is the workaround code - */ - _cache.transfer = NULL; - _cache.dropAction = dropAction; - - /* - * End workaround code - */ - - arg.name = XmNtransferStatus; - arg.value = (XtArgVal)(success == JNI_TRUE ? XmTRANSFER_SUCCESS - : XmTRANSFER_FAILURE - ); - - XmDropTransferStart(dragContext, &arg, 1); - } - - /* - * bugid# 4146717 - * - * If this is a local tx, then we never exec the awt_XmTransferProc, - * thus we need to flush the cache here as it is our only chance, - * otherwise we leave a mess for the next operation to fail on .... - * - */ - - if (isLocal == JNI_TRUE) - flush_cache(env); /* flush now, last chance */ - else - _cache.flushPending = True; /* flush pending in transfer proc */ - } - - cacheDropDone(True); - - AWT_NOTIFY_ALL(); - AWT_UNLOCK(); -} - - -static Boolean exitIdleProc = False; -static int32_t x_root = -1, y_root = -1; - -extern void waitForEvents(JNIEnv *env, int32_t fdXPipe, int32_t fdAWTPipe); - -static jint convertModifiers(uint32_t modifiers) { - return getModifiers(modifiers, 0, 0); -} - -static void -checkMouseMoved(XtPointer client_data) { - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - /* - * When dragging over the root window XmNdragMotionCallback is not called - * (Motif feature). - * Since there is no legal way to receive MotionNotify events during drag - * we have to query for mouse position periodically. - */ - if (XQueryPointer(awt_display, XDefaultRootWindow(awt_display), - &rootWindow, &childWindow, - &xr, &yr, &xw, &yw, &modifiers) && - childWindow == None && (xr != x_root || yr != y_root)) { - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)client_data; - - call_dSCmouseMoved(env, this, XmDROP_NOOP, convertModifiers(modifiers), - xr, yr); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - x_root = xr; - y_root = yr; - } -} - -static void IdleProc(XtPointer client_data, XtIntervalId* id) { - if (!exitIdleProc) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - /* The pipe where X events arrive */ - int32_t fdXPipe = ConnectionNumber(awt_display) ; - - /* - * Motif DnD internal event loop doesn't process the events - * from the AWT putback event queue. So we pass -1 instead - * of the AWT read pipe descriptor to disable checking of - * the putback event queue. - */ - waitForEvents(env, fdXPipe, -1); - - checkMouseMoved(client_data); - /* Reschedule the timer callback */ - XtAppAddTimeOut(awt_appContext, AWT_DND_POLL_INTERVAL / 10, - IdleProc, client_data); - } -} - -static void RemoveIdleProc(Widget w, - XtPointer client_data, - XmDropFinishCallbackStruct* cbstruct) { - exitIdleProc = True; -} - -/** - * - */ - -JNIEXPORT jlong JNICALL -Java_sun_awt_motif_MDragSourceContextPeer_startDrag(JNIEnv *env, - jobject this, - jobject component, - jobject transferable, - jobject trigger, - jobject cursor, - jint ctype, - jint actions, - jlongArray formats, - jobject formatMap) { - Arg args[32]; - Cardinal nargs = 0; - jobject dscp = (*env)->NewGlobalRef(env, this); - jbyteArray bdata = - (jbyteArray)(*env)->GetObjectField(env, trigger, awtEventIDs.bdata); - Atom* targets = NULL; - jlong* jTargets; - jsize nTargets; - Widget dc; - XtCallbackRec dsecbr[2]; - XtCallbackRec dmcbr[2]; - XtCallbackRec occbr[2]; - XtCallbackRec dslcbr[2]; - XtCallbackRec dscbr[2]; - XtCallbackRec ddfcbr[2]; - XEvent* xevent; - unsigned char xmActions = DnDConstantsToXm(actions); - jboolean isCopy=JNI_TRUE; - awt_convertDataCallbackStruct* structPtr; - -#ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */ - jsize i; - jlong* saveJTargets; - Atom* saveTargets; -#endif - - if (xmActions == XmDROP_NOOP) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Invalid source actions."); - return ptr_to_jlong(NULL); - } - - if (JNU_IsNull(env, formats)) { - JNU_ThrowNullPointerException(env, "formats"); - return ptr_to_jlong(NULL); - } - - if (JNU_IsNull(env, bdata)) { - JNU_ThrowNullPointerException(env, - "null native data for trigger event"); - return ptr_to_jlong(NULL); - } - - nTargets = (*env)->GetArrayLength(env, formats); - - /* - * In debug build GetLongArrayElements aborts with assertion on an empty - * array. - */ - if (nTargets > 0) { - jTargets = (*env)->GetLongArrayElements(env, formats, &isCopy); - if (!JNU_IsNull(env, ((*env)->ExceptionOccurred(env)))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (jTargets != NULL) { - targets = (Atom *)malloc(nTargets * sizeof(Atom)); - if (targets != NULL) { -#ifdef _LP64 - memcpy(targets, jTargets, nTargets * sizeof(Atom)); -#else - saveJTargets = jTargets; - saveTargets = targets; - for (i = 0; i < nTargets; i++, targets++, jTargets++) { - *targets = (Atom)*jTargets; - } - jTargets = saveJTargets; - targets = saveTargets; -#endif - } - (*env)->ReleaseLongArrayElements(env, formats, jTargets, JNI_ABORT); - } - } - if (targets == NULL) { - nTargets = 0; - } - -#define SetCB(cbr, cb, cl) cbr[0].callback = (XtCallbackProc)cb; cbr[0].closure = (XtPointer)cl; cbr[1].callback = (XtCallbackProc)NULL; cbr[1].closure = (XtPointer)NULL - -#define SetArg(n, v) args[nargs].name = n; args[nargs++].value = (XtArgVal)(v); - - SetCB(dsecbr, awt_XmDragEnterProc, dscp); - SetCB(dmcbr, awt_XmDragMotionProc, dscp); - SetCB(occbr, awt_XmDropOperationChangedProc, dscp); - SetCB(dslcbr, awt_XmDragLeaveProc, dscp); - SetCB(ddfcbr, awt_XmDropFinishProc, dscp); - - SetArg(XmNblendModel, XmBLEND_NONE ); - SetArg(XmNdragOperations, xmActions ); - /* No incremental transfer */ - SetArg(XmNconvertProc, awt_convertData ); - SetArg(XmNdropSiteEnterCallback, dsecbr ); - SetArg(XmNdragMotionCallback, dmcbr ); - SetArg(XmNoperationChangedCallback, occbr ); - SetArg(XmNdropSiteLeaveCallback, dslcbr ); - SetArg(XmNdropFinishCallback, ddfcbr ); - SetArg(XmNexportTargets, targets ); - SetArg(XmNnumExportTargets, (Cardinal)nTargets ); - - { - jsize len = (*env)->GetArrayLength(env, bdata); - if (len <= 0) { - free(targets); - return ptr_to_jlong(NULL); - } - - xevent = calloc(1, len); - - if (xevent == NULL) { - free(targets); - JNU_ThrowOutOfMemoryError(env, ""); - return ptr_to_jlong(NULL); - } - - (*env)->GetByteArrayRegion(env, bdata, 0, len, (jbyte *)xevent); - - DASSERT(JNU_IsNull(env, (*env)->ExceptionOccurred(env))); - } - - if (xevent->type != ButtonPress && - xevent->type != ButtonRelease && - xevent->type != KeyRelease && - xevent->type != KeyPress && - xevent->type != MotionNotify) { - - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "A drag can only be initiated in response to an InputEvent."); - free(xevent); - free(targets); - return ptr_to_jlong(NULL); - } - - /* This call causes an UnsatisfiedLinkError on Linux. - * This function is a no-op for Motif 2.1. - * Since Linux only links against Motif 2.1, we can safely remove - * this function altogether from the Linux build. - * bchristi 1/22/2001 - */ - -#ifdef __solaris__ - awt_motif_adjustDragTriggerEvent(xevent); -#endif - - AWT_LOCK(); - - /* - * Fix for BugTraq ID 4357905. - * Drop is processed asynchronously on the event dispatch thread. - * Reject all drag attempts until the current drop is done. - */ - if (!isDropDone()) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Drop transfer in progress."); - free(xevent); - free(targets); - AWT_UNLOCK(); - return ptr_to_jlong(NULL); - } - - if (XFindContext(awt_display, MOTIF_DROP_ATOM, awt_convertDataContext, - (XPointer*)&structPtr) == XCNOMEM || structPtr != NULL) { - free(xevent); - free(targets); - AWT_UNLOCK(); - return ptr_to_jlong(NULL); - } - - structPtr = calloc(1, sizeof(awt_convertDataCallbackStruct)); - if (structPtr == NULL) { - free(xevent); - free(targets); - JNU_ThrowOutOfMemoryError(env, ""); - AWT_UNLOCK(); - return ptr_to_jlong(NULL); - } - - structPtr->source = (*env)->NewGlobalRef(env, component); - structPtr->transferable = (*env)->NewGlobalRef(env, transferable); - structPtr->formatMap = (*env)->NewGlobalRef(env, formatMap); - structPtr->formats = (*env)->NewGlobalRef(env, formats); - - if (XSaveContext(awt_display, MOTIF_DROP_ATOM, awt_convertDataContext, - (XPointer)structPtr) == XCNOMEM) { - free(structPtr); - free(xevent); - free(targets); - AWT_UNLOCK(); - return ptr_to_jlong(NULL); - } - - dc = XmDragStart(awt_root_shell, xevent, args, nargs); - - /* Fix for 4215643: remember the window corresponding to the drag source - and the button mask after the event which triggered drag start */ - - if (xevent->type == ButtonPress || xevent->type == MotionNotify) { - _cache.win = xevent->xbutton.window; - if (xevent->type == ButtonPress) { - _cache.state = buttonToMask(xevent->xbutton.button); - } else { - _cache.state = xevent->xmotion.state & (Button1Mask | Button2Mask); - } - XtAddEventHandler(dc, ButtonReleaseMask, False, - dragsource_track_release, NULL); - } - - free(targets); - - if (dc != (Widget)NULL) { - setCursor(env, awt_display, cursor, ctype, xevent->xbutton.time); - } - - free(xevent); - - /* - * With the new synchronization model we don't release awt_lock - * in the DragContext callbacks. During drag-n-drop operation - * the events processing is performed not by our awt_MToolkit_loop, - * but by internal Motif InitiatorMainLoop, which returns only - * when the operation is completed. So our polling mechanism doesn't - * have a chance to execute and even if there are no events in - * the queue AWT_LOCK will still be held by the Toolkit thread - * and so other threads will likely be blocked on it. - * - * The solution is to schedule a timer callback which checks - * for events and if the queue is empty releases AWT_LOCK and polls - * the X pipe for some time, then acquires AWT_LOCK back again - * and reschedules itself. - */ - if (dc != NULL) { - exitIdleProc = False; - XtAddCallback(dc, XmNdragDropFinishCallback, - (XtCallbackProc)RemoveIdleProc, NULL); - XtAppAddTimeOut(awt_appContext, AWT_DND_POLL_INTERVAL / 10, - IdleProc, (XtPointer)dscp); - } - - AWT_UNLOCK(); - - return ptr_to_jlong(dc); - -#undef SetArg -#undef SetCB -} - -/*****************************************************************************/ - -/** - * - */ - -static void setCursor(JNIEnv* env, Display* dpy, jobject cursor, jint type, - Time time) -{ - Cursor xcursor = None; - - if (JNU_IsNull(env, cursor)) return; - - XChangeActivePointerGrab(dpy, - ButtonPressMask | - ButtonMotionMask | - ButtonReleaseMask | - EnterWindowMask | - LeaveWindowMask, - getCursor(env, cursor), - time - ); - - XSync(dpy, False); -} - -/** - * Update the cached targets for this widget - */ - -static Boolean updateCachedTargets(JNIEnv* env, Widget dt) { - Atom* targets = (Atom*)NULL; - Cardinal nTargets = (Cardinal)0; - Arg args[2]; - - /* - * Get the targets for this component - */ - args[0].name = XmNexportTargets; args[0].value = (XtArgVal)&targets; - args[1].name = XmNnumExportTargets; args[1].value = (XtArgVal)&nTargets; - XtGetValues(_cache.dt = dt, args, 2); - - /* - * Free the previous targets if there were any - */ - if (!JNU_IsNull(env, _cache.targets)) { - (*env)->DeleteGlobalRef(env, _cache.targets); - _cache.targets = (jlongArray)NULL; - } - - _cache.nTargets = nTargets; - - /* - * If the widget has targets (atoms) then copy them to the cache - */ - if (nTargets > 0) { - jboolean isCopy; - jlong* jTargets; - -#ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */ - jlong* saveJTargets; - Cardinal i; -#endif - - _cache.targets = (*env)->NewLongArray(env, nTargets); - if (_cache.targets == NULL) { - _cache.nTargets = 0; - return False; - } - - _cache.targets = (*env)->NewGlobalRef(env, _cache.targets); - if (_cache.targets == NULL) { - _cache.nTargets = 0; - return False; - } - - jTargets = (*env)->GetLongArrayElements(env, _cache.targets, &isCopy); - if (jTargets == NULL) { - (*env)->DeleteGlobalRef(env, _cache.targets); - _cache.targets = NULL; - _cache.nTargets = 0; - return False; - } - -#ifdef _LP64 - memcpy(jTargets, targets, nTargets * sizeof(Atom)); -#else - saveJTargets = jTargets; - for (i = 0; i < nTargets; i++, jTargets++, targets++) { - *jTargets = (*targets & 0xFFFFFFFFLU); - } - jTargets = saveJTargets; -#endif - - (*env)->ReleaseLongArrayElements(env, _cache.targets, jTargets, 0); - return True; - } - - return False; -} - - -/** - * - */ - -static void flush_cache(JNIEnv* env) { - _cache.w = (Widget)NULL; - _cache.dt = (Widget)NULL; - - (*env)->DeleteGlobalRef(env, _cache.peer); - _cache.peer = (jobject)NULL; - - (*env)->DeleteGlobalRef(env, _cache.component); - _cache.component = (jobject)NULL; - - if (_cache.dtcpeer != (jobject)NULL) { - (*env)->DeleteGlobalRef(env, _cache.dtcpeer); - - _cache.dtcpeer = (jobject)NULL; - } - - _cache.nTargets = (Cardinal)0; - if (_cache.targets != (jlongArray)NULL) { - (*env)->DeleteGlobalRef(env, _cache.targets); - _cache.targets = (jlongArray)NULL; - } - - _cache.transfersPending = 0; - _cache.flushPending = False; - _cache.transfer = (Widget)NULL; - cacheDropDone(True); -} - -/** - * - */ - -static void update_cache(JNIEnv* env, Widget w, Widget dt) { - if(w != _cache.w) { - struct ComponentData* cdata = (struct ComponentData *)NULL; - Arg args[1] = - {{ XmNuserData, (XtArgVal)&_cache.peer}}; - - flush_cache(env); - - if (w == (Widget)NULL) return; - - XtGetValues(w, args, 1); - - if (JNU_IsNull(env, _cache.peer)) { - _cache.w = NULL; - - return; - } - - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, _cache.peer, mComponentPeerIDs.pData); - - if (cdata == NULL || - cdata->widget != w || - cdata->dsi == (DropSitePtr)NULL) { - _cache.w = NULL; - - return; - } - - _cache.w = w; - _cache.component = (*env)->NewGlobalRef(env, cdata->dsi->component); - _cache.peer = (*env)->NewGlobalRef(env, _cache.peer); - /* SECURITY: OK to call this on privileged thread - peer is secure */ - { - jobject dtcpeer = call_dTCcreate(env); - if (!JNU_IsNull(env, dtcpeer)) { - _cache.dtcpeer = (*env)->NewGlobalRef(env, dtcpeer); - (*env)->DeleteLocalRef(env, dtcpeer); - } else { - _cache.dtcpeer = NULL; - } - } - - _cache.transfersPending = 0; - cacheDropDone(True); - } - - if (_cache.w != (Widget)NULL) updateCachedTargets(env, dt); -} - - -/** - * - */ - -static void -cacheDropDone(Boolean dropDone) { - _cache.dropDone = dropDone; -} - -static Boolean -isDropDone() { - return _cache.dropDone; -} - -/** - * - */ - -static jint XmToDnDConstants(unsigned char operations) { - jint src = java_awt_dnd_DnDConstants_ACTION_NONE; - - if (operations & XmDROP_MOVE) src |= java_awt_dnd_DnDConstants_ACTION_MOVE; - if (operations & XmDROP_COPY) src |= java_awt_dnd_DnDConstants_ACTION_COPY; - if (operations & XmDROP_LINK) src |= java_awt_dnd_DnDConstants_ACTION_LINK; - - return src; -} - -static unsigned char selectOperation(unsigned char operations) { - if (operations & XmDROP_MOVE) return XmDROP_MOVE; - if (operations & XmDROP_COPY) return XmDROP_COPY; - if (operations & XmDROP_LINK) return XmDROP_LINK; - - return XmDROP_NOOP; -} - -/** - * - */ - -static unsigned char DnDConstantsToXm(jint actions) { - unsigned char ret = XmDROP_NOOP; - - if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) ret |= XmDROP_COPY; - if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) ret |= XmDROP_MOVE; - if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) ret |= XmDROP_LINK; - - return ret; -} - -/** - * - */ - -typedef struct DragExitProcStruct { - XtIntervalId timerId; - jobject dtcpeer; /* global reference */ - jobject component; /* global reference */ - jlong dragContext; /* pointer */ -} DragExitProcStruct; - -static DragExitProcStruct pending_drag_exit_data = - { (XtIntervalId)0, NULL, NULL, (jlong)0 }; - -static void drag_exit_proc(XtPointer client_data, XtIntervalId* id) { - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - DASSERT(!JNU_IsNull(env, pending_drag_exit_data.dtcpeer)); - DASSERT(!JNU_IsNull(env, pending_drag_exit_data.component)); - DASSERT(pending_drag_exit_data.dragContext != NULL); - - if (pending_drag_exit_data.timerId != (XtIntervalId)0) { - if (id == NULL) { - XtRemoveTimeOut(pending_drag_exit_data.timerId); - } - if (id == NULL || pending_drag_exit_data.timerId == *id) { - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - call_dTCexit(env, pending_drag_exit_data.dtcpeer, - pending_drag_exit_data.component, - pending_drag_exit_data.dragContext); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - } - - /* cleanup */ - (*env)->DeleteGlobalRef(env, pending_drag_exit_data.dtcpeer); - (*env)->DeleteGlobalRef(env, pending_drag_exit_data.component); - - memset(&pending_drag_exit_data, 0, sizeof(DragExitProcStruct)); -} - -static void awt_XmDragProc(Widget w, XtPointer closure, - XmDragProcCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject component = (jobject)NULL; - jint src = java_awt_dnd_DnDConstants_ACTION_NONE; - jint usrAction = java_awt_dnd_DnDConstants_ACTION_NONE; - jint ret = java_awt_dnd_DnDConstants_ACTION_NONE; - unsigned char srcOps = XmDROP_NOOP; - - /* - * Fix for BugTraq ID 4395290. - * We should dispatch any pending java upcall right now - * to keep the order of upcalls. - */ - if (pending_drag_exit_data.timerId != (XtIntervalId)0) { - drag_exit_proc(NULL, NULL); - } - - /* - * Fix for BugTraq ID 4357905. - * Drop is processed asynchronously on the event dispatch thread. - * We reject other drop attempts to protect the SunDTCP context - * from being overwritten by an upcall before the drop is done. - */ - if (!isDropDone()) { - cbstruct->operation = XmDROP_NOOP; - cbstruct->dropSiteStatus = XmINVALID_DROP_SITE; - return; - } - - if (cbstruct->dragContext == NULL) { - cbstruct->operation = XmDROP_NOOP; - cbstruct->dropSiteStatus = XmINVALID_DROP_SITE; - return; - } - - (*env)->PushLocalFrame(env, 0); - - /* - * Fix for BugTraq ID 4285634. - * If some modifier keys are pressed the Motif toolkit initializes - * cbstruct->operations this field to the bitwise AND of the - * XmDragOperations resource of the XmDragContext for this drag operation - * and the drop action corresponding to the current modifiers state. - * We need to determine the drag operations supported by the drag source, so - * we have to get XmNdragOperations value of the XmDragSource. - */ - XtVaGetValues(cbstruct->dragContext, XmNdragOperations, &srcOps, NULL); - src = XmToDnDConstants(srcOps); - usrAction = XmToDnDConstants(selectOperation(cbstruct->operations)); - - update_cache(env, w, cbstruct->dragContext); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - flush_cache(env); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - goto wayout; - } - - switch (cbstruct->reason) { - case XmCR_DROP_SITE_ENTER_MESSAGE: { - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - ret = call_dTCenter(env, _cache.dtcpeer, _cache.component, - cbstruct->x, cbstruct->y, - usrAction, src, - _cache.targets,ptr_to_jlong(cbstruct->dragContext)); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - flush_cache(env); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - break; - - case XmCR_DROP_SITE_LEAVE_MESSAGE: { - - DASSERT(pending_drag_exit_data.timerId == (XtIntervalId)0); - DASSERT(JNU_IsNull(env, pending_drag_exit_data.dtcpeer)); - DASSERT(JNU_IsNull(env, pending_drag_exit_data.component)); - DASSERT(pending_drag_exit_data.dragContext == (jlong)0); - - DASSERT(!JNU_IsNull(env, _cache.dtcpeer)); - DASSERT(!JNU_IsNull(env, _cache.component)); - DASSERT(cbstruct->dragContext != NULL); - - pending_drag_exit_data.dtcpeer = - (*env)->NewGlobalRef(env, _cache.dtcpeer); - pending_drag_exit_data.component = - (*env)->NewGlobalRef(env, _cache.component); - pending_drag_exit_data.dragContext = - ptr_to_jlong(cbstruct->dragContext); - - /* - * Fix for BugTraq ID 4395290. - * Postpone upcall to java, so that we can abort it in case - * if drop immediatelly follows. - */ - if (!JNU_IsNull(env, pending_drag_exit_data.dtcpeer) && - !JNU_IsNull(env, pending_drag_exit_data.component)) { - pending_drag_exit_data.timerId = - XtAppAddTimeOut(awt_appContext, 0, drag_exit_proc, NULL); - DASSERT(pending_drag_exit_data.timerId != (XtIntervalId)0); - } else { - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (!JNU_IsNull(env, pending_drag_exit_data.dtcpeer)) { - (*env)->DeleteGlobalRef(env, pending_drag_exit_data.dtcpeer); - } - if (!JNU_IsNull(env, pending_drag_exit_data.component)) { - (*env)->DeleteGlobalRef(env, pending_drag_exit_data.component); - } - memset(&pending_drag_exit_data, 0, sizeof(DragExitProcStruct)); - } - - ret = java_awt_dnd_DnDConstants_ACTION_NONE; - - /* now cleanup */ - - flush_cache(env); - } - break; - - case XmCR_DROP_SITE_MOTION_MESSAGE: { - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - ret = call_dTCmotion(env, _cache.dtcpeer, _cache.component, - cbstruct->x, cbstruct->y, - usrAction, src, - _cache.targets, - ptr_to_jlong(cbstruct->dragContext)); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - flush_cache(env); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - } - break; - - case XmCR_OPERATION_CHANGED: { - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - ret = call_dTCmotion(env, _cache.dtcpeer, _cache.component, - cbstruct->x, cbstruct->y, - usrAction, src, - _cache.targets, - ptr_to_jlong(cbstruct->dragContext)); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - flush_cache(env); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - } - break; - - default: break; - } - - wayout: - - /* - * Fix for BugTraq ID 4285634. - * If some modifier keys are pressed the Motif toolkit initializes - * cbstruct->operations this field to the bitwise AND of the - * XmDragOperations resource of the XmDragContext for this drag operation - * and the drop action corresponding to the current modifiers state. - * We should allow the drop target to select a drop action independent of - * the current modifiers state. - */ - cbstruct->operation = DnDConstantsToXm(ret); - - if (cbstruct->reason != XmCR_DROP_SITE_LEAVE_MESSAGE) { - Arg arg; - arg.name = XmNdropSiteOperations; - arg.value = (XtArgVal)cbstruct->operation; - - XmDropSiteUpdate(w, &arg, 1); - } - - if (ret != java_awt_dnd_DnDConstants_ACTION_NONE) { - cbstruct->dropSiteStatus = XmVALID_DROP_SITE; - } else { - cbstruct->dropSiteStatus = XmINVALID_DROP_SITE; - } - - (*env)->PopLocalFrame(env, NULL); -} - -static void drop_failure_cleanup(JNIEnv* env, Widget dragContext) { - Arg arg; - - DASSERT(dragContext != NULL); - _cache.transfer = NULL; - _cache.dropAction = XmDROP_NOOP; - - arg.name = XmNtransferStatus; - arg.value = (XtArgVal)XmTRANSFER_FAILURE; - XmDropTransferStart(dragContext, &arg, 1); - - /* Flush here, since awt_XmTransferProc won't be called. */ - flush_cache(env); -} - -/** - * - */ - -static void awt_XmDropProc(Widget w, XtPointer closure, - XmDropProcCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jint src = java_awt_dnd_DnDConstants_ACTION_NONE; - unsigned char operation = selectOperation(cbstruct->operations); - unsigned char srcOps = XmDROP_NOOP; - unsigned char dstOps = XmDROP_NOOP; - Arg arg; - Boolean sourceIsExternal = False; - - arg.name = XmNdropSiteOperations; - arg.value = (XtArgVal)&dstOps; - XmDropSiteRetrieve(w, &arg, 1); - arg.value = (XtArgVal)(XmDROP_COPY | XmDROP_MOVE | XmDROP_LINK); - XmDropSiteUpdate(w, &arg, 1); - - /* - * Fix for BugTraq ID 4357905. - * Drop is processed asynchronously on the event dispatch thread. - * We reject other drop attempts to protect the SunDTCP context - * from being overwritten by an upcall before the drop is done. - */ - if (!isDropDone()) { - return; - } - - if (cbstruct->dragContext == NULL) { - cbstruct->operation = XmDROP_NOOP; - cbstruct->dropSiteStatus = XmINVALID_DROP_SITE; - return; - } - - /* - * Fix for BugTraq ID 4492640. - * Because of the Motif bug #4528191 XmNdragOperations resource is always - * equal to XmDROP_MOVE | XmDROP_COPY when the drag source is external. - * The workaround for this bug is to assume that an external drag source - * supports all drop actions. - */ - XtVaGetValues(cbstruct->dragContext, - XmNsourceIsExternal, &sourceIsExternal, NULL); - - if (sourceIsExternal) { - srcOps = XmDROP_LINK | XmDROP_MOVE | XmDROP_COPY; - } else { - /* - * Fix for BugTraq ID 4285634. - * If some modifier keys are pressed the Motif toolkit initializes - * cbstruct->operations to the bitwise AND of the - * XmDragOperations resource of the XmDragContext for this drag operation - * and the drop action corresponding to the current modifiers state. - * We need to determine the drag operations supported by the drag source, so - * we have to get XmNdragOperations value of the XmDragSource. - */ - XtVaGetValues(cbstruct->dragContext, XmNdragOperations, &srcOps, NULL); - } - - src = XmToDnDConstants(srcOps); - - if ((srcOps & dstOps) == 0) { - cbstruct->operation = XmDROP_NOOP; - cbstruct->dropSiteStatus = XmINVALID_DROP_SITE; - drop_failure_cleanup(env, cbstruct->dragContext); - return; - } - - (*env)->PushLocalFrame(env, 0); - - update_cache(env, w, cbstruct->dragContext); - - cacheDropDone(False); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - (*env)->PopLocalFrame(env, NULL); - drop_failure_cleanup(env, cbstruct->dragContext); - return; - } - - /* - * Fix for BugTraq ID 4395290. - * Abort a pending upcall to dragExit. - */ - pending_drag_exit_data.timerId = (XtIntervalId)0; - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dTCdrop(env, _cache.dtcpeer, _cache.component, - cbstruct->x, cbstruct->y, - XmToDnDConstants(operation), src, _cache.targets, - ptr_to_jlong(cbstruct->dragContext)); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - flush_cache(env); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - (*env)->PopLocalFrame(env, NULL); -} - -/** - * - */ - -static void awt_XmTransferProc(Widget w, XtPointer closure, Atom* selection, - Atom* type, XtPointer value, - unsigned long* length, int32_t* format) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - Atom req = (Atom)closure; - Display* dpy = XtDisplayOfObject(w); - jobject tName = NULL; - - /* - * Note: this method is only called to transfer data between clients - * in different JVM's or native apps. For Intra-JVM transfers the peer - * code shares the sources Transferable with the destination. - */ - - if (_cache.w == (Widget)NULL || _cache.transfer != w) { - if (value != NULL) { - XtFree(value); - value = NULL; - } - /* we have already cleaned up ... */ - return; - } - - (*env)->PushLocalFrame(env, 0); - - if (*type == None || *type == XT_CONVERT_FAIL) { - /* SECURITY: OK to call this on privileged thread - peer is secure - */ - call_dTCtxFailed(env, _cache.dtcpeer, (jlong)req); - } else { - switch (*format) { - case 8: - case 16: - case 32: { - jsize size = (*length <= INT_MAX) ? (jsize)*length : INT_MAX; - jbyteArray arry = (*env)->NewByteArray(env, size); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - call_dTCtxFailed(env, _cache.dtcpeer, (jlong)req); - - goto wayout; - } - - (*env)->SetByteArrayRegion(env, arry, 0, size, (jbyte*)value); - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - - /* SECURITY: OK to call this on privileged thread - - peer is secure */ - call_dTCtxFailed(env, _cache.dtcpeer, (jlong)req); - goto wayout; - } - - arry = (*env)->NewGlobalRef(env, arry); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - { - char* tn = XGetAtomName(dpy, *type); - - tName = (*env)->NewStringUTF(env, (const char *)tn); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - XFree((void *)tn); - } - - /* SECURITY: OK to call this on privileged thread - peer is - secure */ - call_dTCnewData(env, _cache.dtcpeer, (jlong)req, tName, arry); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - - default: - break; - } - } - - wayout: - if (value != NULL) { - XtFree(value); - value = NULL; - } - - _cache.transfersPending--; - while (_cache.transfersPending == 0 && !isDropDone()) { - AWT_WAIT(0); - } - - if (isDropDone() && _cache.flushPending) { - flush_cache(env); - } - - (*env)->PopLocalFrame(env, NULL); -} - -/** - * - */ - -static void awt_XmDragEnterProc(Widget w, XtPointer closure, - XmDropSiteEnterCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)closure; - - /* This should only be valid, but Im leaving this part of the old code */ - jboolean valid = cbstruct->dropSiteStatus == XmVALID_DROP_SITE - ? JNI_TRUE : JNI_FALSE; - - if (valid == JNI_TRUE) { - /* - * Workaround for Motif bug id #4457656. - * Pointer coordinates passed in cbstruct are incorrect. - * We have to make a round-trip query. - */ - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - XQueryPointer(awt_display, XtWindow(w), - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &modifiers); - - (*env)->PushLocalFrame(env, 0); - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCenter(env, this, XmToDnDConstants(cbstruct->operation), - convertModifiers(modifiers), xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->PopLocalFrame(env, NULL); - } -} - -/** - * - */ - -static void awt_XmDragMotionProc(Widget w, XtPointer closure, - XmDragMotionCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)closure; - - /* This should only be valid, but Im leaving this part of the old code */ - jboolean valid = cbstruct->dropSiteStatus == XmVALID_DROP_SITE - ? JNI_TRUE : JNI_FALSE; - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - XQueryPointer(awt_display, XtWindow(w), - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &modifiers); - /* - * Fix for 4285634. - * Use the cached modifiers state, since the directly queried state can - * differ from the one associated with this dnd notification. - */ - modifiers = ((XmDragContext)w)->drag.lastEventState; - if (xr != x_root || yr != y_root) { - call_dSCmouseMoved(env, this, XmToDnDConstants(cbstruct->operation), - convertModifiers(modifiers), xr, yr); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - x_root = xr; - y_root = yr; - } - - if (valid == JNI_TRUE) { - - (*env)->PushLocalFrame(env, 0); - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCmotion(env, this, XmToDnDConstants(cbstruct->operation), - convertModifiers(modifiers), xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->PopLocalFrame(env, NULL); - } else { - (*env)->PushLocalFrame(env, 0); - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCexit(env, this, xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->PopLocalFrame(env, NULL); - } -} - -/** - * - */ - -static void awt_XmDragLeaveProc(Widget w, XtPointer closure, - XmDropSiteLeaveCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)closure; - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - XQueryPointer(XtDisplay(w), XtWindow(w), - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &modifiers); - - (*env)->PushLocalFrame(env, 0); - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCexit(env, this, xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->PopLocalFrame(env, NULL); -} - -/** - * - */ - -static void awt_XmDropOperationChangedProc(Widget w, XtPointer closure, - XmDropStartCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)closure; - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - XQueryPointer(XtDisplay(w), XtWindow(w), - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &modifiers); - - (*env)->PushLocalFrame(env, 0); - - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCchanged(env, this, XmToDnDConstants(cbstruct->operation), - convertModifiers(modifiers), xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->PopLocalFrame(env, NULL); -} - -/** - * - */ - -static void awt_XmDropFinishProc(Widget w, XtPointer closure, - XmDropFinishCallbackStruct* cbstruct) -{ - JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject this = (jobject)closure; - unsigned char completionStatus = cbstruct->completionStatus; - jint dropAction = XmToDnDConstants(cbstruct->operation); - Window rootWindow, childWindow; - int32_t xw, yw, xr, yr; - uint32_t modifiers; - - XQueryPointer(XtDisplay(w), XtWindow(w), - &rootWindow, &childWindow, &xr, &yr, &xw, &yw, &modifiers); - - /* cleanup */ - - if (_cache.transfer == NULL) { - dropAction = _cache.dropAction; - } - - _cache.dropAction = java_awt_dnd_DnDConstants_ACTION_NONE; - _cache.win = None; - _cache.state = 0; - XtRemoveEventHandler(w, ButtonReleaseMask, False, - dragsource_track_release, NULL); - - /* SECURITY: OK to call this on privileged thread - peer is secure */ - call_dSCddfinished(env, this, completionStatus, dropAction, xr, yr); - - if (!JNU_IsNull(env, (*env)->ExceptionOccurred(env))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - awt_cleanupConvertDataContext(env, MOTIF_DROP_ATOM); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_XmDnD.h --- a/jdk/src/solaris/native/sun/awt/awt_XmDnD.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright 1997-2001 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. - */ - -#include -#include -#include -#include - -/** - * - */ - -typedef struct DropSiteInfo { - Widget tlw; - - jobject component; - Boolean isComposite; - uint32_t dsCnt; -} DropSiteInfo; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_dnd.c --- a/jdk/src/solaris/native/sun/awt/awt_dnd.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,887 +0,0 @@ -/* - * Copyright 2003-2006 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_dnd.h" - -#include "awt_p.h" - -#include "java_awt_dnd_DnDConstants.h" - -/* Shared atoms */ - -Atom XA_WM_STATE; -Atom XA_DELETE; - -/* XDnD atoms */ - -Atom XA_XdndAware; -Atom XA_XdndProxy; - -Atom XA_XdndEnter; -Atom XA_XdndPosition; -Atom XA_XdndLeave; -Atom XA_XdndDrop; -Atom XA_XdndStatus; -Atom XA_XdndFinished; - -Atom XA_XdndTypeList; -Atom XA_XdndSelection; - -Atom XA_XdndActionCopy; -Atom XA_XdndActionMove; -Atom XA_XdndActionLink; -Atom XA_XdndActionAsk; -Atom XA_XdndActionPrivate; -Atom XA_XdndActionList; - -/* Motif DnD atoms */ - -Atom _XA_MOTIF_DRAG_WINDOW; -Atom _XA_MOTIF_DRAG_TARGETS; -Atom _XA_MOTIF_DRAG_INITIATOR_INFO; -Atom _XA_MOTIF_DRAG_RECEIVER_INFO; -Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE; -Atom _XA_MOTIF_ATOM_0; -Atom XA_XmTRANSFER_SUCCESS; -Atom XA_XmTRANSFER_FAILURE; - -unsigned char MOTIF_BYTE_ORDER = 0; - -static Window awt_root_window = None; - -static Boolean -init_atoms(Display* display) { - struct atominit { - Atom *atomptr; - const char *name; - }; - - /* Add new atoms to this list */ - static struct atominit atom_list[] = { - /* Shared atoms */ - { &XA_WM_STATE, "WM_STATE" }, - { &XA_DELETE, "DELETE" }, - - /* XDnD atoms */ - { &XA_XdndAware, "XdndAware" }, - { &XA_XdndProxy, "XdndProxy" }, - { &XA_XdndEnter, "XdndEnter" }, - { &XA_XdndPosition, "XdndPosition" }, - { &XA_XdndLeave, "XdndLeave" }, - { &XA_XdndDrop, "XdndDrop" }, - { &XA_XdndStatus, "XdndStatus" }, - { &XA_XdndFinished, "XdndFinished" }, - { &XA_XdndTypeList, "XdndTypeList" }, - { &XA_XdndSelection, "XdndSelection" }, - { &XA_XdndActionCopy, "XdndActionCopy" }, - { &XA_XdndActionMove, "XdndActionMove" }, - { &XA_XdndActionLink, "XdndActionLink" }, - { &XA_XdndActionAsk, "XdndActionAsk" }, - { &XA_XdndActionPrivate, "XdndActionPrivate" }, - { &XA_XdndActionList, "XdndActionList" }, - - /* Motif DnD atoms */ - { &_XA_MOTIF_DRAG_WINDOW, "_MOTIF_DRAG_WINDOW" }, - { &_XA_MOTIF_DRAG_TARGETS, "_MOTIF_DRAG_TARGETS" }, - { &_XA_MOTIF_DRAG_INITIATOR_INFO, "_MOTIF_DRAG_INITIATOR_INFO" }, - { &_XA_MOTIF_DRAG_RECEIVER_INFO, "_MOTIF_DRAG_RECEIVER_INFO" }, - { &_XA_MOTIF_DRAG_AND_DROP_MESSAGE, "_MOTIF_DRAG_AND_DROP_MESSAGE" }, - { &_XA_MOTIF_ATOM_0, "_MOTIF_ATOM_0" }, - { &XA_XmTRANSFER_SUCCESS, "XmTRANSFER_SUCCESS" }, - { &XA_XmTRANSFER_FAILURE, "XmTRANSFER_FAILURE" } - }; - -#define ATOM_LIST_LENGTH (sizeof(atom_list)/sizeof(atom_list[0])) - - const char *names[ATOM_LIST_LENGTH]; - Atom atoms[ATOM_LIST_LENGTH]; - Status status; - size_t i; - - /* Fill the array of atom names */ - for (i = 0; i < ATOM_LIST_LENGTH; ++i) { - names[i] = atom_list[i].name; - } - - DTRACE_PRINT2("%s:%d initializing atoms ... ", __FILE__, __LINE__); - - status = XInternAtoms(awt_display, (char**)names, ATOM_LIST_LENGTH, - False, atoms); - if (status == 0) { - DTRACE_PRINTLN("failed"); - return False; - } - - /* Store returned atoms into corresponding global variables */ - DTRACE_PRINTLN("ok"); - for (i = 0; i < ATOM_LIST_LENGTH; ++i) { - *atom_list[i].atomptr = atoms[i]; - } - - return True; -#undef ATOM_LIST_LENGTH -} - -/* - * NOTE: must be called after awt_root_shell is created and realized. - */ -Boolean -awt_dnd_init(Display* display) { - static Boolean inited = False; - - if (!inited) { - Boolean atoms_inited = False; - Boolean ds_inited = False; - unsigned int value = 1; - MOTIF_BYTE_ORDER = (*((char*)&value) != 0) ? 'l' : 'B'; - - /* NOTE: init_atoms() should be called before the rest of initialization - so that atoms can be used. */ - inited = init_atoms(display); - - if (inited) { - if (XtIsRealized(awt_root_shell)) { - awt_root_window = XtWindow(awt_root_shell); - } else { - inited = False; - } - } - - inited = inited && awt_dnd_ds_init(display); - } - - return inited; -} - -/* - * Returns a window of awt_root_shell. - */ -Window -get_awt_root_window() { - return awt_root_window; -} - -static unsigned char local_xerror_code = Success; - -static int -xerror_handler(Display *dpy, XErrorEvent *err) { - local_xerror_code = err->error_code; - return 0; -} - -/**************** checked_X* wrappers *****************************************/ -#undef NO_SYNC -#undef SYNC_TRACE - -unsigned char -checked_XChangeProperty(Display* display, Window w, Atom property, Atom type, - int format, int mode, unsigned char* data, - int nelements) { - XErrorHandler xerror_saved_handler; - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 1\n"); -#endif -#endif - local_xerror_code = Success; - xerror_saved_handler = XSetErrorHandler(xerror_handler); - - XChangeProperty(display, w, property, type, format, mode, data, nelements); - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 2\n"); -#endif -#endif - XSetErrorHandler(xerror_saved_handler); - - return local_xerror_code; -} - -unsigned char -checked_XGetWindowProperty(Display* display, Window w, Atom property, long long_offset, - long long_length, Bool delete, Atom req_type, - Atom* actual_type_return, int* actual_format_return, - unsigned long* nitems_return, unsigned long* bytes_after_return, - unsigned char** prop_return) { - - XErrorHandler xerror_saved_handler; - int ret_val = Success; - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 3\n"); -#endif -#endif - local_xerror_code = Success; - xerror_saved_handler = XSetErrorHandler(xerror_handler); - - ret_val = XGetWindowProperty(display, w, property, long_offset, long_length, - delete, req_type, actual_type_return, - actual_format_return, nitems_return, - bytes_after_return, prop_return); - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 4\n"); -#endif -#endif - XSetErrorHandler(xerror_saved_handler); - - return ret_val != Success ? local_xerror_code : Success; -} - -unsigned char -checked_XSendEvent(Display* display, Window w, Bool propagate, long event_mask, - XEvent* event_send) { - - XErrorHandler xerror_saved_handler; - Status ret_val = 0; - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 5\n"); -#endif -#endif - local_xerror_code = Success; - xerror_saved_handler = XSetErrorHandler(xerror_handler); - - ret_val = XSendEvent(display, w, propagate, event_mask, event_send); - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 6\n"); -#endif -#endif - XSetErrorHandler(xerror_saved_handler); - - return ret_val == 0 ? local_xerror_code : Success; -} - -/* - * NOTE: returns Success even if the two windows aren't on the same screen. - */ -unsigned char -checked_XTranslateCoordinates(Display* display, Window src_w, Window dest_w, - int src_x, int src_y, int* dest_x_return, - int* dest_y_return, Window* child_return) { - - XErrorHandler xerror_saved_handler; - Bool ret_val = True; - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 7\n"); -#endif -#endif - local_xerror_code = Success; - xerror_saved_handler = XSetErrorHandler(xerror_handler); - - ret_val = XTranslateCoordinates(display, src_w, dest_w, src_x, src_y, - dest_x_return, dest_y_return, child_return); - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 8\n"); -#endif -#endif - XSetErrorHandler(xerror_saved_handler); - - return local_xerror_code; -} - -unsigned char -checked_XSelectInput(Display* display, Window w, long event_mask) { - XErrorHandler xerror_saved_handler; - Bool ret_val = True; - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 7\n"); -#endif -#endif - local_xerror_code = Success; - xerror_saved_handler = XSetErrorHandler(xerror_handler); - - XSelectInput(display, w, event_mask); - -#ifndef NO_SYNC - XSync(display, False); -#ifdef SYNC_TRACE - fprintf(stderr,"XSync 8\n"); -#endif -#endif - XSetErrorHandler(xerror_saved_handler); - - return local_xerror_code; -} -/******************************************************************************/ - -jint -xdnd_to_java_action(Atom action) { - if (action == XA_XdndActionCopy) { - return java_awt_dnd_DnDConstants_ACTION_COPY; - } else if (action == XA_XdndActionMove) { - return java_awt_dnd_DnDConstants_ACTION_MOVE; - } else if (action == XA_XdndActionLink) { - return java_awt_dnd_DnDConstants_ACTION_LINK; - } else if (action == None) { - return java_awt_dnd_DnDConstants_ACTION_NONE; - } else { - /* XdndActionCopy is the default. */ - return java_awt_dnd_DnDConstants_ACTION_COPY; - } -} - -Atom -java_to_xdnd_action(jint action) { - switch (action) { - case java_awt_dnd_DnDConstants_ACTION_COPY: return XA_XdndActionCopy; - case java_awt_dnd_DnDConstants_ACTION_MOVE: return XA_XdndActionMove; - case java_awt_dnd_DnDConstants_ACTION_LINK: return XA_XdndActionLink; - default: return None; - } -} - -void -write_card8(void** p, CARD8 value) { - CARD8** card8_pp = (CARD8**)p; - **card8_pp = value; - (*card8_pp)++; -} - -void -write_card16(void** p, CARD16 value) { - CARD16** card16_pp = (CARD16**)p; - **card16_pp = value; - (*card16_pp)++; -} - -void -write_card32(void** p, CARD32 value) { - CARD32** card32_pp = (CARD32**)p; - **card32_pp = value; - (*card32_pp)++; -} - -CARD8 -read_card8(char* data, size_t offset) { - return *((CARD8*)(data + offset)); -} - -CARD16 -read_card16(char* data, size_t offset, char byte_order) { - CARD16 card16 = *((CARD16*)(data + offset)); - - if (byte_order != MOTIF_BYTE_ORDER) { - SWAP2BYTES(card16); - } - - return card16; -} - -CARD32 -read_card32(char* data, size_t offset, char byte_order) { - CARD32 card32 = *((CARD32*)(data + offset)); - - if (byte_order != MOTIF_BYTE_ORDER) { - SWAP4BYTES(card32); - } - - return card32; -} - -static Window -read_motif_window(Display* dpy) { - Window root_window = DefaultRootWindow(dpy); - Window motif_window = None; - - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - ret = checked_XGetWindowProperty(dpy, root_window, _XA_MOTIF_DRAG_WINDOW, - 0, 0xFFFF, False, AnyPropertyType, &type, - &format, &nitems, &after, &data); - - if (ret != Success) { - DTRACE_PRINTLN2("%s:%d Failed to read _MOTIF_DRAG_WINDOW.", - __FILE__, __LINE__); - return None; - } - - - if (type == XA_WINDOW && format == 32 && nitems == 1) { - motif_window = *((Window*)data); - } - - XFree ((char *)data); - - return motif_window; -} - -static Window -create_motif_window(Display* dpy) { - Window root_window = DefaultRootWindow(dpy); - Window motif_window = None; - Display* display = NULL; - XSetWindowAttributes swa; - - display = XOpenDisplay(XDisplayString(dpy)); - if (display == NULL) { - return None; - } - - XGrabServer(display); - - XSetCloseDownMode(display, RetainPermanent); - - swa.override_redirect = True; - swa.event_mask = PropertyChangeMask; - motif_window = XCreateWindow(display, root_window, - -10, -10, 1, 1, 0, 0, - InputOnly, CopyFromParent, - (CWOverrideRedirect|CWEventMask), - &swa); - XMapWindow(display, motif_window); - - XChangeProperty(display, root_window, _XA_MOTIF_DRAG_WINDOW, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&motif_window, 1); - - XUngrabServer(display); - - XCloseDisplay(display); - - return motif_window; -} - -Window -get_motif_window(Display* dpy) { - /* - * Note: it is unsafe to cache the motif drag window handle, as another - * client can change the _MOTIF_DRAG_WINDOW property on the root, the handle - * becomes out-of-sync and all subsequent drag operations will fail. - */ - Window motif_window = read_motif_window(dpy); - if (motif_window == None) { - motif_window = create_motif_window(dpy); - } - - return motif_window; -} - -typedef struct { - CARD16 num_targets; - Atom* targets; -} TargetsTableEntry; - -typedef struct { - CARD16 num_entries; - TargetsTableEntry* entries; -} TargetsTable; - -typedef struct { - CARD8 byte_order; - CARD8 protocol_version; - CARD16 num_entries B16; - CARD32 heap_offset B32; -} TargetsPropertyRec; - -static TargetsTable* -get_target_list_table(Display* dpy) { - Window motif_window = get_motif_window(dpy); - TargetsTable* targets_table = NULL; - TargetsPropertyRec* targets_property_rec_ptr; - char* bufptr; - - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - unsigned int i, j; - - ret = checked_XGetWindowProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS, - 0L, 100000L, False, _XA_MOTIF_DRAG_TARGETS, - &type, &format, &nitems, &after, - (unsigned char**)&targets_property_rec_ptr); - - if (ret != Success || type != _XA_MOTIF_DRAG_TARGETS || - targets_property_rec_ptr == NULL) { - - DTRACE_PRINT2("%s:%d Cannot read _XA_MOTIF_DRAG_TARGETS", __FILE__, __LINE__); - return NULL; - } - - if (targets_property_rec_ptr->protocol_version != - MOTIF_DND_PROTOCOL_VERSION) { - DTRACE_PRINT2("%s:%d incorrect protocol version", __FILE__, __LINE__); - return NULL; - } - - if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) { - SWAP2BYTES(targets_property_rec_ptr->num_entries); - SWAP4BYTES(targets_property_rec_ptr->heap_offset); - } - - targets_table = (TargetsTable*)malloc(sizeof(TargetsTable)); - if (targets_table == NULL) { - DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__); - return NULL; - } - targets_table->num_entries = targets_property_rec_ptr->num_entries; - targets_table->entries = - (TargetsTableEntry*)malloc(sizeof(TargetsTableEntry) * - targets_property_rec_ptr->num_entries); - if (targets_table->entries == NULL) { - DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__); - free(targets_table); - return NULL; - } - - bufptr = (char *)targets_property_rec_ptr + sizeof(TargetsPropertyRec); - for (i = 0; i < targets_table->num_entries; i++) { - CARD16 num_targets; - Atom* targets; - memcpy(&num_targets, bufptr, 2 ); - bufptr += 2; - if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) { - SWAP2BYTES(num_targets); - } - - targets = (Atom*)malloc(sizeof(Atom) * num_targets); - if (targets == NULL) { - DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__); - free(targets_table->entries); - free(targets_table); - return NULL; - } - for (j = 0; j < num_targets; j++) { - CARD32 target; - memcpy(&target, bufptr, 4 ); - bufptr += 4; - if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) { - SWAP4BYTES(target); - } - targets[j] = (Atom)target; - } - - targets_table->entries[i].num_targets = num_targets; - targets_table->entries[i].targets = targets; - } - - free(targets_property_rec_ptr); - - return targets_table; -} - -static void -put_target_list_table(Display* dpy, TargetsTable* table) { - Window motif_window = get_motif_window(dpy); - TargetsPropertyRec* targets_property_rec_ptr; - size_t table_size = sizeof(TargetsPropertyRec); - unsigned char ret; - int i, j; - char* buf; - - for (i = 0; i < table->num_entries; i++) { - table_size += table->entries[i].num_targets * sizeof(Atom) + 2; - } - - targets_property_rec_ptr = (TargetsPropertyRec*)malloc(table_size); - if (targets_property_rec_ptr == NULL) { - DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__); - return; - } - targets_property_rec_ptr->byte_order = MOTIF_BYTE_ORDER; - targets_property_rec_ptr->protocol_version = MOTIF_DND_PROTOCOL_VERSION; - targets_property_rec_ptr->num_entries = table->num_entries; - targets_property_rec_ptr->heap_offset = table_size; - - buf = (char*)targets_property_rec_ptr + sizeof(TargetsPropertyRec); - - for (i = 0; i < table->num_entries; i++) { - CARD16 num_targets = table->entries[i].num_targets; - memcpy(buf, &num_targets, 2); - buf += 2; - - for (j = 0; j < num_targets; j++) { - CARD32 target = table->entries[i].targets[j]; - memcpy(buf, &target, 4); - buf += 4; - } - } - - ret = checked_XChangeProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS, - _XA_MOTIF_DRAG_TARGETS, 8, PropModeReplace, - (unsigned char*)targets_property_rec_ptr, - (int)table_size); - - if (ret != Success) { - DTRACE_PRINT2("%s:%d XChangeProperty failed", __FILE__, __LINE__); - } - - XtFree((char*)targets_property_rec_ptr); -} - -static int -_compare(const void* p1, const void* p2) { - long diff = *(Atom*)p1 - *(Atom*)p2; - - if (diff > 0) { - return 1; - } else if (diff < 0) { - return -1; - } else { - return 0; - } -} - -/* - * Returns the index for the specified target list or -1 on failure. - */ -int -get_index_for_target_list(Display* dpy, Atom* targets, unsigned int num_targets) { - TargetsTable* targets_table = NULL; - Atom* sorted_targets = NULL; - int i, j; - int ret = -1; - - if (targets == NULL && num_targets > 0) { - DTRACE_PRINT4("%s:%d targets=%X num_targets=%d", - __FILE__, __LINE__, targets, num_targets); - return -1; - } - - if (num_targets > 0) { - sorted_targets = (Atom*)malloc(sizeof(Atom) * num_targets); - if (sorted_targets == NULL) { - DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__); - return -1; - } - - memcpy(sorted_targets, targets, sizeof(Atom) * num_targets); - qsort ((void *)sorted_targets, (size_t)num_targets, (size_t)sizeof(Atom), - _compare); - } - - XGrabServer(dpy); - targets_table = get_target_list_table(dpy); - - if (targets_table != NULL) { - for (i = 0; i < targets_table->num_entries; i++) { - TargetsTableEntry* entry_ptr = &targets_table->entries[i]; - Boolean equals = True; - if (num_targets == entry_ptr->num_targets) { - for (j = 0; j < entry_ptr->num_targets; j++) { - if (sorted_targets[j] != entry_ptr->targets[j]) { - equals = False; - break; - } - } - } else { - equals = False; - } - - if (equals) { - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - free((char*)sorted_targets); - return i; - } - } - } else { - targets_table = (TargetsTable*)malloc(sizeof(TargetsTable)); - targets_table->num_entries = 0; - targets_table->entries = NULL; - } - - /* Index not found - expand the table. */ - targets_table->entries = - (TargetsTableEntry*)realloc((char*)targets_table->entries, - sizeof(TargetsTableEntry) * - (targets_table->num_entries + 1)); - if (targets_table->entries == NULL) { - DTRACE_PRINT2("%s:%d realloc failed.", __FILE__, __LINE__); - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - free((char*)sorted_targets); - return -1; - } - - /* Fill in the new entry */ - { - TargetsTableEntry* new_entry = - &targets_table->entries[targets_table->num_entries]; - - new_entry->num_targets = num_targets; - if (num_targets > 0) { - new_entry->targets = (Atom*)malloc(sizeof(Atom) * num_targets); - if (new_entry->targets == NULL) { - DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__); - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - free((char*)sorted_targets); - return -1; - } - memcpy(new_entry->targets, sorted_targets, - sizeof(Atom) * num_targets); - } else { - new_entry->targets = NULL; - } - } - - targets_table->num_entries++; - - put_target_list_table(dpy, targets_table); - - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - - ret = targets_table->num_entries - 1; - - free((char*)sorted_targets); - - for (i = 0; i < targets_table->num_entries; i++) { - free((char*)targets_table->entries[i].targets); - } - - free((char*)targets_table->entries); - free((char*)targets_table); - return ret; -} - -/* - * Retrieves the target list for the specified index. - * Stores the number of targets in the list to 'num_targets' and the targets - * to 'targets'. On failure stores 0 and NULL respectively. - * The caller should free the allocated array when done with it. - */ -void -get_target_list_for_index(Display* dpy, int index, Atom** targets, unsigned int* num_targets) { - TargetsTable* table = get_target_list_table(dpy); - TargetsTableEntry* entry = NULL; - - if (table == NULL) { - DTRACE_PRINT2("%s:%d No target table.", __FILE__, __LINE__); - *targets = NULL; - *num_targets = 0; - return; - } - - if (table->num_entries <= index) { - DTRACE_PRINT4("%s:%d index out of bounds idx=%d entries=%d", - __FILE__, __LINE__, index, table->num_entries); - *targets = NULL; - *num_targets = 0; - return; - } - - entry = &table->entries[index]; - - *targets = (Atom*)malloc(entry->num_targets * sizeof(Atom)); - - if (*targets == NULL) { - DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__); - *num_targets = 0; - return; - } - - memcpy(*targets, entry->targets, entry->num_targets * sizeof(Atom)); - *num_targets = entry->num_targets; -} - -jint -motif_to_java_actions(unsigned char motif_action) { - jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE; - - if (motif_action & MOTIF_DND_COPY) { - java_action |= java_awt_dnd_DnDConstants_ACTION_COPY; - } - - if (motif_action & MOTIF_DND_MOVE) { - java_action |= java_awt_dnd_DnDConstants_ACTION_MOVE; - } - - if (motif_action & MOTIF_DND_LINK) { - java_action |= java_awt_dnd_DnDConstants_ACTION_LINK; - } - - return java_action; -} - -unsigned char -java_to_motif_actions(jint java_action) { - unsigned char motif_action = MOTIF_DND_NOOP; - - if (java_action & java_awt_dnd_DnDConstants_ACTION_COPY) { - motif_action |= MOTIF_DND_COPY; - } - - if (java_action & java_awt_dnd_DnDConstants_ACTION_MOVE) { - motif_action |= MOTIF_DND_MOVE; - } - - if (java_action & java_awt_dnd_DnDConstants_ACTION_LINK) { - motif_action |= MOTIF_DND_LINK; - } - - return motif_action; -} - -Boolean -awt_dnd_process_event(XEvent* event) { - Boolean ret = awt_dnd_ds_process_event(event) || - awt_dnd_dt_process_event(event); - - /* Extract the event from the queue if it is processed. */ - if (ret) { - XNextEvent(event->xany.display, event); - } - - return ret; -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_dnd.h --- a/jdk/src/solaris/native/sun/awt/awt_dnd.h Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ -/* - * Copyright 2003-2004 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include - -#include "awt_p.h" - -/* For definition of MComponentPeerIDs */ -#include "awt_Component.h" - -extern struct MComponentPeerIDs mComponentPeerIDs; - -/* DnD protocols */ - -typedef enum { - NO_PROTOCOL, - XDND_PROTOCOL, - MOTIF_DND_PROTOCOL -} Protocol; - -/* XDnD constants */ - -#define XDND_PROTOCOL_VERSION 5 -/* XDnD compliance only requires supporting version 3 and up. */ -#define XDND_MIN_PROTOCOL_VERSION 3 - -#define XDND_PROTOCOL_MASK 0xFF000000 -#define XDND_PROTOCOL_SHIFT 24 -#define XDND_DATA_TYPES_BIT 0x1 -#define XDND_ACCEPT_DROP_FLAG 0x1 - -/* Motif DnD constants */ - -#define MOTIF_DND_PROTOCOL_VERSION 0 - -/* Suuported protocol styles */ -#define MOTIF_PREFER_PREREGISTER_STYLE 2 -#define MOTIF_PREFER_DYNAMIC_STYLE 4 -#define MOTIF_DYNAMIC_STYLE 5 -#define MOTIF_PREFER_RECEIVER_STYLE 6 - -#define MOTIF_MESSAGE_REASON_MASK 0x7F -#define MOTIF_MESSAGE_SENDER_MASK 0x80 -#define MOTIF_MESSAGE_FROM_RECEIVER 0x80 -#define MOTIF_MESSAGE_FROM_INITIATOR 0 - -/* Info structure sizes */ -#define MOTIF_INITIATOR_INFO_SIZE 8 -#define MOTIF_RECEIVER_INFO_SIZE 16 - -/* Message flags masks and shifts */ -#define MOTIF_DND_ACTION_MASK 0x000F -#define MOTIF_DND_ACTION_SHIFT 0 -#define MOTIF_DND_STATUS_MASK 0x00F0 -#define MOTIF_DND_STATUS_SHIFT 4 -#define MOTIF_DND_ACTIONS_MASK 0x0F00 -#define MOTIF_DND_ACTIONS_SHIFT 8 - -/* message type constants */ -#define TOP_LEVEL_ENTER 0 -#define TOP_LEVEL_LEAVE 1 -#define DRAG_MOTION 2 -#define DROP_SITE_ENTER 3 -#define DROP_SITE_LEAVE 4 -#define DROP_START 5 -#define DROP_FINISH 6 -#define DRAG_DROP_FINISH 7 -#define OPERATION_CHANGED 8 - -/* drop action constants */ -#define MOTIF_DND_NOOP 0L -#define MOTIF_DND_MOVE (1L << 0) -#define MOTIF_DND_COPY (1L << 1) -#define MOTIF_DND_LINK (1L << 2) - -/* drop site status constants */ -#define MOTIF_NO_DROP_SITE 1 -#define MOTIF_INVALID_DROP_SITE 2 -#define MOTIF_VALID_DROP_SITE 3 - -/* Shared atoms */ - -extern Atom XA_WM_STATE; -extern Atom XA_DELETE; - -/* XDnD atoms */ - -extern Atom XA_XdndAware; -extern Atom XA_XdndProxy; - -extern Atom XA_XdndEnter; -extern Atom XA_XdndPosition; -extern Atom XA_XdndLeave; -extern Atom XA_XdndDrop; -extern Atom XA_XdndStatus; -extern Atom XA_XdndFinished; - -extern Atom XA_XdndTypeList; -extern Atom XA_XdndSelection; - -extern Atom XA_XdndActionCopy; -extern Atom XA_XdndActionMove; -extern Atom XA_XdndActionLink; -extern Atom XA_XdndActionAsk; -extern Atom XA_XdndActionPrivate; -extern Atom XA_XdndActionList; - -/* Motif DnD atoms */ - -extern Atom _XA_MOTIF_DRAG_WINDOW; -extern Atom _XA_MOTIF_DRAG_TARGETS; -extern Atom _XA_MOTIF_DRAG_INITIATOR_INFO; -extern Atom _XA_MOTIF_DRAG_RECEIVER_INFO; -extern Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE; -extern Atom XA_XmTRANSFER_SUCCESS; -extern Atom XA_XmTRANSFER_FAILURE; -extern Atom _XA_MOTIF_ATOM_0; - -extern unsigned char MOTIF_BYTE_ORDER; - -/* Motif DnD macros */ - -#define SWAP4BYTES(l) {\ - struct {\ - unsigned t :32;\ - } bit32;\ - char n, *tp = (char *) &bit32;\ - bit32.t = l;\ - n = tp[0]; tp[0] = tp[3]; tp[3] = n;\ - n = tp[1]; tp[1] = tp[2]; tp[2] = n;\ - l = bit32.t;\ -} - -#define SWAP2BYTES(s) {\ - struct {\ - unsigned t :16;\ - } bit16;\ - char n, *tp = (char *) &bit16;\ - bit16.t = s;\ - n = tp[0]; tp[0] = tp[1]; tp[1] = n;\ - s = bit16.t;\ -} - -typedef struct DropSiteInfo { - Widget tlw; - jobject component; - Boolean isComposite; - uint32_t dsCnt; -} DropSiteInfo; - -Boolean awt_dnd_init(Display* display); -Boolean awt_dnd_ds_init(Display* display); - -Window get_awt_root_window(); - -/**************** checked_X* wrappers *****************************************/ -unsigned char -checked_XChangeProperty(Display* display, Window w, Atom property, Atom type, - int format, int mode, unsigned char* data, - int nelements); - -unsigned char -checked_XGetWindowProperty(Display* display, Window w, Atom property, - long long_offset, long long_length, Bool delete, - Atom req_type, Atom* actual_type_return, - int* actual_format_return, - unsigned long* nitems_return, - unsigned long* bytes_after_return, - unsigned char** prop_return); - -unsigned char -checked_XSendEvent(Display* display, Window w, Bool propagate, long event_mask, - XEvent* event_send); - -unsigned char -checked_XTranslateCoordinates(Display* display, Window src_w, Window dest_w, - int src_x, int src_y, int* dest_x_return, - int* dest_y_return, Window* child_return); - -unsigned char -checked_XSelectInput(Display* display, Window w, long event_mask); -/******************************************************************************/ - -jint xdnd_to_java_action(Atom action); -Atom java_to_xdnd_action(jint action); - -jint motif_to_java_actions(unsigned char action); -unsigned char java_to_motif_actions(jint action); - -void write_card8(void** p, CARD8 value); -void write_card16(void** p, CARD16 value); -void write_card32(void** p, CARD32 value); - -CARD8 read_card8(char* data, size_t offset); -CARD16 read_card16(char* data, size_t offset, char byte_order); -CARD32 read_card32(char* data, size_t offset, char byte_order); - -Window get_motif_window(Display* dpy); - -/*************************** TARGET LIST SUPPORT ***************************************/ - -int get_index_for_target_list(Display* dpy, Atom* targets, unsigned int num_targets); -void get_target_list_for_index(Display* dpy, int index, Atom** targets, unsigned - int* num_targets); - -/***************************************************************************************/ - -Boolean awt_dnd_process_event(XEvent* event); -Boolean awt_dnd_ds_process_event(XEvent* event); -Boolean awt_dnd_dt_process_event(XEvent* event); - -Window awt_dnd_ds_get_source_window(); - -/**************************** XEmbed server DnD support ***********************/ -void set_proxy_mode_source_window(Window window); -/******************************************************************************/ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_dnd_ds.c --- a/jdk/src/solaris/native/sun/awt/awt_dnd_ds.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1796 +0,0 @@ -/* - * Copyright 2003-2006 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_dnd.h" - -/* Declares getCursor(JNIEnv, jobject) */ -#include "awt_Cursor.h" - -/* Define java constants */ -#include "java_awt_dnd_DnDConstants.h" -#include "sun_awt_dnd_SunDragSourceContextPeer.h" - -/* Define DECLARE_* macros */ -#include "awt_DataTransferer.h" - -#define GRAB_EVENT_MASK \ - (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask) - -/* Events selected on the root window during drag. */ -#define ROOT_EVENT_MASK \ - (ButtonMotionMask | KeyPressMask | KeyReleaseMask) - -/* Events selected on registered receiver windows during drag. */ -#define RECEIVER_EVENT_MASK \ - (StructureNotifyMask) - - -/* in canvas.c */ -extern jint getModifiers(uint32_t state, jint button, jint keyCode); - -typedef struct { - CARD8 byte_order; - CARD8 protocol_version; - CARD16 index; - CARD32 selection_atom; -} InitiatorInfo; - -typedef enum { - /* - * Communicate with receivers of both protocols. - * If the receiver supports both protocols, - * choose Motif DnD for communication. - */ - DS_POLICY_PREFER_MOTIF, - /* - * Communicate with receivers of both protocols. - * If the receiver supports both protocols, - * choose XDnD for communication. [default] - */ - DS_POLICY_PREFER_XDND, - /* Communicate only with Motif DnD receivers. */ - DS_POLICY_ONLY_MOTIF, - /* Communicate only with XDnD receivers. */ - DS_POLICY_ONLY_XDND -} DragSourcePolicy; - - -/* The drag source policy. */ -static DragSourcePolicy drag_source_policy = DS_POLICY_PREFER_XDND; - -static Boolean dnd_in_progress = False; -static Boolean drag_in_progress = False; -static jobject source_peer = NULL; -static Atom* data_types = NULL; -static unsigned int data_types_count = 0; -static Window drag_root_window = None; -static EventMask your_root_event_mask = NoEventMask; -static Time latest_time_stamp = CurrentTime; - -/* The child of the root which is currently under the mouse. */ -static Window target_root_subwindow = None; - -static Window target_window = None; -static long target_window_mask = 0; -static Window target_proxy_window = None; -static Protocol target_protocol = NO_PROTOCOL; -static unsigned int target_protocol_version = 0; -/* - * The server time when the pointer entered the current target - - * needed on Motif DnD to filter out messages from the previous - * target. - * It is updated whenever the target_window is updated. - * If the target_window is set to non-None, it is set to the time stamp - * of the X event that trigger the update. Otherwise, it is set to CurrentTime. - */ -static Time target_enter_server_time = CurrentTime; - -static int x_root = 0; -static int y_root = 0; -static unsigned int event_state = 0; - -static jint source_action = java_awt_dnd_DnDConstants_ACTION_NONE; -static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; -static jint target_action = java_awt_dnd_DnDConstants_ACTION_NONE; - -/* Forward declarations */ -static void cleanup_drag(Display* dpy, Time time); -static Boolean process_proxy_mode_event(XEvent* xev); - -/**************************** XEmbed server DnD support ***********************/ -static Window proxy_mode_source_window = None; -/******************************************************************************/ - -/**************************** JNI stuff ***************************************/ - -DECLARE_JAVA_CLASS(dscp_clazz, "sun/awt/dnd/SunDragSourceContextPeer") - -static void -ds_postDragSourceDragEvent(JNIEnv* env, jint targetAction, unsigned int state, - int x, int y, jint dispatch_type) { - DECLARE_VOID_JAVA_METHOD(dscp_postDragSourceDragEvent, dscp_clazz, - "postDragSourceDragEvent", "(IIIII)V"); - - DASSERT(!JNU_IsNull(env, source_peer)); - if (JNU_IsNull(env, source_peer)) { - return; - } - - (*env)->CallVoidMethod(env, source_peer, dscp_postDragSourceDragEvent, - targetAction, getModifiers(state, 0, 0), x, y, - dispatch_type); -} - -static jint -ds_convertModifiersToDropAction(JNIEnv* env, unsigned int state) { - jint action; - DECLARE_STATIC_JINT_JAVA_METHOD(dscp_convertModifiersToDropAction, dscp_clazz, - "convertModifiersToDropAction", "(II)I"); - action = (*env)->CallStaticIntMethod(env, clazz, dscp_convertModifiersToDropAction, - getModifiers(state, 0, 0), source_actions); - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - return java_awt_dnd_DnDConstants_ACTION_NONE; - } - return action; -} - -static void -ds_postDragSourceEvent(JNIEnv* env, int x, int y) { - DECLARE_VOID_JAVA_METHOD(dscp_dragExit, dscp_clazz, - "dragExit", "(II)V"); - - DASSERT(!JNU_IsNull(env, source_peer)); - if (JNU_IsNull(env, source_peer)) { - return; - } - - (*env)->CallVoidMethod(env, source_peer, dscp_dragExit, x, y); -} - -static void -ds_postDragSourceDropEvent(JNIEnv* env, jboolean success, jint targetAction, - int x, int y) { - DECLARE_VOID_JAVA_METHOD(dscp_dragDropFinished, dscp_clazz, - "dragDropFinished", "(ZIII)V"); - - DASSERT(!JNU_IsNull(env, source_peer)); - if (JNU_IsNull(env, source_peer)) { - return; - } - - (*env)->CallVoidMethod(env, source_peer, dscp_dragDropFinished, - success, targetAction, x, y); -} - -/******************************************************************************/ - -static void -cancel_drag(XtPointer client_data, XtIntervalId* id) { - Time time_stamp = awt_util_getCurrentServerTime(); - - cleanup_drag(awt_display, time_stamp); -} - -#define DONT_CARE -1 - -static void -awt_popupCallback(Widget shell, XtPointer closure, XtPointer call_data) { - XtGrabKind grab_kind = XtGrabNone; - - if (call_data != NULL) { - grab_kind = *((XtGrabKind*)call_data); - } - - if (XmIsVendorShell(shell)) { - int input_mode; - XtVaGetValues(shell, XmNmwmInputMode, &input_mode, NULL); - switch (input_mode) { - case DONT_CARE: - case MWM_INPUT_MODELESS: - grab_kind = XtGrabNonexclusive; break; - case MWM_INPUT_PRIMARY_APPLICATION_MODAL: - case MWM_INPUT_SYSTEM_MODAL: - case MWM_INPUT_FULL_APPLICATION_MODAL: - grab_kind = XtGrabExclusive; break; - } - } - - if (grab_kind == XtGrabExclusive) { - /* - * We should cancel the drag on the toolkit thread. Otherwise, it can be - * called while the toolkit thread is waiting inside some drag callback. - * In this case Motif will crash when the drag callback returns. - */ - XtAppAddTimeOut(awt_appContext, 0L, cancel_drag, NULL); - } -} - -static XtInitProc xt_shell_initialize = NULL; - -static void -awt_ShellInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args) { - XtAddCallback(new, XtNpopupCallback, awt_popupCallback, NULL); - (*xt_shell_initialize)(req, new, args, num_args); -} - -/* - * Fix for 4484572 (copied from awt_XmDnD.c). - * Modify the 'initialize' routine for all ShellWidget instances, so that it - * will install an XtNpopupCallback that cancels the current drag operation. - * It is needed, since AWT doesn't have full control over all ShellWidget - * instances (e.g. XmPopupMenu internally creates and popups an XmMenuShell). - */ -static void -awt_set_ShellInitialize() { - static Boolean inited = False; - - DASSERT(!inited); - if (inited) { - return; - } - - xt_shell_initialize = shellWidgetClass->core_class.initialize; - shellWidgetClass->core_class.initialize = (XtInitProc)awt_ShellInitialize; - inited = True; -} - -/* - * Returns True if initialization completes successfully. - */ -Boolean -awt_dnd_ds_init(Display* display) { - if (XSaveContext(display, XA_XdndSelection, awt_convertDataContext, - (XPointer)NULL) == XCNOMEM) { - return False; - } - - if (XSaveContext(display, _XA_MOTIF_ATOM_0, awt_convertDataContext, - (XPointer)NULL) == XCNOMEM) { - return False; - } - - { - char *ev = getenv("_JAVA_DRAG_SOURCE_POLICY"); - - /* By default XDnD protocol is preferred. */ - drag_source_policy = DS_POLICY_PREFER_XDND; - - if (ev != NULL) { - if (strcmp(ev, "PREFER_XDND") == 0) { - drag_source_policy = DS_POLICY_PREFER_XDND; - } else if (strcmp(ev, "PREFER_MOTIF") == 0) { - drag_source_policy = DS_POLICY_PREFER_MOTIF; - } else if (strcmp(ev, "ONLY_MOTIF") == 0) { - drag_source_policy = DS_POLICY_ONLY_MOTIF; - } else if (strcmp(ev, "ONLY_XDND") == 0) { - drag_source_policy = DS_POLICY_ONLY_XDND; - } - } - } - - awt_set_ShellInitialize(); - - return True; -} - -/* - * Returns a handle of the window used as a drag source. - */ -Window -awt_dnd_ds_get_source_window() { - return get_awt_root_window(); -} - -/* - * Returns True if a drag operation initiated by this client - * is still in progress. - */ -Boolean -awt_dnd_ds_in_progress() { - return dnd_in_progress; -} - -static void -ds_send_event_to_target(XClientMessageEvent* xclient) { - /* Shortcut if the source is in the same JVM. */ - if (XtWindowToWidget(xclient->display, target_proxy_window) != NULL) { - awt_dnd_dt_process_event((XEvent*)xclient); - } else { - XSendEvent(xclient->display, target_proxy_window, False, NoEventMask, - (XEvent*)xclient); - } -} - -static void -xdnd_send_enter(Display* dpy, Time time) { - XClientMessageEvent enter; - - enter.display = dpy; - enter.type = ClientMessage; - enter.window = target_window; - enter.format = 32; - enter.message_type = XA_XdndEnter; - enter.data.l[0] = awt_dnd_ds_get_source_window(); - enter.data.l[1] = target_protocol_version << XDND_PROTOCOL_SHIFT; - enter.data.l[1] |= data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; - enter.data.l[2] = data_types_count > 0 ? data_types[0] : None; - enter.data.l[3] = data_types_count > 1 ? data_types[1] : None; - enter.data.l[4] = data_types_count > 2 ? data_types[2] : None; - - ds_send_event_to_target(&enter); -} - -static void -motif_send_enter(Display* dpy, Time time) { - XClientMessageEvent enter; - - enter.display = dpy; - enter.type = ClientMessage; - enter.window = target_window; - enter.format = 8; - enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = &enter.data.b[0]; - int flags = 0; - - flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; - flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; - - write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, MOTIF_BYTE_ORDER); - write_card16(&p, flags); - write_card32(&p, time); - write_card32(&p, awt_dnd_ds_get_source_window()); - write_card32(&p, _XA_MOTIF_ATOM_0); - } - - ds_send_event_to_target(&enter); -} - -static void -send_enter(Display* dpy, Time time) { - switch (target_protocol) { - case XDND_PROTOCOL: - xdnd_send_enter(dpy, time); - break; - case MOTIF_DND_PROTOCOL: - motif_send_enter(dpy, time); - break; - case NO_PROTOCOL: - default: - DTRACE_PRINTLN2("%s:%d send_enter: unknown DnD protocol.", __FILE__, __LINE__); - break; - } -} - -static void -xdnd_send_move(XMotionEvent* event) { - XClientMessageEvent move; - - move.display = event->display; - move.type = ClientMessage; - move.window = target_window; - move.format = 32; - move.message_type = XA_XdndPosition; - move.data.l[0] = awt_dnd_ds_get_source_window(); - move.data.l[1] = 0; /* flags */ - move.data.l[2] = event->x_root << 16 | event->y_root; - move.data.l[3] = event->time; - move.data.l[4] = java_to_xdnd_action(source_action); - - ds_send_event_to_target(&move); -} - -static void -motif_send_move(XMotionEvent* event) { - XClientMessageEvent move; - - move.display = event->display; - move.type = ClientMessage; - move.window = target_window; - move.format = 8; - move.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = move.data.b; - int flags = 0; - - flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; - flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; - - write_card8(&p, DRAG_MOTION | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, MOTIF_BYTE_ORDER); - write_card16(&p, flags); - write_card32(&p, event->time); - write_card16(&p, event->x_root); - write_card16(&p, event->y_root); - } - - ds_send_event_to_target(&move); -} - -static void -send_move(XMotionEvent* event) { - switch (target_protocol) { - case XDND_PROTOCOL: - xdnd_send_move(event); - break; - case MOTIF_DND_PROTOCOL: - motif_send_move(event); - break; - case NO_PROTOCOL: - default: - DTRACE_PRINTLN2("%s:%d send_move: unknown DnD protocol.", __FILE__, __LINE__); - break; - } -} - -static void -xdnd_send_leave(Display* dpy, Time time) { - XClientMessageEvent leave; - - leave.display = dpy; - leave.type = ClientMessage; - leave.window = target_window; - leave.format = 32; - leave.message_type = XA_XdndLeave; - leave.data.l[0] = awt_dnd_ds_get_source_window(); - leave.data.l[1] = 0; - leave.data.l[2] = 0; - leave.data.l[3] = 0; - leave.data.l[4] = 0; - - ds_send_event_to_target(&leave); -} - -static void -motif_send_leave(Display* dpy, Time time) { - XClientMessageEvent leave; - - leave.display = dpy; - leave.type = ClientMessage; - leave.window = target_window; - leave.format = 8; - leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = &leave.data.b[0]; - - write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, MOTIF_BYTE_ORDER); - write_card16(&p, 0); - write_card32(&p, time); - write_card32(&p, awt_dnd_ds_get_source_window()); - } - - ds_send_event_to_target(&leave); -} - -static void -send_leave(Display* dpy, Time time) { - switch (target_protocol) { - case XDND_PROTOCOL: - xdnd_send_leave(dpy, time); - break; - case MOTIF_DND_PROTOCOL: - motif_send_leave(dpy, time); - break; - case NO_PROTOCOL: - default: - DTRACE_PRINTLN2("%s:%d send_leave: unknown DnD protocol.", __FILE__, __LINE__); - break; - } -} - - -static void -xdnd_send_drop(XButtonEvent* event) { - XClientMessageEvent drop; - - drop.display = event->display; - drop.type = ClientMessage; - drop.window = target_window; - drop.format = 32; - drop.message_type = XA_XdndDrop; - drop.data.l[0] = awt_dnd_ds_get_source_window(); - drop.data.l[1] = 0; /* flags */ - drop.data.l[2] = event->time; /* ### */ - drop.data.l[3] = 0; - drop.data.l[4] = 0; - - ds_send_event_to_target(&drop); -} - -static void -motif_send_drop(XButtonEvent* event) { - XClientMessageEvent drop; - - /* - * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START. - */ - motif_send_leave(event->display, event->time); - - drop.display = event->display; - drop.type = ClientMessage; - drop.window = target_window; - drop.format = 8; - drop.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = &drop.data.b[0]; - int flags = 0; - - flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; - flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; - - write_card8(&p, DROP_START | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, MOTIF_BYTE_ORDER); - write_card16(&p, flags); - write_card32(&p, event->time); - write_card16(&p, event->x_root); - write_card16(&p, event->y_root); - write_card32(&p, _XA_MOTIF_ATOM_0); - write_card32(&p, awt_dnd_ds_get_source_window()); - } - - ds_send_event_to_target(&drop); -} - -static void -send_drop(XButtonEvent* event) { - switch (target_protocol) { - case XDND_PROTOCOL: - xdnd_send_drop(event); - break; - case MOTIF_DND_PROTOCOL: - motif_send_drop(event); - break; - case NO_PROTOCOL: - default: - DTRACE_PRINTLN2("%s:%d send_drop: unknown DnD protocol.", __FILE__, __LINE__); - break; - } -} - -static void -remove_dnd_grab(Display* dpy, Time time) { - XUngrabPointer(dpy, time); - XUngrabKeyboard(dpy, time); - - /* Restore the root event mask if it was changed. */ - if ((your_root_event_mask | ROOT_EVENT_MASK) != your_root_event_mask && - drag_root_window != None) { - - XSelectInput(dpy, drag_root_window, your_root_event_mask); - - drag_root_window = None; - your_root_event_mask = NoEventMask; - } -} - -static void -cleanup_target_info(Display* dpy) { - target_root_subwindow = None; - - target_window = None; - target_proxy_window = None; - target_protocol = NO_PROTOCOL; - target_protocol_version = 0; - target_enter_server_time = CurrentTime; - target_action = java_awt_dnd_DnDConstants_ACTION_NONE; -} - -static void -cleanup_drag(Display* dpy, Time time) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - - if (dnd_in_progress) { - if (target_window != None) { - send_leave(dpy, time); - } - - if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - ds_postDragSourceEvent(env, x_root, y_root); - } - - ds_postDragSourceDropEvent(env, JNI_FALSE, - java_awt_dnd_DnDConstants_ACTION_NONE, - x_root, y_root); - } - - /* Cleanup the global state */ - dnd_in_progress = False; - drag_in_progress = False; - data_types_count = 0; - if (data_types != NULL) { - free(data_types); - data_types = NULL; - } - if (!JNU_IsNull(env, source_peer)) { - (*env)->DeleteGlobalRef(env, source_peer); - source_peer = NULL; - } - - cleanup_target_info(dpy); - - remove_dnd_grab(dpy, time); - - XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), _XA_MOTIF_ATOM_0); - XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndTypeList); - XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndActionList); - XtDisownSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time); - XtDisownSelection(awt_root_shell, XA_XdndSelection, time); - - awt_cleanupConvertDataContext(env, _XA_MOTIF_ATOM_0); - awt_cleanupConvertDataContext(env, XA_XdndSelection); -} - -static void -process_drop(XButtonEvent* event) { - unsigned char ret; - XWindowAttributes xwa; - - DASSERT(target_window != None); - - XGetWindowAttributes(event->display, target_window, &xwa); - - target_window_mask = xwa.your_event_mask; - - /* Select for DestoyNotify to cleanup if the target crashes. */ - ret = checked_XSelectInput(event->display, target_window, - (target_window_mask | StructureNotifyMask)); - - if (ret == Success) { - send_drop(event); - } else { - DTRACE_PRINTLN2("%s:%d drop rejected - invalid window.", - __FILE__, __LINE__); - cleanup_drag(event->display, event->time); - } -} - -static Window -find_client_window(Display* dpy, Window window) { - Window root, parent, *children; - unsigned int nchildren, idx; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - Status ret; - - if (XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False, - AnyPropertyType, &type, &format, &nitems, - &after, &data) == Success) { - XFree(data); - } - - if (type != None) { - return window; - } - - if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) { - return None; - } - - if (children == NULL) { - return None; - } - - for (idx = 0; idx < nchildren; idx++) { - Window win = find_client_window(dpy, children[idx]); - if (win != None) { - XFree(children); - return win; - } - } - - XFree(children); - return None; -} - -static void -do_update_target_window(Display* dpy, Window subwindow, Time time) { - Window client_window = None; - Window proxy_window = None; - Protocol protocol = NO_PROTOCOL; - unsigned int protocol_version = 0; - Boolean is_receiver = False; - - client_window = find_client_window(dpy, subwindow); - - if (client_window != None) { - /* Request status */ - int status; - - /* Returns of XGetWindowProperty */ - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - /* - * No need for checked_XGetWindowProperty, since we check the returned - * property type anyway. - */ - if (drag_source_policy != DS_POLICY_ONLY_XDND) { - - data = NULL; - status = XGetWindowProperty(dpy, client_window, - _XA_MOTIF_DRAG_RECEIVER_INFO, - 0, 0xFFFF, False, AnyPropertyType, - &type, &format, &nitems, &after, &data); - - if (status == Success && data != NULL && type != None && format == 8 - && nitems >= MOTIF_RECEIVER_INFO_SIZE) { - unsigned char byte_order = read_card8((char*)data, 0); - unsigned char drag_protocol_style = read_card8((char*)data, 2); - - switch (drag_protocol_style) { - case MOTIF_PREFER_PREREGISTER_STYLE : - case MOTIF_PREFER_DYNAMIC_STYLE : - case MOTIF_DYNAMIC_STYLE : - case MOTIF_PREFER_RECEIVER_STYLE : - proxy_window = read_card32((char*)data, 4, byte_order); - protocol = MOTIF_DND_PROTOCOL; - protocol_version = read_card8((char*)data, 1); - is_receiver = True; - break; - default: - DTRACE_PRINTLN3("%s:%d unsupported protocol style (%d).", - __FILE__, __LINE__, (int)drag_protocol_style); - } - } - - if (status == Success) { - XFree(data); - data = NULL; - } - } - - if (drag_source_policy != DS_POLICY_ONLY_MOTIF && - (drag_source_policy != DS_POLICY_PREFER_MOTIF || !is_receiver)) { - - data = NULL; - status = XGetWindowProperty(dpy, client_window, XA_XdndAware, 0, 1, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - if (status == Success && data != NULL && type == XA_ATOM) { - unsigned int target_version = *((unsigned int*)data); - - if (target_version >= XDND_MIN_PROTOCOL_VERSION) { - proxy_window = None; - protocol = XDND_PROTOCOL; - protocol_version = target_version < XDND_PROTOCOL_VERSION ? - target_version : XDND_PROTOCOL_VERSION; - is_receiver = True; - } - } - - /* Retrieve the proxy window handle and check if it is valid. */ - if (protocol == XDND_PROTOCOL) { - if (status == Success) { - XFree(data); - } - - data = NULL; - status = XGetWindowProperty(dpy, client_window, XA_XdndProxy, 0, - 1, False, XA_WINDOW, &type, &format, - &nitems, &after, &data); - - if (status == Success && data != NULL && type == XA_WINDOW) { - proxy_window = *((Window*)data); - } - - if (proxy_window != None) { - if (status == Success) { - XFree(data); - } - - data = NULL; - status = XGetWindowProperty(dpy, proxy_window, XA_XdndProxy, - 0, 1, False, XA_WINDOW, &type, - &format, &nitems, &after, &data); - - if (status != Success || data == NULL || type != XA_WINDOW || - *((Window*)data) != proxy_window) { - proxy_window = None; - } else { - if (status == Success) { - XFree(data); - } - - data = NULL; - status = XGetWindowProperty(dpy, proxy_window, - XA_XdndAware, 0, 1, False, - AnyPropertyType, &type, - &format, &nitems, &after, - &data); - - if (status != Success || data == NULL || type != XA_ATOM) { - proxy_window = None; - } - } - } - } - - XFree(data); - } - - if (proxy_window == None) { - proxy_window = client_window; - } - } - - if (is_receiver) { - target_window = client_window; - target_proxy_window = proxy_window; - target_protocol = protocol; - target_protocol_version = protocol_version; - } else { - target_window = None; - target_proxy_window = None; - target_protocol = NO_PROTOCOL; - target_protocol_version = 0; - } - - target_action = java_awt_dnd_DnDConstants_ACTION_NONE; - - if (target_window != None) { - target_enter_server_time = time; - } else { - target_enter_server_time = CurrentTime; - } - - target_root_subwindow = subwindow; -} - -static void -update_target_window(XMotionEvent* event) { - Display* dpy = event->display; - int x = event->x_root; - int y = event->x_root; - Time time = event->time; - Window subwindow = event->subwindow; - - /* - * If this event had occurred before the pointer was grabbed, - * query the server for the current root subwindow. - */ - if (event->window != event->root) { - int xw, yw, xr, yr; - unsigned int modifiers; - XQueryPointer(dpy, event->root, &event->root, &subwindow, - &xr, &yr, &xw, &yw, &modifiers); - } - - if (target_root_subwindow != subwindow) { - if (target_window != None) { - send_leave(dpy, time); - - /* - * Neither Motif DnD nor XDnD provide a mean for the target - * to notify the source that the pointer exits the drop site - * that occupies the whole top level. - * We detect this situation and post dragExit. - */ - if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - ds_postDragSourceEvent(env, x, y); - } - } - - /* Update the global state. */ - do_update_target_window(dpy, subwindow, time); - - if (target_window != None) { - send_enter(dpy, time); - } - } -} - -/* - * Updates the source action based on the specified event state. - * Returns True if source action changed, False otherwise. - */ -static Boolean -update_source_action(unsigned int state) { - JNIEnv* env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - jint action = ds_convertModifiersToDropAction(env, state); - if (source_action == action) { - return False; - } - source_action = action; - return True; -} - -static void -handle_mouse_move(XMotionEvent* event) { - if (!drag_in_progress) { - return; - } - - if (x_root != event->x_root || y_root != event->y_root) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - ds_postDragSourceDragEvent(env, target_action, event->state, - event->x_root, event->y_root, - sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOUSE_MOVED); - - x_root = event->x_root; - y_root = event->y_root; - } - - if (event_state != event->state) { - if (update_source_action(event->state) && target_window != None) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - ds_postDragSourceDragEvent(env, target_action, event->state, - event->x_root, event->y_root, - sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_CHANGED); - } - event_state = event->state; - } - - update_target_window(event); - - if (target_window != None) { - send_move(event); - } -} - -static Boolean -handle_xdnd_status(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - long* event_data = event->data.l; - Window target_win = None; - jint action = java_awt_dnd_DnDConstants_ACTION_NONE; - - DTRACE_PRINTLN4("%s:%d XdndStatus target_window=%ld target_protocol=%d.", - __FILE__, __LINE__, target_window, target_protocol); - - if (target_protocol != XDND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.", - __FILE__, __LINE__); - return True; - } - - target_win = event_data[0]; - - /* Ignore XDnD messages from all other windows. */ - if (target_window != target_win) { - DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.", - __FILE__, __LINE__, target_window, target_win); - return True; - } - - if (event_data[1] & XDND_ACCEPT_DROP_FLAG) { - /* This feature is new in XDnD version 2, but we can use it as XDnD - compliance only requires supporting version 3 and up. */ - action = xdnd_to_java_action(event_data[4]); - } - - if (action == java_awt_dnd_DnDConstants_ACTION_NONE && - target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { - ds_postDragSourceEvent(env, x_root, y_root); - } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { - jint type = 0; - - if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) { - type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER; - } else { - type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION; - } - - ds_postDragSourceDragEvent(env, action, event_state, - x_root, y_root, type); - } - - target_action = action; - - return True; -} - -static Boolean -handle_xdnd_finished(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - long* event_data = event->data.l; - Window target_win = None; - jboolean success = JNI_TRUE; - jint action = java_awt_dnd_DnDConstants_ACTION_NONE; - - if (target_protocol != XDND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.", - __FILE__, __LINE__); - return True; - } - - target_win = event_data[0]; - - /* Ignore XDnD messages from all other windows. */ - if (target_window != target_win) { - DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.", - __FILE__, __LINE__, target_window, target_win); - return True; - } - - if (target_protocol_version >= 5) { - success = (event_data[1] & XDND_ACCEPT_DROP_FLAG) != 0 ? - JNI_TRUE : JNI_FALSE; - action = xdnd_to_java_action(event_data[2]); - } else { - /* Assume that the drop was successful and the performed drop action is - the drop action accepted with the latest XdndStatus message. */ - success = JNI_TRUE; - action = target_action; - } - - ds_postDragSourceDropEvent(env, success, action, x_root, y_root); - - dnd_in_progress = False; - - XSelectInput(event->display, target_win, target_window_mask); - - cleanup_drag(event->display, CurrentTime); - - return True; -} - -static Boolean -handle_motif_client_message(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - int reason = (int)(event->data.b[0] & MOTIF_MESSAGE_REASON_MASK); - int origin = (int)(event->data.b[0] & MOTIF_MESSAGE_SENDER_MASK); - unsigned char byte_order = event->data.b[1]; - jint action = java_awt_dnd_DnDConstants_ACTION_NONE; - Time time = CurrentTime; - int x = 0, y = 0; - - /* Only receiver messages should be handled. */ - if (origin != MOTIF_MESSAGE_FROM_RECEIVER) { - return False; - } - - if (target_protocol != MOTIF_DND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid state.", - __FILE__, __LINE__); - return True; - } - - switch (reason) { - case DROP_SITE_ENTER: - case DROP_SITE_LEAVE: - case DRAG_MOTION: - case OPERATION_CHANGED: - break; - default: - return False; - } - - time = read_card32(event->data.b, 4, byte_order); - - /* Discard events from the previous receiver. */ - if (target_enter_server_time == CurrentTime || - time < target_enter_server_time) { - DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid time.", - __FILE__, __LINE__); - return True; - } - - if (reason != DROP_SITE_LEAVE) { - CARD16 flags = read_card16(event->data.b, 2, byte_order); - unsigned char status = (flags & MOTIF_DND_STATUS_MASK) >> - MOTIF_DND_STATUS_SHIFT; - unsigned char motif_action = (flags & MOTIF_DND_ACTION_MASK) >> - MOTIF_DND_ACTION_SHIFT; - - if (status == MOTIF_VALID_DROP_SITE) { - action = motif_to_java_actions(motif_action); - } else { - action = java_awt_dnd_DnDConstants_ACTION_NONE; - } - - x = read_card16(event->data.b, 8, byte_order); - y = read_card16(event->data.b, 10, byte_order); - } - - /* - * We should derive the type of java event to post not from the message - * reason, but from the combination of the current and previous target - * actions: - * Even if the reason is DROP_SITE_LEAVE we shouldn't post dragExit - * if the drag was rejected earlier. - * Even if the reason is DROP_SITE_ENTER we shouldn't post dragEnter - * if the drag is not accepted. - */ - if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE && - action == java_awt_dnd_DnDConstants_ACTION_NONE) { - - ds_postDragSourceEvent(env, x, y); - } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { - jint type = 0; - - if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) { - type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER; - } else { - type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION; - } - - ds_postDragSourceDragEvent(env, action, event_state, x, y, type); - } - - target_action = action; - - return True; -} - -/* - * Handles client messages. - * Returns True if the event is processed, False otherwise. - */ -static Boolean -handle_client_message(XClientMessageEvent* event) { - if (event->message_type == XA_XdndStatus) { - return handle_xdnd_status(event); - } else if (event->message_type == XA_XdndFinished) { - return handle_xdnd_finished(event); - } else if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - return handle_motif_client_message(event); - } - return False; -} - -/* - * Similar to XtLastTimestampProcessed(). We cannot use Xt time stamp, as it is - * updated in XtDispatchEvent that may not be called if a java event is - * consumed. This can make Xt time stamp out-of-date and cause XGrab* failures - * with GrabInvalidTime reason. - */ -static Time -get_latest_time_stamp() { - return latest_time_stamp; -} - -static void -update_latest_time_stamp(XEvent* event) { - Time time = latest_time_stamp; - - switch (event->type) { - case KeyPress: - case KeyRelease: time = event->xkey.time; break; - case ButtonPress: - case ButtonRelease: time = event->xbutton.time; break; - case MotionNotify: time = event->xmotion.time; break; - case EnterNotify: - case LeaveNotify: time = event->xcrossing.time; break; - case PropertyNotify: time = event->xproperty.time; break; - case SelectionClear: time = event->xselectionclear.time; break; - } - - latest_time_stamp = time; -} - -Boolean -awt_dnd_ds_process_event(XEvent* event) { - Display* dpy = event->xany.display; - - update_latest_time_stamp(event); - - if (process_proxy_mode_event(event)) { - return True; - } - - if (!dnd_in_progress) { - return False; - } - - /* Process drag and drop messages. */ - switch (event->type) { - case ClientMessage: - return handle_client_message(&event->xclient); - case DestroyNotify: - /* Target crashed during drop processing - cleanup. */ - if (!drag_in_progress && - event->xdestroywindow.window == target_window) { - cleanup_drag(dpy, CurrentTime); - return True; - } - /* Pass along */ - return False; - } - - if (!drag_in_progress) { - return False; - } - - /* Process drag-only messages. */ - switch (event->type) { - case KeyRelease: - case KeyPress: { - KeySym keysym = XKeycodeToKeysym(dpy, event->xkey.keycode, 0); - switch (keysym) { - case XK_Escape: { - if (keysym == XK_Escape) { - remove_dnd_grab(dpy, event->xkey.time); - cleanup_drag(dpy, event->xkey.time); - } - break; - } - case XK_Control_R: - case XK_Control_L: - case XK_Shift_R: - case XK_Shift_L: { - Window subwindow; - int xw, yw, xr, yr; - unsigned int modifiers; - XQueryPointer(event->xkey.display, event->xkey.root, &event->xkey.root, &subwindow, - &xr, &yr, &xw, &yw, &modifiers); - event->xkey.state = modifiers; - //It's safe to use key event as motion event since we use only their common fields. - handle_mouse_move(&event->xmotion); - break; - } - } - return True; - } - case ButtonPress: - return True; - case MotionNotify: - handle_mouse_move(&event->xmotion); - return True; - case ButtonRelease: - /* - * On some X servers it could happen that ButtonRelease coordinates - * differ from the latest MotionNotify coordinates, so we need to - * process it as a mouse motion. - * MotionNotify differs from ButtonRelease only in is_hint member, but - * we never use it, so it is safe to cast to MotionNotify. - */ - handle_mouse_move(&event->xmotion); - if (event->xbutton.button == Button1 || event->xbutton.button == Button2) { - // drag is initiated with Button1 or Button2 pressed and - // ended on release of either of these buttons (as the same - // behavior was with our old Motif DnD-based implementation) - remove_dnd_grab(dpy, event->xbutton.time); - drag_in_progress = False; - if (target_window != None && target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { - /* - * ACTION_NONE indicates that either the drop target rejects the - * drop or it haven't responded yet. The latter could happen in - * case of fast drag, slow target-server connection or slow - * drag notifications processing on the target side. - */ - process_drop(&event->xbutton); - } else { - cleanup_drag(dpy, event->xbutton.time); - } - } - return True; - default: - return False; - } -} - -static Boolean -motif_convert_proc(Widget w, Atom* selection, Atom* target, Atom* type, - XtPointer* value, unsigned long* length, int32_t* format) { - - if (*target == XA_XmTRANSFER_SUCCESS || - *target == XA_XmTRANSFER_FAILURE) { - - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - jboolean success = - (*target == XA_XmTRANSFER_SUCCESS) ? JNI_TRUE : JNI_FALSE; - - ds_postDragSourceDropEvent(env, success, target_action, - x_root, y_root); - - dnd_in_progress = False; - - XSelectInput(XtDisplay(w), target_window, target_window_mask); - - cleanup_drag(XtDisplay(w), CurrentTime); - - *type = *target; - *length = 0; - *format = 32; - *value = NULL; - - return True; - } else { - return awt_convertData(w, selection, target, type, value, length, - format); - } -} - -static Boolean -set_convert_data_context(JNIEnv* env, Display* dpy, XID xid, jobject component, - jobject transferable, jobject formatMap, - jlongArray formats) { - awt_convertDataCallbackStruct* structPtr = NULL; - - if (XFindContext(awt_display, xid, awt_convertDataContext, - (XPointer*)&structPtr) == XCNOMEM || structPtr != NULL) { - return False; - } - - structPtr = calloc(1, sizeof(awt_convertDataCallbackStruct)); - if (structPtr == NULL) { - return False; - } - - structPtr->source = (*env)->NewGlobalRef(env, component); - structPtr->transferable = (*env)->NewGlobalRef(env, transferable); - structPtr->formatMap = (*env)->NewGlobalRef(env, formatMap); - structPtr->formats = (*env)->NewGlobalRef(env, formats); - - if (JNU_IsNull(env, structPtr->source) || - JNU_IsNull(env, structPtr->transferable) || - JNU_IsNull(env, structPtr->formatMap) || - JNU_IsNull(env, structPtr->formats)) { - - if (!JNU_IsNull(env, structPtr->source)) { - (*env)->DeleteGlobalRef(env, structPtr->source); - } - if (!JNU_IsNull(env, structPtr->transferable)) { - (*env)->DeleteGlobalRef(env, structPtr->transferable); - } - if (!JNU_IsNull(env, structPtr->formatMap)) { - (*env)->DeleteGlobalRef(env, structPtr->formatMap); - } - if (!JNU_IsNull(env, structPtr->formats)) { - (*env)->DeleteGlobalRef(env, structPtr->formats); - } - free(structPtr); - return False; - } - - if (XSaveContext(dpy, xid, awt_convertDataContext, - (XPointer)structPtr) == XCNOMEM) { - free(structPtr); - return False; - } - - return True; -} - -/* - * Convenience routine. Constructs an appropriate exception message based on the - * specified prefix and the return code of XGrab* function and throws an - * InvalidDnDOperationException with the constructed message. - */ -static void -throw_grab_failure_exception(JNIEnv* env, int ret_code, char* msg_prefix) { - char msg[200]; - char* msg_cause = ""; - - switch (ret_code) { - case GrabNotViewable: msg_cause = "not viewable"; break; - case AlreadyGrabbed: msg_cause = "already grabbed"; break; - case GrabInvalidTime: msg_cause = "invalid time"; break; - case GrabFrozen: msg_cause = "grab frozen"; break; - default: msg_cause = "unknown failure"; break; - } - - sprintf(msg, "%s: %s.", msg_prefix, msg_cause); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - msg); -} - -/* - * Sets the proxy mode source window - the source window which the drag - * notifications from an XEmbed client should be forwarded to. - * If the window is not None and there is a drag operation in progress, - * throws InvalidDnDOperationException and doesn't change - * proxy_mode_source_window. - * The caller mush hold AWT_LOCK. - */ -void -set_proxy_mode_source_window(Window window) { - if (window != None && dnd_in_progress) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Drag and drop is already in progress."); - return; - } - - proxy_mode_source_window = window; -} - -/* - * Checks if the event is a drag notification from an XEmbed client. - * If it is, forwards this event back to the current source and returns True. - * Otherwise, returns False. - * Currently only XDnD protocol notifications are recognized. - * The caller must hold AWT_LOCK. - */ -static Boolean -process_proxy_mode_event(XEvent* event) { - if (proxy_mode_source_window == None) { - return False; - } - - if (event->type == ClientMessage) { - XClientMessageEvent* xclient = &event->xclient; - if (xclient->message_type == XA_XdndStatus || - xclient->message_type == XA_XdndFinished) { - Window source = proxy_mode_source_window; - - xclient->data.l[0] = xclient->window; - xclient->window = source; - - XSendEvent(xclient->display, source, False, NoEventMask, - (XEvent*)xclient); - - if (xclient->message_type == XA_XdndFinished) { - proxy_mode_source_window = None; - } - - return True; - } - } - - return False; -} - -/* - * Class: sun_awt_motif_X11DragSourceContextPeer - * Method: startDrag - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11DragSourceContextPeer_startDrag(JNIEnv *env, - jobject this, - jobject component, - jobject wpeer, - jobject transferable, - jobject trigger, - jobject cursor, - jint ctype, - jint actions, - jlongArray formats, - jobject formatMap) { - Time time_stamp = CurrentTime; - Cursor xcursor = None; - Window root_window = None; - Atom* targets = NULL; - jsize num_targets = 0; - - AWT_LOCK(); - - if (dnd_in_progress) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Drag and drop is already in progress."); - AWT_UNLOCK(); - return; - } - - if (proxy_mode_source_window != None) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Proxy drag is in progress."); - AWT_UNLOCK(); - return; - } - - if (!awt_dnd_init(awt_display)) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "DnD subsystem initialization failed."); - AWT_UNLOCK(); - return; - } - - if (!JNU_IsNull(env, cursor)) { - xcursor = getCursor(env, cursor); - - if (xcursor == None) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Invalid drag cursor"); - AWT_UNLOCK(); - } - } - - /* Determine the root window for the drag operation. */ - { - struct FrameData* wdata = (struct FrameData*) - JNU_GetLongFieldAsPtr(env, wpeer, mComponentPeerIDs.pData); - - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "Null component data"); - AWT_UNLOCK(); - return; - } - - if (wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "Null shell widget"); - AWT_UNLOCK(); - return; - } - - root_window = RootWindowOfScreen(XtScreen(wdata->winData.shell)); - - if (root_window == None) { - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot get the root window for the drag operation."); - AWT_UNLOCK(); - return; - } - } - - time_stamp = get_latest_time_stamp(); - - /* Extract the targets from java array. */ - { - targets = NULL; - num_targets = (*env)->GetArrayLength(env, formats); - - /* - * In debug build GetLongArrayElements aborts with assertion on an empty - * array. - */ - if (num_targets > 0) { - jboolean isCopy = JNI_TRUE; - jlong* java_targets = (*env)->GetLongArrayElements(env, formats, - &isCopy); - - if ((*env)->ExceptionCheck(env) == JNI_TRUE) { - AWT_UNLOCK(); - return; - } - - if (java_targets != NULL) { - targets = (Atom*)malloc(num_targets * sizeof(Atom)); - if (targets != NULL) { -#ifdef _LP64 - memcpy(targets, java_targets, num_targets * sizeof(Atom)); -#else - jsize i; - - for (i = 0; i < num_targets; i++) { - targets[i] = (Atom)java_targets[i]; - } -#endif - } - (*env)->ReleaseLongArrayElements(env, formats, java_targets, - JNI_ABORT); - } - } - if (targets == NULL) { - num_targets = 0; - } - } - - /* Write the XDnD initiator info on the awt_root_shell. */ - { - unsigned char ret; - Atom action_atoms[3]; - unsigned int action_count = 0; - - if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) { - action_atoms[action_count] = XA_XdndActionCopy; - action_count++; - } - if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) { - action_atoms[action_count] = XA_XdndActionMove; - action_count++; - } - if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) { - action_atoms[action_count] = XA_XdndActionLink; - action_count++; - } - - ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), - XA_XdndActionList, XA_ATOM, 32, - PropModeReplace, (unsigned char*)action_atoms, - action_count * sizeof(Atom)); - - if (ret != Success) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot write XdndActionList property"); - AWT_UNLOCK(); - return; - } - - ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), - XA_XdndTypeList, XA_ATOM, 32, - PropModeReplace, (unsigned char*)targets, - num_targets); - - if (ret != Success) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot write XdndTypeList property"); - AWT_UNLOCK(); - return; - } - } - - /* Write the Motif DnD initiator info on the awt_root_shell. */ - { - InitiatorInfo info; - unsigned char ret; - int target_list_index = - get_index_for_target_list(awt_display, targets, num_targets); - - if (target_list_index == -1) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot determine the target list index."); - AWT_UNLOCK(); - return; - } - - info.byte_order = MOTIF_BYTE_ORDER; - info.protocol_version = MOTIF_DND_PROTOCOL_VERSION; - info.index = target_list_index; - info.selection_atom = _XA_MOTIF_ATOM_0; - - ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), - _XA_MOTIF_ATOM_0, - _XA_MOTIF_DRAG_INITIATOR_INFO, 8, - PropModeReplace, (unsigned char*)&info, - sizeof(InitiatorInfo)); - - if (ret != Success) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot write the Motif DnD initiator info"); - AWT_UNLOCK(); - return; - } - } - - /* Acquire XDnD selection ownership. */ - if (XtOwnSelection(awt_root_shell, XA_XdndSelection, time_stamp, - awt_convertData, NULL, NULL) != True) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot acquire XdndSelection ownership."); - AWT_UNLOCK(); - return; - } - - /* Acquire Motif DnD selection ownership. */ - if (XtOwnSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time_stamp, - motif_convert_proc, NULL, NULL) != True) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot acquire Motif DnD selection ownership."); - AWT_UNLOCK(); - return; - } - - /* - * Store the information needed to convert data for both selections - * in awt_convertDataContext. - */ - { - if (!set_convert_data_context(env, awt_display, XA_XdndSelection, - component, transferable, formatMap, - formats)) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot save context for XDnD selection data conversion."); - AWT_UNLOCK(); - return; - } - - if (!set_convert_data_context(env, awt_display, _XA_MOTIF_ATOM_0, - component, transferable, formatMap, - formats)) { - cleanup_drag(awt_display, time_stamp); - JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", - "Cannot save context for Motif DnD selection data conversion."); - AWT_UNLOCK(); - return; - } - } - - /* Install X grabs. */ - { - XWindowAttributes xwa; - int ret; - - XGetWindowAttributes(awt_display, root_window, &xwa); - - your_root_event_mask = xwa.your_event_mask; - - XSelectInput(awt_display, root_window, - your_root_event_mask | ROOT_EVENT_MASK); - - ret = XGrabPointer(awt_display, - root_window, - False, - GRAB_EVENT_MASK, - GrabModeAsync, - GrabModeAsync, - None, - xcursor, - time_stamp); - - if (ret != GrabSuccess) { - cleanup_drag(awt_display, time_stamp); - throw_grab_failure_exception(env, ret, "Cannot grab pointer"); - AWT_UNLOCK(); - return; - } - - ret = XGrabKeyboard(awt_display, - root_window, - False, - GrabModeAsync, - GrabModeAsync, - time_stamp); - - if (ret != GrabSuccess) { - cleanup_drag(awt_display, time_stamp); - throw_grab_failure_exception(env, ret, "Cannot grab keyboard"); - AWT_UNLOCK(); - return; - } - } - - /* Update the global state. */ - source_peer = (*env)->NewGlobalRef(env, this); - dnd_in_progress = True; - drag_in_progress = True; - data_types = targets; - data_types_count = num_targets; - source_actions = actions; - drag_root_window = root_window; - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_X11DragSourceContextPeer - * Method: setNativeCursor - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor(JNIEnv *env, - jobject this, - jlong nativeCtxt, - jobject cursor, - jint type) { - if (JNU_IsNull(env, cursor)) { - return; - } - - XChangeActivePointerGrab(awt_display, - GRAB_EVENT_MASK, - getCursor(env, cursor), - CurrentTime); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_dnd_dt.c --- a/jdk/src/solaris/native/sun/awt/awt_dnd_dt.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3700 +0,0 @@ -/* - * Copyright 2003-2006 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_dnd.h" - -#include "jlong.h" - -#include "awt_DataTransferer.h" -#include "awt_MToolkit.h" - -#include "java_awt_dnd_DnDConstants.h" -#include "java_awt_event_MouseEvent.h" - -#include "sun_awt_motif_MComponentPeer.h" -#include "awt_xembed.h" - -#define DT_INITIAL_STATE 0 -#define DT_ENTERED_STATE 1 -#define DT_OVER_STATE 2 - -extern struct ComponentIDs componentIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; - -/**************************** XEmbed server DnD support ***********************/ -extern void -set_xembed_drop_target(JNIEnv* env, jobject server); -extern void -remove_xembed_drop_target(JNIEnv* env, jobject server); -extern Boolean -is_xembed_client(Window window); - -DECLARE_JAVA_CLASS(MEmbedCanvasPeerClass, "sun/awt/motif/MEmbedCanvasPeer"); -/******************************************************************************/ - -typedef enum { - EventSuccess, /* Event is successfully processed. */ - EventFailure /* Failed to process the event. */ -} EventStatus; - -typedef enum { - EnterEvent, /* XdndEnter, TOP_LEVEL_ENTER */ - MotionEvent, /* XdndPosition, DRAG_MOTION, OPERATION_CHANGED */ - LeaveEvent, /* XdndLeave, TOP_LEVEL_LEAVE */ - DropEvent, /* XdndDrop, DROP_START */ - UnknownEvent -} EventType; - -static Protocol source_protocol = NO_PROTOCOL; -static unsigned int source_protocol_version = 0; -static Window source_window = None; -static Atom source_atom = None; -static long source_window_mask = None; -static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; -/* - * According to XDnD protocol, XdndActionList is optional. - * In case if XdndActionList is not set on the source, the list of drop actions - * supported by the source is constructed as follows: - * - "copy" is always included; - * - "move" is included if at least one XdndPosition message received - * after the latest XdndEnter passed XdndActionMove in data.l[4]; - * - "link" is included if at least one XdndPosition message received - * after the latest XdndEnter passed XdndActionLink in data.l[4]. - * We use a boolean flag to signal that we are building the list of drop actions - * supported by the source. - */ -static Boolean track_source_actions = False; -static jint user_action = java_awt_dnd_DnDConstants_ACTION_NONE; -static jlongArray source_data_types = NULL; -static Atom* source_data_types_native = NULL; -static unsigned int source_data_types_count = 0; -static int source_x = 0; -static int source_y = 0; -static jobject target_component = NULL; -/* - * The Motif DnD protocol prescribes that DROP_START message should always be - * preceeded with TOP_LEVEL_LEAVE message. We need to cleanup on TOP_LEVEL_LEAVE - * message, but DROP_START wouldn't be processed properly. - * To resolve this issue we postpone cleanup using a boolean flag this flag is - * set when we receive the TOP_LEVEL_LEAVE message and cleared when the next - * client message arrives if that message is not DROP_START. If that message is - * a DROP_START message, the flag is cleared after the DROP_START is processed. - */ -static Boolean motif_top_level_leave_postponed = False; -/* - * We store a postponed TOP_LEVEL_LEAVE message here. - */ -static XClientMessageEvent motif_top_level_leave_postponed_event; - -/* Forward declarations */ -static Window get_root_for_window(Window window); -static Window get_outer_canvas_for_window(Window window); -static Boolean register_drop_site(Widget outer_canvas, XtPointer componentRef); -static Boolean is_xdnd_drag_message_type(unsigned long message_type); -static Boolean register_xdnd_drop_site(Display* dpy, Window toplevel, - Window window); - -/**************************** JNI stuff ***************************************/ - -DECLARE_JAVA_CLASS(dtcp_clazz, "sun/awt/motif/X11DropTargetContextPeer") - -static void -dt_postDropTargetEvent(JNIEnv* env, jobject component, int x, int y, - jint dropAction, jint event_id, - XClientMessageEvent* event) { - DECLARE_STATIC_VOID_JAVA_METHOD(dtcp_postDropTargetEventToPeer, dtcp_clazz, - "postDropTargetEventToPeer", - "(Ljava/awt/Component;IIII[JJI)V"); - - { - void* copy = NULL; - - if (event != NULL) { - /* - * For XDnD messages we append the information from the latest - * XdndEnter to the context. It is done to be able to reconstruct - * XdndEnter for an XEmbed client. - */ - Boolean isXDnDMessage = - is_xdnd_drag_message_type(event->message_type); - - if (isXDnDMessage) { - copy = malloc(sizeof(XClientMessageEvent) + - 4 * sizeof(long)); - } else { - copy = malloc(sizeof(XClientMessageEvent)); - } - - if (copy == NULL) { - DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); - return; - } - - memcpy(copy, event, sizeof(XClientMessageEvent)); - - if (isXDnDMessage) { - size_t msgSize = sizeof(XClientMessageEvent); - long data1 = source_protocol_version << XDND_PROTOCOL_SHIFT; - long * appended_data; - if (source_data_types_native != NULL && - source_data_types_count > 3) { - - data1 |= XDND_DATA_TYPES_BIT; - } - - appended_data = (long*)((char*)copy + msgSize); - appended_data[0] = data1; - appended_data[1] = source_data_types_count > 0 ? - source_data_types_native[0] : 0; - appended_data[2] = source_data_types_count > 1 ? - source_data_types_native[1] : 0; - appended_data[3] = source_data_types_count > 2 ? - source_data_types_native[2] : 0; - } - } - - DASSERT(!JNU_IsNull(env, component)); - - (*env)->CallStaticVoidMethod(env, clazz, dtcp_postDropTargetEventToPeer, - component, x, y, dropAction, - source_actions, source_data_types, - ptr_to_jlong(copy), event_id); - } -} - -/******************************************************************************/ - -/********************* Embedded drop site list support ************************/ - -struct EmbeddedDropSiteListEntryRec; - -typedef struct EmbeddedDropSiteListEntryRec EmbeddedDropSiteListEntry; - -struct EmbeddedDropSiteListEntryRec { - Window toplevel; - Window root; - /* - * We select for PropertyNotify events on the toplevel, so we need to - * restore the event mask when we are done with this toplevel. - */ - long event_mask; - unsigned int embedded_sites_count; - Window* embedded_sites; - EmbeddedDropSiteListEntry* next; -}; - -static EmbeddedDropSiteListEntry* embedded_drop_site_list = NULL; - -struct EmbeddedDropSiteProtocolListEntryRec; - -typedef struct EmbeddedDropSiteProtocolListEntryRec EmbeddedDropSiteProtocolListEntry; - -struct EmbeddedDropSiteProtocolListEntryRec { - Window window; - Window proxy; - /* - * We override the XdndAware property on the toplevel, so we should keep its - * original contents - the XDnD protocol version supported by the browser. - * This is needed to adjust XDnD messages forwarded to the browser. - */ - unsigned int protocol_version; - /* True if the toplevel was already registered as a drag receiver and - we just changed the proxy. False, otherwise */ - Boolean overriden; - EmbeddedDropSiteProtocolListEntry* next; -}; - -static EmbeddedDropSiteProtocolListEntry* embedded_motif_protocol_list = NULL; -static EmbeddedDropSiteProtocolListEntry* embedded_xdnd_protocol_list = NULL; - -typedef enum { - RegFailure, /* Proxy registration failed */ - RegSuccess, /* The new drop site is registered with the new proxy */ - RegOverride, /* The new proxy is set for the existing drop site */ - RegAlreadyRegistered /* This proxy is already set for this drop site */ -} ProxyRegistrationStatus; - -/* Forward declarations. */ -static EmbeddedDropSiteProtocolListEntry* -get_xdnd_protocol_entry_for_toplevel(Window toplevel); -static EmbeddedDropSiteProtocolListEntry* -get_motif_protocol_entry_for_toplevel(Window toplevel); -static void remove_xdnd_protocol_entry_for_toplevel(Window toplevel); -static void remove_motif_protocol_entry_for_toplevel(Window toplevel); - -/* - * Registers the toplevel as a Motif drag receiver if it is not registered yet, - * sets the specified new_proxy for it and returns the previous proxy in old_proxy. - * Does nothing if the new_proxy is already set as a proxy for this toplevel. - * Returns the completion status. - */ -static ProxyRegistrationStatus -set_motif_proxy(Display* dpy, Window toplevel, Window new_proxy, Window *old_proxy) { - Boolean override = False; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char* data; - unsigned char ret; - - DASSERT(old_proxy != NULL); - - *old_proxy = None; - - data = NULL; - ret = checked_XGetWindowProperty(dpy, toplevel, - _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - /* Check if toplevel is a valid window. */ - if (ret != Success) { - return RegFailure; - } - - if (ret == Success && data != NULL && type != None && format == 8 - && nitems >= MOTIF_RECEIVER_INFO_SIZE) { - unsigned char byte_order = read_card8((char*)data, 0); - void* p = (char*)data + 4; - - /* Browser and plugin have different byte orders - report failure for now. */ - if (MOTIF_BYTE_ORDER != byte_order) { - XFree(data); - return RegFailure; - } - - *old_proxy = read_card32((char*)data, 4, byte_order); - - /* If the proxy is already set to the specified window - return. */ - if (*old_proxy == new_proxy) { - XFree(data); - return RegAlreadyRegistered; - } - - /* replace the proxy window */ - write_card32(&p, new_proxy); - - override = True; - } else { - void* p; - - if (ret == Success) { - XFree(data); - data = NULL; - } - - data = malloc(MOTIF_RECEIVER_INFO_SIZE); - - if (data == NULL) { - DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); - return RegFailure; - } - - p = data; - - write_card8(&p, MOTIF_BYTE_ORDER); - write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */ - write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */ - write_card8(&p, 0); /* pad */ - write_card32(&p, new_proxy); /* proxy window */ - write_card16(&p, 0); /* num_drop_sites */ - write_card16(&p, 0); /* pad */ - write_card32(&p, MOTIF_RECEIVER_INFO_SIZE); - } - - ret = checked_XChangeProperty(dpy, toplevel, - _XA_MOTIF_DRAG_RECEIVER_INFO, - _XA_MOTIF_DRAG_RECEIVER_INFO, 8, - PropModeReplace, (unsigned char*)data, - MOTIF_RECEIVER_INFO_SIZE); - - if (data != NULL) { - XFree(data); - data = NULL; - } - - if (ret == Success) { - if (override) { - return RegOverride; - } else { - return RegSuccess; - } - } else { - return RegFailure; - } -} - -/* - * Registers the toplevel as a XDnD drag receiver if it is not registered yet, - * sets the specified new_proxy for it and returns the previous proxy in - * old_proxy and the original XDnD protocol version in old_version. - * Does nothing if the new_proxy is already set as a proxy for this toplevel. - * Returns the completion status. - */ -static ProxyRegistrationStatus -set_xdnd_proxy(Display* dpy, Window toplevel, Window new_proxy, - Window* old_proxy, unsigned int* old_version) { - Atom version_atom = XDND_PROTOCOL_VERSION; - Window xdnd_proxy = None; - Boolean override = False; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char* data; - unsigned char ret; - - DASSERT(old_proxy != NULL); - - *old_proxy = None; - - data = NULL; - ret = checked_XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - if (ret != Success) { - return RegFailure; - } - - if (ret == Success && data != NULL && type == XA_ATOM) { - unsigned int protocol_version = *((unsigned int*)data); - - override = True; - *old_version = protocol_version; - - /* XdndProxy is not supported for prior to XDnD version 4 */ - if (protocol_version >= 4) { - int status; - - XFree(data); - - data = NULL; - status = XGetWindowProperty(dpy, toplevel, XA_XdndProxy, 0, 1, - False, XA_WINDOW, &type, &format, - &nitems, &after, &data); - - if (status == Success && data != NULL && type == XA_WINDOW) { - xdnd_proxy = *((Window*)data); - - if (xdnd_proxy != None) { - XFree(data); - - data = NULL; - status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy, - 0, 1, False, XA_WINDOW, &type, - &format, &nitems, &after, &data); - - if (status != Success || data == NULL || type != XA_WINDOW || - *((Window*)data) != xdnd_proxy) { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } - - if (xdnd_proxy != None) { - XFree(data); - - data = NULL; - status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware, - 0, 1, False, AnyPropertyType, - &type, &format, &nitems, &after, - &data); - - if (status == Success && data != NULL && type == XA_ATOM) { - unsigned int proxy_version = *((unsigned int*)data); - - if (proxy_version != protocol_version) { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } else { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } - } - - *old_proxy = xdnd_proxy; - } - } - - XFree(data); - - /* If the proxy is already set to the specified window - return. */ - if (xdnd_proxy == new_proxy) { - return RegAlreadyRegistered; - } - - /* The proxy window must have the XdndAware set, as XDnD protocol prescribes - to check the proxy window for XdndAware. */ - ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndAware, XA_ATOM, 32, - PropModeReplace, - (unsigned char*)&version_atom, 1); - - if (ret != Success) { - return RegFailure; - } - - /* The proxy window must have the XdndProxy set to point to itself. */ - ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndProxy, XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&new_proxy, 1); - - if (ret != Success) { - return RegFailure; - } - - ret = checked_XChangeProperty(dpy, toplevel, XA_XdndAware, XA_ATOM, 32, - PropModeReplace, - (unsigned char*)&version_atom, 1); - - if (ret != Success) { - return RegFailure; - } - - ret = checked_XChangeProperty(dpy, toplevel, XA_XdndProxy, XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&new_proxy, 1); - - if (ret == Success) { - if (override) { - return RegOverride; - } else { - return RegSuccess; - } - } else { - return RegFailure; - } -} - -/* - * 'toplevel' is the browser toplevel window. To register a drop site on the - * plugin window we set the proxy for the browser toplevel window to point to - * the awt_root_shell window. - * - * We assume that only one JVM per browser instance is possible. This - * assumption is true with the current plugin implementation - it creates a - * single JVM for all plugin instances created by the given plugin factory. - * - * When a client message event for the browser toplevel window is received, we - * will iterate over drop sites registered with this toplevel and determine if - * the mouse pointer is currently over one of them (there could be several - * plugin windows in one browser window - for example if an HTML page contains - * frames and several frames contain a plugin object). - * - * If the pointer is not over any of the plugin drop sites the client message - * will be resent to the browser, otherwise it will be processed normally. - */ -static EmbeddedDropSiteListEntry* -awt_dnd_dt_init_proxy(Display* dpy, Window root, Window toplevel, Window window) { - Window awt_root_window = get_awt_root_window(); - Window motif_proxy = None; - Boolean motif_override = False; - unsigned long event_mask = 0; - - if (awt_root_window == None) { - return NULL; - } - - /* Grab server, since we are working with the window that belongs to - another client. REMIND: ungrab when done!!! */ - XGrabServer(dpy); - - { - ProxyRegistrationStatus motif_status = RegFailure; - - motif_status = set_motif_proxy(dpy, toplevel, awt_root_window, &motif_proxy); - - switch (motif_status) { - case RegFailure: - case RegAlreadyRegistered: - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - return NULL; - case RegOverride: - motif_override = True; - break; - case RegSuccess: - motif_override = False; - break; - default: - DASSERT(False); - } - - - } - - { - XWindowAttributes xwa; - XGetWindowAttributes(dpy, toplevel, &xwa); - event_mask = xwa.your_event_mask; - if ((event_mask & PropertyChangeMask) == 0) { - XSelectInput(dpy, toplevel, event_mask | PropertyChangeMask); - } - } - - XUngrabServer(dpy); - /* Workaround for bug 5039226 */ - XSync(dpy, False); - - /* Add protocol specific entries for the toplevel. */ - { - EmbeddedDropSiteProtocolListEntry* motif_entry = NULL; - - motif_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); - - if (motif_entry == NULL) { - return NULL; - } - - motif_entry->window = toplevel; - motif_entry->proxy = motif_proxy; - motif_entry->protocol_version = 0; - motif_entry->overriden = motif_override; - motif_entry->next = embedded_motif_protocol_list; - embedded_motif_protocol_list = motif_entry; - } - - { - EmbeddedDropSiteListEntry* entry = NULL; - Window* sites = NULL; - - entry = malloc(sizeof(EmbeddedDropSiteListEntry)); - - if (entry == NULL) { - return NULL; - } - - sites = malloc(sizeof(Window)); - - if (sites == NULL) { - free(entry); - return NULL; - } - - sites[0] = window; - - entry->toplevel = toplevel; - entry->root = root; - entry->event_mask = event_mask; - entry->embedded_sites_count = 1; - entry->embedded_sites = sites; - entry->next = NULL; - - return entry; - } -} - -static void -register_xdnd_embedder(Display* dpy, EmbeddedDropSiteListEntry* entry, long window) { - Window awt_root_window = get_awt_root_window(); - Window toplevel = entry->toplevel; - Window xdnd_proxy = None; - unsigned int xdnd_protocol_version = 0; - Boolean xdnd_override = False; - Boolean register_xdnd = True; - Boolean motif_overriden = False; - - EmbeddedDropSiteProtocolListEntry* motif_entry = embedded_motif_protocol_list; - while (motif_entry != NULL) { - if (motif_entry->window == toplevel) { - motif_overriden = motif_entry->overriden; - break; - } - motif_entry = motif_entry->next; - } - - /* - * First check if the window is an XEmbed client. - * In this case we don't have to setup a proxy on the toplevel, - * instead we register the XDnD drop site on the embedded window. - */ - if (isXEmbedActiveByWindow(window)) { - register_xdnd_drop_site(dpy, toplevel, window); - return; - } - - /* - * By default, we register a drop site that supports both dnd - * protocols. This approach is not appropriate in plugin - * scenario if the browser doesn't support XDnD. If we forcibly set - * XdndAware on the browser toplevel, any drag source that supports both - * protocols and prefers XDnD will be unable to drop anything on the - * browser. - * The solution for this problem is not to register XDnD drop site - * if the browser supports only Motif DnD. - */ - if (motif_overriden) { - int status; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char* data; - - data = NULL; - status = XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - XFree(data); - data = NULL; - - if (type != XA_ATOM) { - register_xdnd = False; - } - } - - if (register_xdnd) { - ProxyRegistrationStatus xdnd_status; - /* Grab server, since we are working with the window that belongs to - another client. REMIND: ungrab when done!!! */ - XGrabServer(dpy); - - xdnd_status = - set_xdnd_proxy(dpy, toplevel, awt_root_window, &xdnd_proxy, - &xdnd_protocol_version); - - XUngrabServer(dpy); - - switch (xdnd_status) { - case RegFailure: - case RegAlreadyRegistered: - return; - case RegOverride: - xdnd_override = True; - break; - case RegSuccess: - xdnd_override = False; - break; - default: - DASSERT(False); - } - - { - EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL; - - xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); - - if (xdnd_entry == NULL) { - return; - } - - xdnd_entry->window = toplevel; - xdnd_entry->proxy = xdnd_proxy; - xdnd_entry->protocol_version = xdnd_protocol_version; - xdnd_entry->overriden = xdnd_override; - xdnd_entry->next = embedded_xdnd_protocol_list; - embedded_xdnd_protocol_list = xdnd_entry; - } - } -} - -/* - * If embedded_drop_site_list already contains an entry with the specified - * 'toplevel', the method registers the specified 'window' as an embedded drop - * site for this 'toplevel' and returns True. - * Otherwise, it checks if the 'toplevel' is a registered drop site for adds - * (window, component) pair to the list and returns True - * if completes successfully. - */ -static Boolean -add_to_embedded_drop_site_list(Display* dpy, Window root, Window toplevel, - Window window) { - EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; - - while (entry != NULL) { - if (entry->toplevel == toplevel) { - void* p = realloc(entry->embedded_sites, - sizeof(Window) * - (entry->embedded_sites_count + 1)); - if (p == NULL) { - return False; - } - entry->embedded_sites = p; - entry->embedded_sites[entry->embedded_sites_count++] = window; - - register_xdnd_embedder(dpy, entry, window); - - return True; - } - entry = entry->next; - } - - entry = awt_dnd_dt_init_proxy(dpy, root, toplevel, window); - - if (entry == NULL) { - return False; - } - - register_xdnd_embedder(dpy, entry, window); - - entry->next = embedded_drop_site_list; - embedded_drop_site_list = entry; - - return True; -} - -/* - * Removes the window from the list of embedded drop sites for the toplevel. - * Returns True if the window was successfully removed, False otherwise. - */ -static Boolean -remove_from_embedded_drop_site_list(Display* dpy, Window toplevel, Window window) { - EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; - EmbeddedDropSiteListEntry* prev = NULL; - - while (entry != NULL) { - if (entry->toplevel == toplevel) { - unsigned int idx; - - for (idx = 0; idx < entry->embedded_sites_count; idx++) { - if (entry->embedded_sites[idx] == window) { - int tail = entry->embedded_sites_count - idx - 1; - if (tail > 0) { - memmove(entry->embedded_sites + idx, - entry->embedded_sites + idx + 1, - tail * sizeof(Window)); - } - entry->embedded_sites_count--; - - /* If the list of embedded drop sites for this toplevel - becomes empty - restore the original proxies and remove - the entry. */ - if (entry->embedded_sites_count == 0) { - Widget w = XtWindowToWidget(dpy, toplevel); - - if (w != NULL) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - Widget copy = w; - jobject peer = findPeer(&w); - - if (!JNU_IsNull(env, peer) && - (*env)->IsInstanceOf(env, peer, - get_MEmbedCanvasPeerClass(env)) == JNI_TRUE) { - remove_xembed_drop_target(env, peer); - } - } else { - EmbeddedDropSiteProtocolListEntry* xdnd_entry = - get_xdnd_protocol_entry_for_toplevel(toplevel); - EmbeddedDropSiteProtocolListEntry* motif_entry = - get_motif_protocol_entry_for_toplevel(toplevel); - - if (xdnd_entry != NULL) { - if (xdnd_entry->overriden == True) { - XChangeProperty(dpy, toplevel, XA_XdndAware, - XA_ATOM, 32, - PropModeReplace, - (unsigned char*)&xdnd_entry->protocol_version, - 1); - - XChangeProperty(dpy, toplevel, XA_XdndProxy, - XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&xdnd_entry->proxy, 1); - } else { - XDeleteProperty(dpy, toplevel, XA_XdndAware); - XDeleteProperty(dpy, toplevel, XA_XdndProxy); - } - remove_xdnd_protocol_entry_for_toplevel(toplevel); - } - - if (motif_entry != NULL) { - if (motif_entry->overriden == True) { - /* Request status */ - int status; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char* data; - - data = NULL; - status = XGetWindowProperty(dpy, toplevel, - _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - if (status == Success && data != NULL && type != None && - format == 8 && nitems >= MOTIF_RECEIVER_INFO_SIZE) { - unsigned char byte_order = read_card8((char*)data, 0); - void* p = (char*)data + 4; - - DASSERT(MOTIF_BYTE_ORDER == byte_order); - - if (MOTIF_BYTE_ORDER == byte_order) { - /* restore the original proxy window */ - write_card32(&p, motif_entry->proxy); - - XChangeProperty(dpy, toplevel, - _XA_MOTIF_DRAG_RECEIVER_INFO, - _XA_MOTIF_DRAG_RECEIVER_INFO, 8, - PropModeReplace, - (unsigned char*)data, - MOTIF_RECEIVER_INFO_SIZE); - } - } - - if (status == Success) { - XFree(data); - } - } else { - XDeleteProperty(dpy, toplevel, _XA_MOTIF_DRAG_RECEIVER_INFO); - } - - remove_motif_protocol_entry_for_toplevel(toplevel); - } - - if ((entry->event_mask & PropertyChangeMask) == 0) { - XSelectInput(dpy, toplevel, entry->event_mask); - } - } - - if (prev == NULL) { - embedded_drop_site_list = entry->next; - } else { - prev->next = entry->next; - } - - free(entry); - } - return True; - } - } - return False; - } - prev = entry; - entry = entry->next; - } - return False; -} - -static EmbeddedDropSiteListEntry* -get_entry_for_toplevel(Window toplevel) { - EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; - - while (entry != NULL) { - if (entry->toplevel == toplevel) { - return entry; - } - entry = entry->next; - } - return NULL; -} - -static EmbeddedDropSiteProtocolListEntry* -get_motif_protocol_entry_for_toplevel(Window toplevel) { - EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list; - - while (entry != NULL) { - if (entry->window == toplevel) { - return entry; - } - entry = entry->next; - } - return NULL; -} - -static EmbeddedDropSiteProtocolListEntry* -get_xdnd_protocol_entry_for_toplevel(Window toplevel) { - EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list; - - while (entry != NULL) { - if (entry->window == toplevel) { - return entry; - } - entry = entry->next; - } - return NULL; -} - -static void -remove_motif_protocol_entry_for_toplevel(Window toplevel) { - EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list; - EmbeddedDropSiteProtocolListEntry* prev_entry = NULL; - - while (entry != NULL) { - if (entry->window == toplevel) { - if (prev_entry != NULL) { - prev_entry->next = entry->next; - } else { - embedded_motif_protocol_list = entry->next; - } - free(entry); - } - entry = entry->next; - prev_entry = entry; - } -} - -static void -remove_xdnd_protocol_entry_for_toplevel(Window toplevel) { - EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list; - EmbeddedDropSiteProtocolListEntry* prev_entry = NULL; - - while (entry != NULL) { - if (entry->window == toplevel) { - if (prev_entry != NULL) { - prev_entry->next = entry->next; - } else { - embedded_xdnd_protocol_list = entry->next; - } - free(entry); - } - entry = entry->next; - } -} - -static Boolean -is_embedding_toplevel(Window toplevel) { - return get_entry_for_toplevel(toplevel) != NULL; -} - -static Window -get_embedded_window(Display* dpy, Window toplevel, int x, int y) { - EmbeddedDropSiteListEntry* entry = get_entry_for_toplevel(toplevel); - - if (entry != NULL) { - unsigned int idx; - - for (idx = 0; idx < entry->embedded_sites_count; idx++) { - Window site = entry->embedded_sites[idx]; - Window child = None; - int x_return, y_return; - - if (XTranslateCoordinates(dpy, entry->root, site, x, y, - &x_return, &y_return, &child)) { - if (x_return >= 0 && y_return >= 0) { - XWindowAttributes xwa; - XGetWindowAttributes(dpy, site, &xwa); - if (xwa.map_state != IsUnmapped && - x_return < xwa.width && y_return < xwa.height) { - return site; - } - } - } - } - } - - return None; -} - -/* - * If the toplevel is not an embedding toplevel does nothing and returns False. - * Otherwise, sets xdnd_proxy for the specified toplevel to the 'proxy_window', - * xdnd_protocol_version to 'version', xdnd_override to 'override', returns True. - */ -static Boolean -set_xdnd_proxy_for_toplevel(Window toplevel, Window proxy_window, - unsigned int version, Boolean override) { - EmbeddedDropSiteProtocolListEntry* entry = - get_xdnd_protocol_entry_for_toplevel(toplevel); - - if (entry == NULL) { - return False; - } - - entry->proxy = proxy_window; - entry->protocol_version = version; - entry->overriden = override; - - return True; -} - -/* - * If the toplevel is not an embedding toplevel does nothing and returns False. - * Otherwise, sets motif_proxy for the specified toplevel to the proxy_window, - * motif_override to 'override' and returns True. - */ -static Boolean -set_motif_proxy_for_toplevel(Window toplevel, Window proxy_window, Boolean override) { - EmbeddedDropSiteProtocolListEntry* entry = - get_motif_protocol_entry_for_toplevel(toplevel); - - if (entry == NULL) { - return False; - } - - entry->proxy = proxy_window; - entry->overriden = override; - - return True; -} - -/* - * Forwards a drag notification to the embedding toplevel modifying the event - * to match the protocol version supported by the toplevel. - * Returns True if the event is sent, False otherwise. - */ -static Boolean -forward_client_message_to_toplevel(Window toplevel, XClientMessageEvent* event) { - EmbeddedDropSiteProtocolListEntry* protocol_entry = NULL; - Window proxy = None; - - if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - protocol_entry = get_motif_protocol_entry_for_toplevel(toplevel); - } else { - /* Assume XDnD */ - protocol_entry = get_xdnd_protocol_entry_for_toplevel(toplevel); - if (protocol_entry != NULL) { - /* Adjust the event to match the XDnD protocol version. */ - unsigned int version = protocol_entry->protocol_version; - if (event->message_type == XA_XdndEnter) { - unsigned int min_version = source_protocol_version < version ? - source_protocol_version : version; - event->data.l[1] = min_version << XDND_PROTOCOL_SHIFT; - event->data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; - } - } - } - - if (protocol_entry == NULL) { - return False; - } - - if (!protocol_entry->overriden) { - return False; - } - proxy = protocol_entry->proxy; - - if (proxy == None) { - proxy = toplevel; - } - - event->window = toplevel; - - XSendEvent(event->display, proxy, False, NoEventMask, (XEvent*)event); - - return True; -} - -/******************************************************************************/ - -/********************* Drop site list support *********************************/ - -struct DropSiteListEntryRec; - -typedef struct DropSiteListEntryRec DropSiteListEntry; - -struct DropSiteListEntryRec { - Window window; - Window root; - /* - * The closest to the root ancestor with WM_STATE property set. - * Normally toplevel == window. - * In plugin scenario toplevel is the browser toplevel window. - */ - Window toplevel; - /* - * Java top-level position is the outer canvas position, not the shell - * window position. We need to keep the outer canvas ID (and the root ID) to - * translate from mouse position root coordinates to the Java component - * coordinates. - */ - Window outer_canvas; - jobject component; - DropSiteListEntry* next; -}; - -static DropSiteListEntry* drop_site_list = NULL; - -/* - * If drop_site_list already contains an entry with the same window, - * does nothing and returns False. - * Otherwise, adds a new entry the list and returns True - * if completes successfully. - */ -static Boolean -add_to_drop_site_list(Window window, Window root, Window toplevel, - Window outer_canvas, jobject component) { - DropSiteListEntry* entry = drop_site_list; - - while (entry != NULL) { - if (entry->window == window) { - return False; - } - entry = entry->next; - } - - entry = malloc(sizeof(DropSiteListEntry)); - - if (entry == NULL) { - return False; - } - - entry->window = window; - entry->root = root; - entry->toplevel = toplevel; - entry->outer_canvas = outer_canvas; - entry->component = component; - entry->next = drop_site_list; - drop_site_list = entry; - - return True; -} - -/* - * Returns True if the list entry for the specified window has been successfully - * removed from the list. Otherwise, returns False. - */ -static Boolean -remove_from_drop_site_list(Window window) { - DropSiteListEntry* entry = drop_site_list; - DropSiteListEntry* prev = NULL; - - while (entry != NULL) { - if (entry->window == window) { - if (prev != NULL) { - prev->next = entry->next; - } else { - drop_site_list = entry->next; - } - free(entry); - return True; - } - prev = entry; - entry = entry->next; - } - - return False; -} - -static jobject -get_component_for_window(Window window) { - DropSiteListEntry* entry = drop_site_list; - - while (entry != NULL) { - if (entry->window == window) { - return entry->component; - } - entry = entry->next; - } - - return NULL; -} - -static Window -get_root_for_window(Window window) { - DropSiteListEntry* entry = drop_site_list; - - while (entry != NULL) { - if (entry->window == window) { - return entry->root; - } - entry = entry->next; - } - - return None; -} - -static Window -get_toplevel_for_window(Window window) { - DropSiteListEntry* entry = drop_site_list; - - while (entry != NULL) { - if (entry->window == window) { - return entry->toplevel; - } - entry = entry->next; - } - - return None; -} - -static Window -get_outer_canvas_for_window(Window window) { - DropSiteListEntry* entry = drop_site_list; - - while (entry != NULL) { - if (entry->window == window) { - return entry->outer_canvas; - } - entry = entry->next; - } - - return None; -} -/******************************************************************************/ - -/******************* Delayed drop site registration stuff *********************/ -struct DelayedRegistrationEntryRec; - -typedef struct DelayedRegistrationEntryRec DelayedRegistrationEntry; - -struct DelayedRegistrationEntryRec { - Widget outer_canvas; - jobject component; - XtIntervalId timer; - DelayedRegistrationEntry* next; -}; - -static DelayedRegistrationEntry* delayed_registration_list = NULL; - -static const int DELAYED_REGISTRATION_PERIOD = 500; - -/* Timer callback. */ -static void -register_drop_site_later(XtPointer client_data, XtIntervalId* id); - -/* - * Enqueues the specified widget and component for delayed drop site - * registration. If this widget has already been registered, does nothing and - * returns False. Otherwise, schedules a timer callback that will repeatedly - * attempt to register the drop site until the registration succeeds. - * To remove this widget from the queue of delayed registration call - * remove_delayed_registration_entry(). - * - * The caller must own AWT_LOCK. - */ -static Boolean -add_delayed_registration_entry(Widget outer_canvas, XtPointer componentRef) { - DelayedRegistrationEntry* entry = delayed_registration_list; - - if (outer_canvas == NULL || componentRef == NULL) { - return False; - } - - while (entry != NULL && entry->outer_canvas != outer_canvas) { - entry = entry->next; - } - - if (entry != NULL) { - return False; - } - - entry = malloc(sizeof(DelayedRegistrationEntry)); - - if (entry == NULL) { - return False; - } - - entry->outer_canvas = outer_canvas; - entry->component = componentRef; - entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD, - register_drop_site_later, entry); - entry->next = delayed_registration_list; - delayed_registration_list = entry; - - return True; -} - -/* - * Unregisters the timer callback and removes this widget from the queue of - * delayed drop site registration. - * - * The caller must own AWT_LOCK. - */ -static Boolean -remove_delayed_registration_entry(Widget outer_canvas) { - DelayedRegistrationEntry* entry = delayed_registration_list; - DelayedRegistrationEntry* prev = NULL; - - if (outer_canvas == NULL) { - return False; - } - - while (entry != NULL && entry->outer_canvas != outer_canvas) { - prev = entry; - entry = entry->next; - } - - if (entry == NULL) { - return False; - } - - if (prev != NULL) { - prev->next = entry->next; - } else { - delayed_registration_list = entry->next; - } - - if (entry->timer) { - XtRemoveTimeOut(entry->timer); - entry->timer = (XtIntervalId)0; - } - - free(entry); - - return True; -} - -static void -register_drop_site_later(XtPointer client_data, XtIntervalId* id) { - DelayedRegistrationEntry* entry = (DelayedRegistrationEntry*)client_data; - - if (XtIsRealized(entry->outer_canvas) && - register_drop_site(entry->outer_canvas, entry->component)) { - remove_delayed_registration_entry(entry->outer_canvas); - } else { - entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD, - register_drop_site_later, entry); - } -} -/******************************************************************************/ - -static void -awt_dnd_cleanup() { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - - if (!JNU_IsNull(env, target_component)) { - /* Trigger dragExit */ - /* - * Note: we pass NULL native context. This indicates that response - * shouldn't be sent to the source. - */ - dt_postDropTargetEvent(env, target_component, 0, 0, - java_awt_dnd_DnDConstants_ACTION_NONE, - java_awt_event_MouseEvent_MOUSE_EXITED, - NULL); - } - - if (motif_top_level_leave_postponed) { - XClientMessageEvent* leave = &motif_top_level_leave_postponed_event; - if (leave->type == ClientMessage) { - Window win = leave->window; - if (is_embedding_toplevel(win)) { - forward_client_message_to_toplevel(win, leave); - } - } - } - - if (source_window != None) { - XSelectInput(awt_display, source_window, source_window_mask); - } - - source_protocol = NO_PROTOCOL; - source_protocol_version = 0; - source_window = None; - source_atom = None; - source_window_mask = 0; - source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; - track_source_actions = False; - (*env)->DeleteGlobalRef(env, source_data_types); - source_data_types = NULL; - if (source_data_types_native != NULL) { - free(source_data_types_native); - source_data_types_native = NULL; - } - source_data_types_count = 0; - source_x = 0; - source_y = 0; - target_component = NULL; - motif_top_level_leave_postponed = False; - memset(&motif_top_level_leave_postponed_event, 0, - sizeof(XClientMessageEvent)); -} - -static jlongArray -get_data_types_array(JNIEnv* env, Atom* types, unsigned int types_count) { - jlongArray array = NULL; - jboolean isCopy; - jlong* jTargets; -#ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */ - unsigned int i; -#endif - - if ((*env)->PushLocalFrame(env, 1) < 0) { - return NULL; - } - - array = (*env)->NewLongArray(env, types_count); - - if (JNU_IsNull(env, array)) { - return NULL; - } - - if (types_count == 0) { - return array; - } - - jTargets = (*env)->GetLongArrayElements(env, array, &isCopy); - if (jTargets == NULL) { - (*env)->PopLocalFrame(env, NULL); - return NULL; - } - -#ifdef _LP64 - memcpy(jTargets, types, types_count * sizeof(Atom)); -#else - for (i = 0; i < types_count; i++) { - jTargets[i] = (types[i] & 0xFFFFFFFFLU); - } -#endif - - (*env)->ReleaseLongArrayElements(env, array, jTargets, 0); - - array = (*env)->NewGlobalRef(env, array); - - (*env)->PopLocalFrame(env, NULL); - - return array; -} - -static Boolean -is_xdnd_drag_message_type(unsigned long message_type) { - return message_type == XA_XdndEnter || - message_type == XA_XdndPosition || - message_type == XA_XdndLeave || - message_type == XA_XdndDrop ? True : False; -} - -/* - * Returns EventConsume if the event should be consumed, - * EventPassAlong otherwise. - */ -static EventStatus -handle_xdnd_enter(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - Display* dpy = event->display; - long* event_data = event->data.l; - Window source_win = None; - long source_win_mask = 0; - unsigned int protocol_version = 0; - unsigned int data_types_count = 0; - Atom* data_types = NULL; - jlongArray java_data_types = NULL; - jint actions = java_awt_dnd_DnDConstants_ACTION_NONE; - Boolean track = False; - - DTRACE_PRINTLN5("%s:%d XdndEnter comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (!JNU_IsNull(env, target_component) || source_window != None || - source_protocol != NO_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - /* - * NOTE: the component can be NULL if the event was sent to the embedding - * toplevel. - */ - if (JNU_IsNull(env, get_component_for_window(event->window)) && - !is_embedding_toplevel(event->window)) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - window is not a registered drop site.", - __FILE__, __LINE__); - return EventFailure; - } - - protocol_version = - (event_data[1] & XDND_PROTOCOL_MASK) >> XDND_PROTOCOL_SHIFT; - - /* XDnD compliance only requires supporting version 3 and up. */ - if (protocol_version < XDND_MIN_PROTOCOL_VERSION) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.", - __FILE__, __LINE__); - return EventFailure; - } - - /* Ignore the source if the protocol version is higher than we support. */ - if (protocol_version > XDND_PROTOCOL_VERSION) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.", - __FILE__, __LINE__); - return EventFailure; - } - - source_win = event_data[0]; - - /* Extract the list of supported actions. */ - if (protocol_version < 2) { - /* Prior to XDnD version 2 only COPY action was supported. */ - actions = java_awt_dnd_DnDConstants_ACTION_COPY; - } else { - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - data = NULL; - ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndActionList, - 0, 0xFFFF, False, XA_ATOM, &type, - &format, &nitems, &after, &data); - - /* Ignore the source if the window is destroyed. */ - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", - __FILE__, __LINE__); - return EventFailure; - } - - if (ret == Success) { - if (type == XA_ATOM && format == 32) { - unsigned int i; - Atom* action_atoms = (Atom*)data; - - for (i = 0; i < nitems; i++) { - actions |= xdnd_to_java_action(action_atoms[i]); - } - } - - /* - * According to XDnD protocol, XdndActionList is optional. - * If XdndActionList is not set we try to guess which actions are - * supported. - */ - if (type == None) { - actions = java_awt_dnd_DnDConstants_ACTION_COPY; - track = True; - } - - XFree(data); - } - } - - /* Extract the available data types. */ - if (event_data[1] & XDND_DATA_TYPES_BIT) { - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - data = NULL; - ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndTypeList, - 0, 0xFFFF, False, XA_ATOM, &type, - &format, &nitems, &after, &data); - - /* Ignore the source if the window is destroyed. */ - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", - __FILE__, __LINE__); - return EventFailure; - } - - if (ret == Success) { - if (type == XA_ATOM && format == 32 && nitems > 0) { - data_types_count = nitems; - data_types = (Atom*)malloc(data_types_count * sizeof(Atom)); - - if (data_types == NULL) { - XFree(data); - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.", - __FILE__, __LINE__); - return EventFailure; - } - - memcpy((void *)data_types, (void *)data, - data_types_count * sizeof(Atom)); - } - - XFree(data); - } - } else { - int i; - data_types = (Atom*)malloc(3 * sizeof (Atom)); - if (data_types == NULL) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.", - __FILE__, __LINE__); - return EventFailure; - } - for (i = 0; i < 3; i++) { - Atom j; - if ((j = event_data[2 + i]) != None) { - data_types[data_types_count++] = j; - } - } - } - - java_data_types = get_data_types_array(env, data_types, data_types_count); - - if (JNU_IsNull(env, java_data_types)) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - cannot create types array.", - __FILE__, __LINE__); - free((char*)data_types); - return EventFailure; - } - - /* - * Select for StructureNotifyMask to receive DestroyNotify in case of source - * crash. - */ - { - unsigned char ret; - XWindowAttributes xwa; - - XGetWindowAttributes(dpy, source_win, &xwa); - - source_win_mask = xwa.your_event_mask; - - ret = checked_XSelectInput(dpy, source_win, - (source_win_mask | StructureNotifyMask)); - - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", - __FILE__, __LINE__); - free((char*)data_types); - (*env)->DeleteGlobalRef(env, java_data_types); - return EventFailure; - } - } - - /* Update the global state. */ - source_protocol = XDND_PROTOCOL; - source_protocol_version = protocol_version; - source_window = source_win; - source_window_mask = source_win_mask; - source_actions = actions; - track_source_actions = track; - source_data_types = java_data_types; - source_data_types_native = data_types; - source_data_types_count = data_types_count; - - DTRACE_PRINTLN5("%s:%d XdndEnter handled src_win=%ld protocol=%d fmt=%d.", - __FILE__, __LINE__, - source_window, source_protocol, data_types_count); - - return EventSuccess; -} - -/* - * Returns EventConsume if the event should be consumed, - * EventPassAlong otherwise. - */ -static EventStatus -handle_xdnd_position(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - long* event_data = event->data.l; - Window source_win = None; - Time time_stamp = CurrentTime; - Atom action_atom = None; - jint action = java_awt_dnd_DnDConstants_ACTION_NONE; - int x = 0; - int y = 0; - jint java_event_id = 0; - jobject component = NULL; - Window receiver = None; - - DTRACE_PRINTLN5("%s:%d XdndPosition comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (source_protocol != XDND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndPosition rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - source_win = event_data[0]; - - /* Ignore XDnD messages from all other windows. */ - if (source_window != source_win) { - DTRACE_PRINTLN4("%s:%d XdndPosition rejected - invalid source window cur=%ld this=%ld.", - __FILE__, __LINE__, source_window, source_win); - return EventFailure; - } - - x = event_data[2] >> 16; - y = event_data[2] & 0xFFFF; - - component = get_component_for_window(event->window); - - if (JNU_IsNull(env, component)) { - /* - * The window must be the embedding toplevel, since otherwise we would reject the - * XdndEnter and never get to this point. - */ - DASSERT(is_embedding_toplevel(event->window)); - - receiver = get_embedded_window(event->display, event->window, x, y); - - if (receiver != None) { - component = get_component_for_window(receiver); - } - } else { - receiver = event->window; - } - - /* Translate mouse position from root coordinates - to the target window coordinates. */ - if (receiver != None) { - Window child = None; - XTranslateCoordinates(event->display, - get_root_for_window(receiver), - get_outer_canvas_for_window(receiver), - x, y, &x, &y, &child); - } - - /* Time stamp - new in XDnD version 1. */ - if (source_protocol_version > 0) { - time_stamp = event_data[3]; - } - - /* User action - new in XDnD version 1. */ - if (source_protocol_version > 1) { - action_atom = event_data[4]; - } else { - /* The default action is XdndActionCopy */ - action_atom = XA_XdndActionCopy; - } - - action = xdnd_to_java_action(action_atom); - - if (track_source_actions) { - source_actions |= action; - } - - if (JNU_IsNull(env, component)) { - if (!JNU_IsNull(env, target_component)) { - dt_postDropTargetEvent(env, target_component, x, y, - java_awt_dnd_DnDConstants_ACTION_NONE, - java_awt_event_MouseEvent_MOUSE_EXITED, - NULL); - } - } else { - if (JNU_IsNull(env, target_component)) { - java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED; - } else { - java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED; - } - - dt_postDropTargetEvent(env, component, x, y, action, - java_event_id, event); - } - - user_action = action; - source_x = x; - source_y = y; - target_component = component; - - return EventSuccess; -} - -/* - * Returns EventConsume if the event should be consumed, - * EventPassAlong otherwise. - */ -static EventStatus -handle_xdnd_leave(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - long* event_data = event->data.l; - Window source_win = None; - - if (source_protocol != XDND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndLeave rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - source_win = event_data[0]; - - /* Ignore XDnD messages from all other windows. */ - if (source_window != source_win) { - DTRACE_PRINTLN4("%s:%d XdndLeave rejected - invalid source window cur=%ld this=%ld.", - __FILE__, __LINE__, source_window, source_win); - return EventFailure; - } - - awt_dnd_cleanup(); - - return EventSuccess; -} - -/* - * Returns EventConsume if the event should be consumed, - * EventPassAlong otherwise. - */ -static EventStatus -handle_xdnd_drop(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - long* event_data = event->data.l; - Window source_win = None; - - DTRACE_PRINTLN5("%s:%d XdndDrop comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (source_protocol != XDND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d XdndDrop rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - source_win = event_data[0]; - - /* Ignore XDnD messages from all other windows. */ - if (source_window != source_win) { - DTRACE_PRINTLN4("%s:%d XdndDrop rejected - invalid source window cur=%ld this=%ld.", - __FILE__, __LINE__, source_window, source_win); - return EventFailure; - } - - if (!JNU_IsNull(env, target_component)) { - dt_postDropTargetEvent(env, target_component, source_x, source_y, user_action, - java_awt_event_MouseEvent_MOUSE_RELEASED, event); - } - - return EventSuccess; -} - -/* - * Returns EventPassAlong if the event should be passed to the original proxy. - * TOP_LEVEL_ENTER should be passed to the original proxy only if the event is - * invalid. - */ -static EventStatus -handle_motif_top_level_enter(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - Display* dpy = event->display; - char* event_data = event->data.b; - unsigned char event_byte_order = 0; - Window source_win = None; - long source_win_mask = 0; - unsigned int protocol_version = MOTIF_DND_PROTOCOL_VERSION; - Atom property_atom = None; - unsigned int data_types_count = 0; - Atom* data_types = NULL; - jlongArray java_data_types = NULL; - - DTRACE_PRINTLN5("%s:%d TOP_LEVEL_ENTER comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (!JNU_IsNull(env, target_component) || source_window != None || - source_protocol != NO_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - if (JNU_IsNull(env, get_component_for_window(event->window)) && - !is_embedding_toplevel(event->window)) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - window is not a registered drop site.", - __FILE__, __LINE__); - return EventFailure; - } - - event_byte_order = read_card8(event_data, 1); - source_win = read_card32(event_data, 8, event_byte_order); - property_atom = read_card32(event_data, 12, event_byte_order); - - /* Extract the available data types. */ - { - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - data = NULL; - ret = checked_XGetWindowProperty(dpy, source_win, property_atom, 0, - 0xFFFF, False, - _XA_MOTIF_DRAG_INITIATOR_INFO, &type, - &format, &nitems, &after, &data); - - /* Ignore the source if the window is destroyed. */ - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid window.", - __FILE__, __LINE__); - return EventFailure; - } - - if (ret == BadAtom) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid property atom.", - __FILE__, __LINE__); - return EventFailure; - } - - if (ret == Success) { - if (type == _XA_MOTIF_DRAG_INITIATOR_INFO && format == 8 && - nitems == MOTIF_INITIATOR_INFO_SIZE) { - unsigned char property_byte_order = read_card8((char*)data, 0); - int index = read_card16((char*)data, 2, property_byte_order); - - protocol_version = read_card8((char*)data, 1); - - if (protocol_version > MOTIF_DND_PROTOCOL_VERSION) { - DTRACE_PRINTLN3("%s:%d TOP_LEVEL_ENTER rejected - invalid protocol version: %d.", - __FILE__, __LINE__, protocol_version); - XFree(data); - return EventFailure; - } - - get_target_list_for_index(dpy, index, &data_types, &data_types_count); - } - - XFree(data); - } - } - - java_data_types = get_data_types_array(env, data_types, data_types_count); - - if (JNU_IsNull(env, java_data_types)) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - cannot create types array.", - __FILE__, __LINE__); - free((char*)data_types); - return EventFailure; - } - - /* - * Select for StructureNotifyMask to receive DestroyNotify in case of source - * crash. - */ - { - unsigned char ret; - XWindowAttributes xwa; - - XGetWindowAttributes(dpy, source_win, &xwa); - - source_win_mask = xwa.your_event_mask; - - ret = checked_XSelectInput(dpy, source_win, - (source_win_mask | StructureNotifyMask)); - - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", - __FILE__, __LINE__); - free((char*)data_types); - (*env)->DeleteGlobalRef(env, java_data_types); - return EventFailure; - } - } - - source_protocol = MOTIF_DND_PROTOCOL; - source_protocol_version = protocol_version; - source_window = source_win; - source_atom = property_atom; - source_window_mask = source_win_mask; - /* - * TOP_LEVEL_ENTER doesn't communicate the list of supported actions - * They are provided in DRAG_MOTION. - */ - source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; - track_source_actions = False; - source_data_types = java_data_types; - source_data_types_native = data_types; - source_data_types_count = data_types_count; - DTRACE_PRINTLN6("%s:%d TOP_LEVEL_ENTER comp=%d src_win=%ld protocol=%d fmt=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol, data_types_count); - - return EventSuccess; -} - -/* - * Returns EventPassAlong if the event should be passed to the original proxy. - * DRAG_MOTION event shouldn't be passed to the original proxy only if it is - * a valid event and the mouse coordinates passed in it specify the point over - * a Java component in this JVM. - */ -static EventStatus -handle_motif_drag_motion(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - char* event_data = event->data.b; - unsigned char event_reason = 0; - unsigned char event_byte_order = 0; - Window source_win = None; - CARD16 flags = 0; - unsigned char motif_action = 0; - unsigned char motif_actions = 0; - jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE; - jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE; - int x = 0; - int y = 0; - jint java_event_id = 0; - jobject component = NULL; - - DTRACE_PRINTLN5("%s:%d DRAG_MOTION comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (source_protocol != MOTIF_DND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d DRAG_MOTION rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - event_reason = read_card8(event_data, 0) & MOTIF_MESSAGE_REASON_MASK; - event_byte_order = read_card8(event_data, 1); - - flags = read_card16(event_data, 2, event_byte_order); - - motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT; - motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT; - - java_action = motif_to_java_actions(motif_action); - java_actions = motif_to_java_actions(motif_actions); - - /* Append source window id to the event data, so that we can send the - response properly. */ - { - Window win = source_window; - void* p = &event->data.b[12]; - if (event_byte_order != MOTIF_BYTE_ORDER) { - SWAP4BYTES(win); - } - write_card32(&p, (CARD32)win); - } - - component = get_component_for_window(event->window); - - if (event_reason == OPERATION_CHANGED) { - /* OPERATION_CHANGED event doesn't provide coordinates, so we use - previously stored position and component ref. */ - x = source_x; - y = source_y; - - if (JNU_IsNull(env, component)) { - component = target_component; - } - } else { - Window receiver = None; - - x = read_card16(event_data, 8, event_byte_order); - y = read_card16(event_data, 10, event_byte_order); - - if (JNU_IsNull(env, component)) { - /* - * The window must be the embedding toplevel, since otherwise we - * would reject the TOP_LEVEL_ENTER and never get to this point. - */ - DASSERT(is_embedding_toplevel(event->window)); - - receiver = get_embedded_window(event->display, event->window, x, y); - - if (receiver != None) { - component = get_component_for_window(receiver); - } - } else { - receiver = event->window; - } - - /* Translate mouse position from root coordinates - to the target window coordinates. */ - if (receiver != None) { - Window child = None; - XTranslateCoordinates(event->display, - get_root_for_window(receiver), - get_outer_canvas_for_window(receiver), - x, y, &x, &y, &child); - } - } - - if (JNU_IsNull(env, component)) { - if (!JNU_IsNull(env, target_component)) { - /* Triggers dragExit */ - dt_postDropTargetEvent(env, target_component, x, y, - java_awt_dnd_DnDConstants_ACTION_NONE, - java_awt_event_MouseEvent_MOUSE_EXITED, - NULL); - } - } else { - if (JNU_IsNull(env, target_component)) { - /* Triggers dragEnter */ - java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED; - } else { - /* Triggers dragOver */ - java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED; - } - - dt_postDropTargetEvent(env, component, x, y, java_action, java_event_id, - event); - } - - source_actions = java_actions; - track_source_actions = False; - user_action = java_action; - source_x = x; - source_y = y; - target_component = component; - - return EventSuccess; -} - -/* - * Returns EventPassAlong if the event should be passed to the original proxy. - * TOP_LEVEL_LEAVE should be passed to the original proxy only if the event - * is invalid. - */ -static EventStatus -handle_motif_top_level_leave(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - char* event_data = event->data.b; - unsigned char event_byte_order = 0; - Window source_win = None; - - DTRACE_PRINTLN5("%s:%d TOP_LEVEL_LEAVE comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (source_protocol != MOTIF_DND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - event_byte_order = read_card8(event_data, 1); - source_win = read_card32(event_data, 8, event_byte_order); - - /* Ignore Motif DnD messages from all other windows. */ - if (source_window != source_win) { - DTRACE_PRINTLN4("%s:%d TOP_LEVEL_LEAVE rejected - invalid source window cur=%ld this=%ld.", - __FILE__, __LINE__, source_window, source_win); - return EventFailure; - } - - /* - * Postpone upcall to java, so that we can abort it in case - * if drop immediatelly follows (see BugTraq ID 4395290). - * Send a dummy ClientMessage event to guarantee that a postponed java - * upcall will be processed. - */ - motif_top_level_leave_postponed = True; - { - XClientMessageEvent dummy; - Window proxy; - - dummy.display = event->display; - dummy.type = ClientMessage; - dummy.window = event->window; - dummy.format = 32; - dummy.message_type = None; - - /* - * If this is an embedded drop site, the event should go to the - * awt_root_window as this is a proxy for all embedded drop sites. - * Otherwise the event should go to the event->window, as we don't use - * proxies for normal drop sites. - */ - if (is_embedding_toplevel(event->window)) { - proxy = get_awt_root_window(); - } else { - proxy = event->window; - } - - XSendEvent(event->display, proxy, False, NoEventMask, - (XEvent*)&dummy); - } - - return EventSuccess; -} - -/* - * Returns EventPassAlong if the event should be passed to the original proxy. - * DROP_START event shouldn't be passed to the original proxy only if it is - * a valid event and the mouse coordinates passed in it specify the point over - * a Java component in this JVM. - */ -static EventStatus -handle_motif_drop_start(XClientMessageEvent* event) { - JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); - char* event_data = event->data.b; - unsigned char event_byte_order = 0; - Window source_win = None; - Atom property_atom = None; - CARD16 flags = 0; - unsigned char motif_action = 0; - unsigned char motif_actions = 0; - jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE; - jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE; - int x = 0; - int y = 0; - jobject component = NULL; - Window receiver = None; - - DTRACE_PRINTLN5("%s:%d DROP_START comp=%X src_win=%ld protocol=%d.", - __FILE__, __LINE__, - target_component, source_window, source_protocol); - - if (source_protocol != MOTIF_DND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d DROP_START rejected - invalid state.", - __FILE__, __LINE__); - return EventFailure; - } - - event_byte_order = read_card8(event_data, 1); - source_win = read_card32(event_data, 16, event_byte_order); - - /* Ignore Motif DnD messages from all other windows. */ - if (source_window != source_win) { - DTRACE_PRINTLN4("%s:%d DROP_START rejected - invalid source window cur=%ld this=%ld.", - __FILE__, __LINE__, source_window, source_win); - return EventFailure; - } - - property_atom = read_card32(event_data, 12, event_byte_order); - - flags = read_card16(event_data, 2, event_byte_order); - - motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT; - motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT; - - java_action = motif_to_java_actions(motif_action); - java_actions = motif_to_java_actions(motif_actions); - - x = read_card16(event_data, 8, event_byte_order); - y = read_card16(event_data, 10, event_byte_order); - - source_actions = java_actions; - - component = get_component_for_window(event->window); - - if (JNU_IsNull(env, component)) { - /* - * The window must be the embedding toplevel, since otherwise we would reject the - * TOP_LEVEL_ENTER and never get to this point. - */ - DASSERT(is_embedding_toplevel(event->window)); - - receiver = get_embedded_window(event->display, event->window, x, y); - - if (receiver != None) { - component = get_component_for_window(receiver); - } - } else { - receiver = event->window; - } - - /* Translate mouse position from root coordinates - to the target window coordinates. */ - if (receiver != None) { - Window child = None; - XTranslateCoordinates(event->display, - get_root_for_window(receiver), - get_outer_canvas_for_window(receiver), - x, y, &x, &y, &child); - } - - if (JNU_IsNull(env, component)) { - if (!JNU_IsNull(env, target_component)) { - /* Triggers dragExit */ - dt_postDropTargetEvent(env, target_component, x, y, - java_awt_dnd_DnDConstants_ACTION_NONE, - java_awt_event_MouseEvent_MOUSE_EXITED, - NULL); - } - } else { - dt_postDropTargetEvent(env, component, x, y, java_action, - java_awt_event_MouseEvent_MOUSE_RELEASED, - event); - } - - return EventSuccess; -} - -static void -send_enter_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) { - XClientMessageEvent enter; - - if (source_protocol == XDND_PROTOCOL) { - enter.display = xclient->display; - enter.type = ClientMessage; - enter.window = toplevel; - enter.format = 32; - enter.message_type = XA_XdndEnter; - enter.data.l[0] = xclient->data.l[0]; /* XID of the source window */ - enter.data.l[1] = source_protocol_version << XDND_PROTOCOL_SHIFT; - enter.data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; - enter.data.l[2] = - source_data_types_count > 0 ? source_data_types_native[0] : None; - enter.data.l[3] = - source_data_types_count > 1 ? source_data_types_native[1] : None; - enter.data.l[4] = - source_data_types_count > 2 ? source_data_types_native[2] : None; - } else if (source_protocol == MOTIF_DND_PROTOCOL) { - int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); - unsigned char byte_order = xclient->data.b[1]; - - enter.display = xclient->display; - enter.type = ClientMessage; - enter.window = toplevel; - enter.format = 8; - enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = &enter.data.b[0]; - int flags = 0; - - flags |= java_to_motif_actions(user_action) << MOTIF_DND_ACTION_SHIFT; - flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; - - write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, byte_order); - write_card16(&p, flags); - { - Time time_stamp = read_card32(xclient->data.b, 4, byte_order); - Window src_window = source_window; - Atom motif_atom = _XA_MOTIF_ATOM_0; - - if (byte_order != MOTIF_BYTE_ORDER) { - SWAP4BYTES(time_stamp); - SWAP4BYTES(src_window); - SWAP4BYTES(motif_atom); - } - write_card32(&p, time_stamp); - write_card32(&p, src_window); - write_card32(&p, motif_atom); - } - } - } else { - return; - } - - forward_client_message_to_toplevel(toplevel, &enter); -} - -static void -send_leave_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) { - XClientMessageEvent leave; - - if (source_protocol == XDND_PROTOCOL) { - leave.display = xclient->display; - leave.type = ClientMessage; - leave.window = toplevel; - leave.format = 32; - leave.message_type = XA_XdndLeave; - leave.data.l[0] = xclient->data.l[0]; /* XID of the source window */ - leave.data.l[1] = 0; /* flags */ - } else if (source_protocol == MOTIF_DND_PROTOCOL) { - int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); - unsigned char byte_order = xclient->data.b[1]; - - leave.display = xclient->display; - leave.type = ClientMessage; - leave.window = toplevel; - leave.format = 8; - leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - { - void* p = &leave.data.b[0]; - int flags = 0; - - write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR); - write_card8(&p, byte_order); - - { - Time time_stamp = read_card32(xclient->data.b, 4, byte_order); - Window src_window = source_window; - - if (byte_order != MOTIF_BYTE_ORDER) { - SWAP4BYTES(time_stamp); - SWAP4BYTES(src_window); - } - write_card32(&p, time_stamp); - write_card32(&p, src_window); - } - } - } else { - return; - } - - forward_client_message_to_toplevel(toplevel, &leave); -} - -static void -post_process_client_message(XClientMessageEvent* xclient, EventStatus status, - EventType type) { - Window win = xclient->window; - Boolean postponed_leave = motif_top_level_leave_postponed; - - motif_top_level_leave_postponed = False; - - if (is_embedding_toplevel(win)) { - Boolean server_grabbed = False; - - if (postponed_leave) { - XClientMessageEvent* leave = &motif_top_level_leave_postponed_event; - DASSERT(leave->type == ClientMessage && type == DropEvent); - /* Grab the server to ensure that no event is sent between - the TOP_LEVEL_LEAVE and the next message. */ - XGrabServer(awt_display); - forward_client_message_to_toplevel(leave->window, leave); - memset(&motif_top_level_leave_postponed_event, 0, - sizeof(XClientMessageEvent)); - } - - /* - * This code forwards drag notifications to the browser according to the - * following rules: - * - the messages that we failed to process are always forwarded to the - * browser; - * - MotionEvents and DropEvents are forwarded if and only if the drag - * is not over a plugin window; - * - XDnD: EnterEvents and LeaveEvents are never forwarded, instead, we - * send synthesized EnterEvents or LeaveEvents when the drag - * respectively exits or enters plugin windows; - * - Motif DnD: EnterEvents and LeaveEvents are always forwarded. - * Synthetic EnterEvents and LeaveEvents are needed, because the XDnD drop - * site implemented Netscape 6.2 has a nice feature: when it receives - * the first XdndPosition it continuously sends XdndStatus messages to - * the source (every 100ms) until the drag terminates or leaves the drop - * site. When the mouse is dragged over plugin window embedded in the - * browser frame, these XdndStatus messages are mixed with the XdndStatus - * messages sent from the plugin. - * For Motif DnD, synthetic events cause Motif warnings being displayed, - * so these events are always forwarded. However, Motif DnD drop site in - * Netscape 6.2 is implemented in the same way, so there could be similar - * problems if the drag source choose Motif DnD for communication. - */ - switch (status) { - case EventFailure: - forward_client_message_to_toplevel(win, xclient); - break; - case EventSuccess: - { - /* True iff the previous notification was MotionEvent and it was - forwarded to the browser. */ - static Boolean motion_passed_along = False; - - Boolean motif_protocol = - xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - switch (type) { - case MotionEvent: - if (JNU_IsNull(env, target_component)) { - if (!motion_passed_along && !motif_protocol) { - send_enter_message_to_toplevel(win, xclient); - } - forward_client_message_to_toplevel(win, xclient); - motion_passed_along = True; - } else { - if (motion_passed_along && !motif_protocol) { - send_leave_message_to_toplevel(win, xclient); - } - motion_passed_along = False; - } - break; - case DropEvent: - if (JNU_IsNull(env, target_component)) { - forward_client_message_to_toplevel(win, xclient); - /* The last chance to cleanup. */ - awt_dnd_cleanup(); - } - motion_passed_along = False; - break; - case EnterEvent: - case LeaveEvent: - if (motif_protocol) { - forward_client_message_to_toplevel(win, xclient); - } - motion_passed_along = False; - break; - } - } - } - - if (postponed_leave) { - XUngrabServer(awt_display); - } - } -} - -/* - * Returns True if the event is processed and shouldn't be passed along to Java. - * Otherwise, return False. - */ -Boolean -awt_dnd_dt_process_event(XEvent* event) { - Display* dpy = event->xany.display; - EventStatus status = EventFailure; - EventType type = UnknownEvent; - - if (event->type == DestroyNotify) { - if (event->xany.window == source_window) { - awt_dnd_cleanup(); - } - /* pass along */ - return False; - } - - if (event->type == PropertyNotify) { - if (is_embedding_toplevel(event->xany.window)) { - Atom atom = event->xproperty.atom; - /* - * If some other client replaced the XDnD or Motif DnD proxy with - * another window we set the proxy back to the awt_root_window - * and update the entry in the embedded_drop_site_list. - * This code is needed, as for example Netscape 4.7 resets the proxy - * when the browser shell is resized. - */ - if (atom == _XA_MOTIF_DRAG_RECEIVER_INFO) { - Window prev_motif_proxy; - ProxyRegistrationStatus status; - status = set_motif_proxy(event->xany.display, event->xany.window, - get_awt_root_window(), &prev_motif_proxy); - if (status != RegFailure && status != RegAlreadyRegistered) { - set_motif_proxy_for_toplevel(event->xany.window, - prev_motif_proxy, - status == RegOverride); - } - } - - if (atom == XA_XdndAware || atom == XA_XdndProxy) { - Window prev_xdnd_proxy; - unsigned int prev_protocol_version; - ProxyRegistrationStatus status; - status = set_xdnd_proxy(event->xany.display, event->xany.window, - get_awt_root_window(), &prev_xdnd_proxy, - &prev_protocol_version); - if (status != RegFailure && status != RegAlreadyRegistered) { - set_xdnd_proxy_for_toplevel(event->xany.window, - prev_xdnd_proxy, - prev_protocol_version, - status == RegOverride); - } - } - } - /* pass along */ - return False; - } - - if (event->type != ClientMessage) { - return False; - } - - if (get_component_for_window(event->xany.window) == NULL && - !is_embedding_toplevel(event->xany.window)) { - return False; - } - - if (motif_top_level_leave_postponed) { - /* Sanity check. */ - if (source_protocol != MOTIF_DND_PROTOCOL) { - DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.", - __FILE__, __LINE__); - awt_dnd_cleanup(); - } else if (event->xclient.message_type == - _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - unsigned char first_byte = event->xclient.data.b[0]; - unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; - unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; - - if (origin == MOTIF_MESSAGE_FROM_INITIATOR && - reason != DROP_START) { - awt_dnd_cleanup(); - } - } else { - awt_dnd_cleanup(); - } - } - - if (event->xclient.message_type == XA_XdndEnter) { - status = handle_xdnd_enter(&event->xclient); - type = EnterEvent; - } else if (event->xclient.message_type == XA_XdndPosition) { - status = handle_xdnd_position(&event->xclient); - type = MotionEvent; - } else if (event->xclient.message_type == XA_XdndLeave) { - status = handle_xdnd_leave(&event->xclient); - type = LeaveEvent; - } else if (event->xclient.message_type == XA_XdndDrop) { - status = handle_xdnd_drop(&event->xclient); - type = DropEvent; - } else if (event->xclient.message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - unsigned char reason = event->xclient.data.b[0] & MOTIF_MESSAGE_REASON_MASK; - unsigned char origin = event->xclient.data.b[0] & MOTIF_MESSAGE_SENDER_MASK; - - /* Only initiator messages should be handled. */ - if (origin == MOTIF_MESSAGE_FROM_INITIATOR) { - switch (reason) { - case DRAG_MOTION: - case OPERATION_CHANGED: - status = handle_motif_drag_motion(&event->xclient); - type = MotionEvent; - break; - case TOP_LEVEL_ENTER: - status = handle_motif_top_level_enter(&event->xclient); - type = EnterEvent; - break; - case TOP_LEVEL_LEAVE: - status = handle_motif_top_level_leave(&event->xclient); - type = LeaveEvent; - break; - case DROP_START: - status = handle_motif_drop_start(&event->xclient); - type = DropEvent; - break; - } - } - } else { - /* Unknown message type. */ - return False; - } - - /* - * We need to handle a special case here: Motif DnD protocol prescribed that - * DROP_START message should always be preceeded with TOP_LEVEL_LEAVE - * message. We need to cleanup on TOP_LEVEL_LEAVE message, but DROP_START - * wouldn't be processed properly. Instead we postpone the cleanup and - * send a dummy client message to ourselves. If dummy arrives first we do a - * normal cleanup. If DROP_START arrives before the dummy we discard delayed - * cleanup. - * In case of forwarding events from an embedded Java app to an embedding - * Java app it could happen that the embedding app receives the dummy before - * the DROP_START message arrives from the embedding app. In this case the - * drop operation on the embedding app fails to complete. - * To resolve this problem we postpone forwarding of TOP_LEVEL_LEAVE message - * until the next client message is about to be forwarded. - */ - if (motif_top_level_leave_postponed && type == LeaveEvent) { - /* motif_top_level_leave_postponed can be set only if the latest client - message has been processed successfully. */ - DASSERT(status == EventSuccess); - memcpy(&motif_top_level_leave_postponed_event, &event->xclient, - sizeof(XClientMessageEvent)); - } else { - post_process_client_message(&event->xclient, status, type); - } - - return True; -} - -static Boolean -register_xdnd_drop_site(Display* dpy, Window toplevel, Window window) { - unsigned char ret; - Atom version_atom = XDND_PROTOCOL_VERSION; - - ret = checked_XChangeProperty(dpy, window, XA_XdndAware, XA_ATOM, 32, - PropModeReplace, - (unsigned char*)&version_atom, 1); - - return (ret == Success); -} - -static Boolean -register_motif_drop_site(Display* dpy, Window toplevel, Window window) { - unsigned char status; - size_t data_size = MOTIF_RECEIVER_INFO_SIZE; - char* data = malloc(data_size); - void* p = data; - - if (data == NULL) { - DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); - return False; - } - - write_card8(&p, MOTIF_BYTE_ORDER); - write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */ - write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */ - write_card8(&p, 0); /* pad */ - write_card32(&p, window); /* proxy window */ - write_card16(&p, 0); /* num_drop_sites */ - write_card16(&p, 0); /* pad */ - write_card32(&p, data_size); - - status = checked_XChangeProperty(dpy, window, _XA_MOTIF_DRAG_RECEIVER_INFO, - _XA_MOTIF_DRAG_RECEIVER_INFO, 8, PropModeReplace, - (unsigned char*)data, data_size); - - free(data); - - return (status == Success); -} - -static Window -find_toplevel_window(Display* dpy, Window window) { - Window ret = None; - Window root = None; - Window parent = None; - Window *children; - unsigned int nchildren; - - int status; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - /* Traverse the ancestor tree from window up to the root and find - the top-level client window nearest to the root. */ - do { - type = None; - - data = NULL; - status = XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False, - AnyPropertyType, &type, &format, &nitems, - &after, &data); - - if (status == Success) { - XFree(data); - } - - if (type != None) { - ret = window; - } - - if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) { - return None; - } - - XFree(children); - - window = parent; - } while (window != root); - - return ret; -} - -static Boolean -register_drop_site(Widget outer_canvas, XtPointer componentRef) { - Display* dpy = XtDisplay(outer_canvas); - Widget shell = NULL; - /* Shell window. */ - Window window = None; - Window root = None; - Window toplevel = None; - - for (shell = outer_canvas; shell != NULL && !XtIsShell(shell); - shell = XtParent(shell)); - - if (shell == NULL || !XtIsRealized(shell)) { - DTRACE_PRINTLN2("%s:%d Cannot find a realized shell for the widget.", - __FILE__, __LINE__); - return False; - } - - window = XtWindow(shell); - - if (!awt_dnd_init(dpy)) { - DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__); - return False; - } - - { - XWindowAttributes xwa; - - if (!XGetWindowAttributes(dpy, window, &xwa)) { - DTRACE_PRINTLN2("%s:%d XGetWindowAttributes failed.", __FILE__, __LINE__); - return False; - } - - root = xwa.root; - - if (root == None) { - DTRACE_PRINTLN2("%s:%d Bad root.", __FILE__, __LINE__); - return False; - } - } - - toplevel = find_toplevel_window(dpy, window); - - /* - * No window with WM_STATE property is found. - * Since the window can be a plugin window reparented to the browser - * toplevel, we cannot determine which window will eventually have WM_STATE - * property set. So we schedule a timer callback that will periodically - * attempt to find an ancestor with WM_STATE and register the drop site - * appropriately. - */ - if (toplevel == None) { - add_delayed_registration_entry(outer_canvas, componentRef); - return False; - } - - if (toplevel == window) { - Boolean xdnd_registered = False; - Boolean motif_registered = False; - - xdnd_registered = register_xdnd_drop_site(dpy, toplevel, window); - - motif_registered = register_motif_drop_site(dpy, toplevel, window); - - if (!xdnd_registered && !motif_registered) { - DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__); - return False; - } - } else { - if (!add_to_embedded_drop_site_list(dpy, root, toplevel, window)) { - DTRACE_PRINTLN2("%s:%d Failed to init proxy.", __FILE__, __LINE__); - return False; - } - } - - /* There is no need to update the window for the component later, since the - window is destroyed only when the component is disposed in which case the - drop site will be unregistered as well. */ - if (add_to_drop_site_list(window, root, toplevel, XtWindow(outer_canvas), - (jobject)componentRef)) { - DTRACE_PRINTLN2("%s:%d Drop site registered.", __FILE__, __LINE__); - return True; - } else { - DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__); - return False; - } -} - -static void -register_drop_site_when_realized(Widget outer_canvas, XtPointer client_data, - XEvent *event, Boolean *dontSwallow) { - if (XtIsRealized(outer_canvas)) { - XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False, - register_drop_site_when_realized, client_data); - - register_drop_site(outer_canvas, client_data); - } -} - -/* - * Registers the top-level Window that contains the specified widget as a drop - * site that supports XDnD and Motif DnD protocols. - * If the registration fails for some reason, adds an event handler that will - * attempt to register the drop site later. - * - * Returns True if the drop site is registered successfully. - */ -static Boolean -awt_dnd_register_drop_site(Widget outer_canvas, XtPointer componentRef) { - if (XtIsRealized(outer_canvas)) { - return register_drop_site(outer_canvas, componentRef); - } else { - XtAddEventHandler(outer_canvas, StructureNotifyMask, False, - register_drop_site_when_realized, - componentRef); - - DTRACE_PRINTLN2("%s:%d Unrealized shell. Register later.", - __FILE__, __LINE__); - - return True; - } -} - -/* - * Unregisters the drop site associated with the top-level Window that contains - * the specified widget . - * - * Returns True if completes successfully, False otherwise. - */ -static Boolean -awt_dnd_unregister_drop_site(Widget outer_canvas, XtPointer componentRef) { - Widget shell = NULL; - - XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False, - register_drop_site_when_realized, componentRef); - - remove_delayed_registration_entry(outer_canvas); - - for (shell = outer_canvas; shell != NULL && !XtIsShell(shell); - shell = XtParent(shell)); - - if (shell != NULL && XtIsShell(shell) && XtIsRealized(shell)) { - Window win = XtWindow(shell); - Window toplevel = get_toplevel_for_window(win); - /* - * Cleanup the global state if this drop site participate in the current - * drag operation. Particularly, this allows to delete global ref to the - * component safely. - */ - if (get_component_for_window(win) == target_component) { - awt_dnd_cleanup(); - } - if (toplevel != win) { - remove_from_embedded_drop_site_list(awt_display, toplevel, win); - } - return remove_from_drop_site_list(win); - } - - return True; -} - -/**************************** XEmbed server DnD support ***********************/ - -/* - * - * - */ -Boolean -register_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server, - Window serverHandle, Window clientHandle) { - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char* data; - unsigned char ret; - unsigned int protocol_version; - - Window xdnd_proxy = None; - unsigned int xdnd_protocol_version = 0; - Boolean xdnd_override = False; - - if (!awt_dnd_init(dpy)) { - DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__); - return False; - } - - /* Get the XDnD protocol version and XDnD proxy of the XEmbed client. */ - data = NULL; - ret = checked_XGetWindowProperty(dpy, clientHandle, XA_XdndAware, 0, 1, - False, AnyPropertyType, &type, &format, - &nitems, &after, &data); - - /* XEmbed client doesn't have an associated XDnD drop site - - do nothing and return True to indicate success. */ - if (ret != Success || data == NULL || nitems == 0 || type != XA_ATOM) { - XFree(data); - return False; - } - - protocol_version = *((unsigned int*)data); - - XFree(data); - - if (protocol_version < XDND_MIN_PROTOCOL_VERSION) { - return False; - } - - xdnd_protocol_version = protocol_version; - - /* XdndProxy is not supported prior to XDnD version 4 */ - if (protocol_version >= 4) { - int status; - - data = NULL; - status = XGetWindowProperty(dpy, clientHandle, XA_XdndProxy, 0, 1, - False, XA_WINDOW, &type, &format, - &nitems, &after, &data); - - if (status == Success && data != NULL && type == XA_WINDOW) { - xdnd_proxy = *((Window*)data); - - if (xdnd_proxy != None) { - XFree(data); - - data = NULL; - status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy, - 0, 1, False, XA_WINDOW, &type, - &format, &nitems, &after, - &data); - - if (status != Success || data == NULL || type != XA_WINDOW || - *((Window*)data) != xdnd_proxy) { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } - - if (xdnd_proxy != None) { - XFree(data); - - data = NULL; - status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware, 0, 1, - False, AnyPropertyType, &type, - &format, &nitems, &after, &data); - - if (status == Success && data != NULL && type == XA_ATOM) { - unsigned int proxy_version = *((unsigned int*)data); - - if (proxy_version != protocol_version) { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } else { - /* Ignore invalid proxy. */ - xdnd_proxy = None; - } - } - } - - XFree(data); - } - - set_xembed_drop_target(env, server); - - /* Add protocol specific entries for the embedded window. */ - /* Only XDnD protocol is supported for XEmbed clients. */ - { - EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL; - - xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); - - if (xdnd_entry == NULL) { - return False; - } - - xdnd_entry->window = clientHandle; - xdnd_entry->proxy = xdnd_proxy; - xdnd_entry->protocol_version = xdnd_protocol_version; - xdnd_entry->overriden = True; - xdnd_entry->next = embedded_xdnd_protocol_list; - embedded_xdnd_protocol_list = xdnd_entry; - } - - { - EmbeddedDropSiteListEntry* entry = NULL; - Window* sites = NULL; - - entry = malloc(sizeof(EmbeddedDropSiteListEntry)); - - if (entry == NULL) { - return False; - } - - sites = malloc(sizeof(Window)); - - if (sites == NULL) { - free(entry); - return False; - } - - sites[0] = clientHandle; - - entry->toplevel = serverHandle; - entry->root = None; - entry->event_mask = 0; - entry->embedded_sites_count = 1; - entry->embedded_sites = sites; - entry->next = embedded_drop_site_list; - embedded_drop_site_list = entry; - } - - return True; -} - -Boolean -unregister_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server, - Window serverHandle, Window clientHandle) { - remove_from_embedded_drop_site_list(dpy, serverHandle, clientHandle); - return True; -} - -void -forward_event_to_embedded(Window embedded, jlong ctxt, jint eventID) { - static XClientMessageEvent* prevMessage = NULL; - static Boolean overXEmbedClient = False; - - XClientMessageEvent* xclient = - (XClientMessageEvent*)jlong_to_ptr(ctxt); - - if (xclient == NULL && prevMessage == NULL) { - return; - } - - if (xclient != NULL) { - /* - * NOTE: this check guarantees that prevMessage will always be an XDnD - * drag message. - */ - if (!is_xdnd_drag_message_type(xclient->message_type)) { - return; - } - - if (!overXEmbedClient) { - long* appended_data = jlong_to_ptr(ctxt) + - sizeof(XClientMessageEvent); - - /* Copy XdndTypeList from source to proxy. */ - if ((appended_data[0] & XDND_DATA_TYPES_BIT) != 0) { - unsigned char ret; - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - data = NULL; - ret = checked_XGetWindowProperty(xclient->display, - xclient->data.l[0], - XA_XdndTypeList, 0, 0xFFFF, - False, XA_ATOM, &type, &format, - &nitems, &after, &data); - - /* Ignore the source if the window is destroyed. */ - if (ret == BadWindow) { - return; - } - - if (ret == Success) { - if (type == XA_ATOM && format == 32) { - ret = checked_XChangeProperty(xclient->display, - xclient->window, - XA_XdndTypeList, XA_ATOM, - 32, PropModeReplace, data, - nitems); - } - - XFree(data); - } - } - - set_proxy_mode_source_window(xclient->data.l[0]); - - { - XClientMessageEvent enter; - enter.display = xclient->display; - enter.type = ClientMessage; - enter.window = embedded; - enter.format = 32; - enter.message_type = XA_XdndEnter; - - enter.data.l[0] = xclient->window; /* XID of the source window */ - enter.data.l[1] = appended_data[0]; - enter.data.l[2] = appended_data[1]; - enter.data.l[3] = appended_data[2]; - enter.data.l[4] = appended_data[3]; - - forward_client_message_to_toplevel(embedded, &enter); - } - - overXEmbedClient = True; - } - - /* Make a copy of the original event, since we are going to modify the - event while it still can be referenced from other Java events. */ - { - XClientMessageEvent copy; - memcpy(©, xclient, sizeof(XClientMessageEvent)); - copy.data.l[0] = xclient->window; - - forward_client_message_to_toplevel(embedded, ©); - } - } - - if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) { - if (overXEmbedClient) { - if (xclient != NULL || prevMessage != NULL) { - /* Last chance to send XdndLeave to the XEmbed client. */ - XClientMessageEvent leave; - - leave.display = xclient != NULL ? - xclient->display : prevMessage->display; - leave.type = ClientMessage; - leave.window = embedded; - leave.format = 32; - leave.message_type = XA_XdndLeave; - leave.data.l[0] = xclient != NULL ? - xclient->window : prevMessage->window; /* XID of the source window */ - leave.data.l[1] = 0; /* flags */ - - forward_client_message_to_toplevel(embedded, &leave); - } - overXEmbedClient = False; - } - } - - if (eventID == java_awt_event_MouseEvent_MOUSE_RELEASED) { - overXEmbedClient = False; - awt_dnd_cleanup(); - } - - if (prevMessage != 0) { - free(prevMessage); - prevMessage = 0; - } - - if (xclient != 0 && overXEmbedClient) { - prevMessage = malloc(sizeof(XClientMessageEvent)); - - memcpy(prevMessage, xclient, sizeof(XClientMessageEvent)); - } -} - -/******************************************************************************/ - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: registerX11DropTarget - * Signature: (Ljava/awt/Component;)V - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_registerX11DropTarget(JNIEnv *env, jobject this, - jobject target) { - struct FrameData* wdata = NULL; - DropSitePtr dsi = NULL; - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL || wdata->winData.comp.widget == NULL) { - JNU_ThrowNullPointerException(env, "NULL component data"); - return; - } - - if (wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "Null shell widget"); - return; - } - - DASSERT(wdata->winData.comp.dsi == NULL); - - dsi = (DropSitePtr)calloc(1, sizeof(struct DropSiteInfo)); - - if (dsi == NULL) { - JNU_ThrowOutOfMemoryError(env, ""); - return; - } - - dsi->component = (*env)->NewGlobalRef(env, target); - dsi->isComposite = False; - - wdata->winData.comp.dsi = dsi; - - AWT_LOCK(); - - awt_dnd_register_drop_site(wdata->winData.comp.widget, - dsi->component); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MWindowPeer - * Method: unregisterX11DropTarget - * Signature: (Ljava/awt/Component;)V - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget(JNIEnv *env, - jobject this, - jobject target) { - struct FrameData* wdata = NULL; - DropSitePtr dsi = NULL; - - wdata = (struct FrameData *) - JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); - - if (wdata == NULL) { - JNU_ThrowNullPointerException(env, "Null component data"); - return; - } - - if (wdata->winData.shell == NULL) { - JNU_ThrowNullPointerException(env, "Null shell widget"); - return; - } - - dsi = wdata->winData.comp.dsi; - - if (dsi == NULL) { - JNU_ThrowNullPointerException(env, "Null DropSiteInfo"); - return; - } - - AWT_LOCK(); - - awt_dnd_unregister_drop_site(wdata->winData.comp.widget, dsi->component); - - AWT_UNLOCK(); - - wdata->winData.comp.dsi = NULL; - - (*env)->DeleteGlobalRef(env, dsi->component); - - free(dsi); -} - -static void -dt_send_event_to_source(XClientMessageEvent* xclient) { - /* Shortcut if the source is in the same JVM. */ - if (xclient->window == awt_dnd_ds_get_source_window()) { - awt_dnd_ds_process_event((XEvent*)xclient); - } else { - unsigned char ret; - - ret = checked_XSendEvent(xclient->display, xclient->window, False, - NoEventMask, (XEvent*)xclient); - - if (ret == BadWindow) { - DTRACE_PRINTLN2("%s:%d XSendEvent - invalid window.", - __FILE__, __LINE__); - - /* Cleanup if we are still communicating with this window. */ - if (source_window == xclient->window) { - awt_dnd_cleanup(); - } - } - } -} - -static void -dt_send_response(XClientMessageEvent* xclient, jint eventID, jint action) { - Display* dpy = xclient->display; - XClientMessageEvent response; - - if (xclient->message_type == XA_XdndPosition) { - long* event_data = xclient->data.l; - - if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) { - action = java_awt_dnd_DnDConstants_ACTION_NONE; - } - - response.display = dpy; - response.type = ClientMessage; - response.window = event_data[0]; - response.format = 32; - response.message_type = XA_XdndStatus; - /* target window */ - response.data.l[0] = xclient->window; - /* flags */ - response.data.l[1] = 0; - if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { - response.data.l[1] |= XDND_ACCEPT_DROP_FLAG; - } - /* specify an empty rectangle */ - response.data.l[2] = 0; /* x, y */ - response.data.l[3] = 0; /* w, h */ - /* action accepted by the target */ - response.data.l[4] = java_to_xdnd_action(action); - } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); - int origin = (int)(xclient->data.b[0] & MOTIF_MESSAGE_SENDER_MASK); - unsigned char byte_order = xclient->data.b[1]; - CARD16 response_flags = 0; - CARD8 response_reason = 0; - void* p = &response.data.b; - - /* Only initiator messages should be handled. */ - if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { - DTRACE_PRINTLN2("%s:%d Receiver message.", __FILE__, __LINE__); - return; - } - - switch (reason) { - case DRAG_MOTION: - switch (eventID) { - case java_awt_event_MouseEvent_MOUSE_ENTERED: - response_reason = DROP_SITE_ENTER; - break; - case java_awt_event_MouseEvent_MOUSE_DRAGGED: - response_reason = DRAG_MOTION; - break; - case java_awt_event_MouseEvent_MOUSE_EXITED: - response_reason = DROP_SITE_LEAVE; - break; - } - } - - response.display = dpy; - response.type = ClientMessage; - response.window = read_card32(xclient->data.b, 12, byte_order); - response.format = 8; - response.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; - - write_card8(&p, response_reason | MOTIF_MESSAGE_FROM_RECEIVER); - write_card8(&p, MOTIF_BYTE_ORDER); - - if (response_reason != DROP_SITE_LEAVE) { - CARD16 flags = read_card16(xclient->data.b, 2, byte_order); - unsigned char drop_site_status = - (action == java_awt_dnd_DnDConstants_ACTION_NONE) ? - MOTIF_INVALID_DROP_SITE : MOTIF_VALID_DROP_SITE; - - /* Clear action and drop site status bits. */ - response_flags = - flags & ~MOTIF_DND_ACTION_MASK & ~MOTIF_DND_STATUS_MASK; - - /* Fill in new action and drop site status. */ - response_flags |= - java_to_motif_actions(action) << MOTIF_DND_ACTION_SHIFT; - response_flags |= - drop_site_status << MOTIF_DND_STATUS_SHIFT; - } else { - response_flags = 0; - } - - write_card16(&p, response_flags); - - /* Write time stamp. */ - write_card32(&p, read_card32(xclient->data.b, 4, byte_order)); - - /* Write coordinates. */ - if (response_reason != DROP_SITE_LEAVE) { - write_card16(&p, read_card16(xclient->data.b, 8, byte_order)); - write_card16(&p, read_card16(xclient->data.b, 10, byte_order)); - } else { - write_card16(&p, 0); - write_card16(&p, 0); - } - } else { - return; - } - - dt_send_event_to_source(&response); -} - -static void -dummy_selection_callback(Widget w, XtPointer client_data, Atom* selection, - Atom* type, XtPointer value, unsigned long *length, - int32_t *format) { - /* The selection callback is responsible for freeing the data. */ - if (value != NULL) { - XtFree(value); - value = NULL; - } -} - -static void -dt_notify_drop_done(JNIEnv* env, XClientMessageEvent* xclient, jboolean success, - jint action) { - if (xclient->message_type == XA_XdndDrop) { - Display* dpy = xclient->display; - XClientMessageEvent finished; - long* event_data = xclient->data.l; - - /* - * The XDnD protocol recommends that the target requests the special - * target DELETE in case if the drop action is XdndActionMove. - */ - if (action == java_awt_dnd_DnDConstants_ACTION_MOVE && - success == JNI_TRUE) { - - Time time_stamp = event_data[2]; - - XtGetSelectionValue(awt_root_shell, XA_XdndSelection, XA_DELETE, - dummy_selection_callback, NULL, time_stamp); - } - - finished.display = dpy; - finished.type = ClientMessage; - finished.window = event_data[0]; - finished.format = 32; - finished.message_type = XA_XdndFinished; - finished.data.l[0] = xclient->window; - finished.data.l[1] = 0; /* flags */ - finished.data.l[2] = None; - if (source_protocol_version >= 5) { - if (success == JNI_TRUE) { - finished.data.l[1] |= XDND_ACCEPT_DROP_FLAG; - } - finished.data.l[2] = java_to_xdnd_action(action); - } - - dt_send_event_to_source(&finished); - } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - char* event_data = xclient->data.b; - unsigned char event_byte_order = read_card8(event_data, 1); - unsigned char first_byte = read_card8(event_data, 0); - unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; - unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; - Atom selection = None; - Time time_stamp = CurrentTime; - Atom status_atom = None; - - if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { - DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__); - return; - } - - if (reason != DROP_START) { - DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__); - return; - } - - selection = read_card32(event_data, 12, event_byte_order); - time_stamp = read_card32(event_data, 4, event_byte_order); - - if (success == JNI_TRUE) { - status_atom = XA_XmTRANSFER_SUCCESS; - } else { - status_atom = XA_XmTRANSFER_FAILURE; - } - - /* - * This is just the way to communicate the drop completion status back - * to the initiator as prescribed by the Motif DnD protocol. - */ - XtGetSelectionValue(awt_root_shell, selection, status_atom, - dummy_selection_callback, NULL, time_stamp); - } - - /* - * Flush the buffer to guarantee that the drop completion event is sent - * to the source before the method returns. - */ - XFlush(awt_display); - - /* Trick to prevent awt_dnd_cleanup() from posting dragExit */ - target_component = NULL; - /* Cannot do cleanup before the drop finishes as we need source protocol - version to send XdndFinished message. */ - awt_dnd_cleanup(); -} - -/* - * Class: sun_awt_motif_X11DropTargetContextPeer - * Method: sendResponse - * Signature: (IIJZ)V - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse(JNIEnv *env, - jobject this, - jint eventID, - jint action, - jlong nativeCtxt, - jboolean dispatcherDone, - jboolean consumed) { - XClientMessageEvent* xclient = - (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); - - AWT_LOCK(); - - if (consumed == JNI_FALSE) { - dt_send_response(xclient, eventID, action); - } - - /* - * Free the native context only if all copies of the original event are - * processed. - */ - if (dispatcherDone == JNI_TRUE) { - XtFree((char*)xclient); - } - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_X11DropTargetContextPeer - * Method: dropDone - * Signature: (JZI)V - */ - -JNIEXPORT void JNICALL -Java_sun_awt_motif_X11DropTargetContextPeer_dropDone(JNIEnv *env, - jobject this, - jlong nativeCtxt, - jboolean success, - jint action) { - XClientMessageEvent* xclient = - (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); - - AWT_LOCK(); - - dt_notify_drop_done(env, xclient, success, action); - - XtFree((char*)xclient); - - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_X11DropTargetContextPeer - * Method: getData - * Signature: (IJ)Ljava/lang/Object; - */ - -JNIEXPORT jobject JNICALL -Java_sun_awt_motif_X11DropTargetContextPeer_getData(JNIEnv *env, - jobject this, - jlong nativeCtxt, - jlong formatAtom) { - XClientMessageEvent* xclient = - (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); - - Atom selection = None; - Time time_stamp = CurrentTime; - Atom target = (Atom)formatAtom; - - if (xclient->message_type == XA_XdndDrop || - xclient->message_type == XA_XdndPosition) { - Display* dpy = xclient->display; - Window source_win = xclient->data.l[0]; - Atom protocol_version = 0; - - int status; - - Atom type; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data; - - AWT_LOCK(); - - data = NULL; - status = XGetWindowProperty(dpy, source_win, XA_XdndAware, 0, 0xFFFF, - False, XA_ATOM, &type, &format, &nitems, - &after, &data); - - if (status == Success && data != NULL && type == XA_ATOM && format == 32 - && nitems > 0) { - protocol_version = (protocol_version > XDND_PROTOCOL_VERSION) ? - XDND_PROTOCOL_VERSION : protocol_version; - - if (protocol_version > 0) { - if (xclient->message_type == XA_XdndDrop) { - time_stamp = xclient->data.l[2]; - } else if (xclient->message_type == XA_XdndPosition) { - time_stamp = xclient->data.l[3]; - } - } - } - - if (status == Success) { - XFree(data); - data = NULL; - } - - AWT_FLUSH_UNLOCK(); - - selection = XA_XdndSelection; - if (time_stamp == CurrentTime) { - time_stamp = awt_util_getCurrentServerTime(); - } - - } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { - char* event_data = xclient->data.b; - unsigned char event_byte_order = read_card8(event_data, 1); - unsigned char first_byte = read_card8(event_data, 0); - unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; - unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; - - if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { - DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__); - return NULL; - } - - switch (reason) { - case DROP_START: - selection = read_card32(event_data, 12, event_byte_order); - break; - case DRAG_MOTION: - case OPERATION_CHANGED: - selection = source_atom; - break; - default: - DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__); - return NULL; - } - - if (selection == None) { - return NULL; - } - - time_stamp = read_card32(event_data, 4, event_byte_order); - } else { - return NULL; - } - - return get_selection_data(env, selection, target, time_stamp); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_motif.c --- a/jdk/src/solaris/native/sun/awt/awt_motif.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright 2000-2002 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_motif.h" - -#include - -/* Common routines required for both Motif 2.1 and Motif 1.2 */ -#include - -/* Remove the ScrollBar widget's continuous scrolling timeout handler - on a ButtonRelease to prevent the continuous scrolling that would - occur if a timeout expired after the ButtonRelease. -*/ -/* - * Note: RFE:4263104 is filed when the API is available these needs to removed - */ -void -awt_motif_Scrollbar_ButtonReleaseHandler(Widget w, - XtPointer data, - XEvent *event, - Boolean *cont) -{ - /* Remove the timeout handler. */ -#define END_TIMER (1<<2) - XmScrollBarWidget sbw = (XmScrollBarWidget) w; - if (sbw->scrollBar.timer != NULL) { - XtRemoveTimeOut( sbw->scrollBar.timer ); - sbw->scrollBar.timer = (XtIntervalId)NULL; - sbw->scrollBar.flags |= END_TIMER; - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_motif12.c --- a/jdk/src/solaris/native/sun/awt/awt_motif12.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,435 +0,0 @@ -/* - * Copyright 2000-2001 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. - */ - -#if MOTIF_VERSION!=1 - #error This file should only be compiled with motif 1.2 -#endif - -#include "awt_motif.h" -#include -#include -#include "debug_util.h" -#include "awt.h" - -/* - * awt_motif_getIMStatusHeight is a cut and paste of the ImGetGeo() function - * found in CDE Motif's Xm/XmIm.c. It returns the height of the Input Method - * Status region attached to the given VendorShell. This is needed in order - * to calculate geometry for Frames and Dialogs that contain TextField or - * TextArea widgets. - * - * BCB: Copying this function out of the Motif source is a horrible - * hack. Unfortunately, Motif tries to hide the existence of the IM Status - * region from us so it does not provide any public way to get this info. - * Clearly a better long term solution needs to be found. - */ - -typedef struct _XmICStruct { - struct _XmICStruct *next; - Widget icw; - Window focus_window; - XtArgVal foreground; - XtArgVal background; - XtArgVal background_pixmap; - XtArgVal font_list; - XtArgVal line_space; - int32_t status_width; - int32_t status_height; - int32_t preedit_width; - int32_t preedit_height; - Boolean has_focus; - Boolean need_reset; -} XmICStruct; - -typedef struct { - Widget im_widget; - XIMStyle input_style; - XIC xic; - int32_t status_width; - int32_t status_height; - int32_t preedit_width; - int32_t preedit_height; - XmICStruct *iclist; - XmICStruct *current; -} XmImInfo; - -static XFontSet extract_fontset(XmFontList); -static XmICStruct *get_iclist(Widget); - -#define MAXARGS 10 -static Arg xic_vlist[MAXARGS]; -static Arg status_vlist[MAXARGS]; -static Arg preedit_vlist[MAXARGS]; - -#define NO_ARG_VAL -1 -#define SEPARATOR_HEIGHT 2 - - -#ifdef MOTIF_2_1_HACK -/* To shut up warning messages from "cc -v" - * Copied from Solaris 2.6 /usr/dt/include/Xm/BaseClassP.h and not - * there in Solaris 7. - */ -#if defined(__SunOS_5_7) || defined(__SunOS_5_8) -extern XmWidgetExtData _XmGetWidgetExtData(Widget, unsigned char); -#endif - -#else - -/* - The following defines are to make the XmImGetXIC to compile on systems - lower than SunOS 5.7, so therefore the following is a copy of the - defines on SunOS 5.7/Motif2.1 header files. -*/ -/*#if defined (__SunOS_5_5_1) || defined (__SunOS_5_6)*/ -#define XmPER_SHELL 0 - -extern XIC XmImGetXIC( - Widget w, - unsigned int input_policy, - ArgList args, - Cardinal num_args) ; -#endif - -static XmICStruct * -get_iclist(Widget w) -{ - Widget p; - XmVendorShellExtObject ve; - XmWidgetExtData extData; - XmImInfo *im_info; - - p = w; - while (!XtIsShell(p)) - p = XtParent(p); - - extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) p, XmSHELL_EXTENSION); - if (extData == NULL) - return NULL; - - ve = (XmVendorShellExtObject) extData->widget; - if ((im_info = (XmImInfo *) ve->vendor.im_info) == NULL) - return NULL; - else - return im_info->iclist; -} - -int32_t -awt_motif_getIMStatusHeight(Widget vw, jobject tc) -{ - XmICStruct *icp; - XmVendorShellExtObject ve; - XmWidgetExtData extData; - XmImInfo *im_info; - int32_t width = 0; - int32_t height = 0; - XRectangle rect; - XRectangle *rp; - int32_t old_height; - Arg args[1]; - int32_t base_height; - XFontSet fs; - XFontSet fss = NULL; - XFontSet fsp = NULL; - - extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) vw, XmSHELL_EXTENSION); - ve = (XmVendorShellExtObject) extData->widget; - - if ((icp = get_iclist(vw)) == NULL) { - ve->vendor.im_height = 0; - return 0; - } - im_info = (XmImInfo *) ve->vendor.im_info; - if (im_info->xic == NULL) { - ve->vendor.im_height = 0; - return 0; - } - status_vlist[0].name = XNFontSet; - status_vlist[1].name = NULL; - preedit_vlist[0].name = XNFontSet; - preedit_vlist[1].name = NULL; - - xic_vlist[0].name = XNAreaNeeded; - xic_vlist[1].name = NULL; - - im_info->status_width = 0; - im_info->status_height = 0; - im_info->preedit_width = 0; - im_info->preedit_height = 0; - for (; icp != NULL; icp = icp->next) { - if (im_info->input_style & XIMStatusArea) { - if (icp->status_height == 0) { - char *ret; - - if (icp->font_list == NO_ARG_VAL || - (fss = extract_fontset((XmFontList) icp->font_list)) == NULL) - continue; - - status_vlist[0].value = (XtArgVal) fss; - XSetICValues(im_info->xic, - XNStatusAttributes, &status_vlist[0], - NULL); - - xic_vlist[0].value = (XtArgVal) & rp; - ret = XGetICValues(im_info->xic, - XNStatusAttributes, &xic_vlist[0], - NULL); - - if (ret) { - /* Cannot obtain XIC value. IM server may be gone. */ - ve->vendor.im_height = 0; - return 0; - } else { - icp->status_width = rp->width; - icp->status_height = rp->height; - XFree(rp); - } - } - if (icp->status_width > im_info->status_width) - im_info->status_width = icp->status_width; - if (icp->status_height > im_info->status_height) - im_info->status_height = icp->status_height; - } - if (im_info->input_style & XIMPreeditArea) { - if (icp->preedit_height == 0) { - if (icp->font_list == NO_ARG_VAL || - (fsp = extract_fontset((XmFontList) icp->font_list)) == NULL) - continue; - - preedit_vlist[0].value = (XtArgVal) fsp; - XSetICValues(im_info->xic, - XNPreeditAttributes, &preedit_vlist[0], - NULL); - - xic_vlist[0].value = (XtArgVal) & rp; - XGetICValues(im_info->xic, - XNPreeditAttributes, &xic_vlist[0], - NULL); - - icp->preedit_width = rp->width; - icp->preedit_height = rp->height; - XFree(rp); - } - if (icp->preedit_width > im_info->preedit_width) - im_info->preedit_width = icp->preedit_width; - if (icp->preedit_height > im_info->preedit_height) - im_info->preedit_height = icp->preedit_height; - } - } - - if (im_info->current != NULL && (fss != NULL || fsp != NULL)) { - if (im_info->current->font_list != NO_ARG_VAL && - (fs = extract_fontset((XmFontList) im_info->current->font_list)) - != NULL) { - if (fss != NULL) - status_vlist[0].value = (XtArgVal) fs; - else - status_vlist[0].name = NULL; - if (fsp != NULL) - preedit_vlist[0].value = (XtArgVal) fs; - else - preedit_vlist[0].name = NULL; - XSetICValues(im_info->xic, - XNStatusAttributes, &status_vlist[0], - XNPreeditAttributes, &preedit_vlist[0], - NULL); - } - } - if (im_info->status_height > im_info->preedit_height) - height = im_info->status_height; - else - height = im_info->preedit_height; - old_height = ve->vendor.im_height; - if (height) - height += SEPARATOR_HEIGHT; - - ve->vendor.im_height = height; - - XtSetArg(args[0], XtNbaseHeight, &base_height); - XtGetValues(vw, args, 1); - if (base_height < 0) - base_height = 0; - XtSetArg(args[0], XtNbaseHeight, base_height); - XtSetValues(vw, args, 1); - return height; -} -static XRectangle geometryRect; -XVaNestedList awt_motif_getXICStatusAreaList(Widget w, jobject tc) -{ - Widget p; - XmVendorShellExtObject ve; - XmWidgetExtData extData; - XmImInfo *im_info; - XmICStruct *icp; - - XVaNestedList list = NULL; - XRectangle *ssgeometry = &geometryRect; - Pixel bg; - Pixel fg; - Pixmap bpm; - Dimension height,width; - Position x,y; - - p = w; - while (!XtIsShell(p)){ - p = XtParent(p); - } - - XtVaGetValues(p, - XmNx, &x, - XmNy, &y, - XmNwidth, &width, - XmNheight, &height, - NULL); - - extData = (XmWidgetExtData)_XmGetWidgetExtData((Widget) p, XmSHELL_EXTENSION); - if (extData == NULL) { - return NULL; - } - - ve = (XmVendorShellExtObject) extData->widget; - if ((im_info = (XmImInfo *) ve->vendor.im_info) == NULL) { - return NULL; - } else - icp = im_info->iclist; - - - if (icp) { - /* - * We hava at least a textfield/textarea in the frame, use the - * first one. - */ - ssgeometry->x = 0; - ssgeometry->y = height - icp->status_height; - ssgeometry->width = icp->status_width; - ssgeometry->height = icp->status_height; - - /* - * use motif TextComponent's resource - */ - fg = icp->foreground; - bg = icp->background; - bpm = icp->background_pixmap; - - list = XVaCreateNestedList(0, - XNFontSet, extract_fontset((XmFontList)icp->font_list), - XNArea, ssgeometry, - XNBackground, bg, - XNForeground, fg, - XNBackgroundPixmap, bpm, - NULL); - } - return list ; -} - -static XFontSet -extract_fontset(XmFontList fl) -{ - XmFontContext context; - XmFontListEntry next_entry; - XmFontType type_return; - XtPointer tmp_font; - XFontSet first_fs = NULL; - char *font_tag; - - if (!XmFontListInitFontContext(&context, fl)) - return NULL; - - do { - next_entry = XmFontListNextEntry(context); - if (next_entry) { - tmp_font = XmFontListEntryGetFont(next_entry, &type_return); - if (type_return == XmFONT_IS_FONTSET) { - font_tag = XmFontListEntryGetTag(next_entry); - if (!strcmp(font_tag, XmFONTLIST_DEFAULT_TAG)) { - XmFontListFreeFontContext(context); - XtFree(font_tag); - return (XFontSet) tmp_font; - } - XtFree(font_tag); - if (first_fs == NULL) - first_fs = (XFontSet) tmp_font; - } - } - } while (next_entry); - - XmFontListFreeFontContext(context); - return first_fs; -} - -/* - * Motif 1.2 requires that an X event passed to XmDragStart is of - * ButtonPress type. In Motif 2.1 the restriction is relaxed to allow - * ButtonPress, ButtonRelease, KeyRelease, KeyPress, MotionNotify events - * as drag initiators. Actually the code in Motif 1.2 works okay for these - * events as well, since it uses only the fields that have the same values - * in all five event types. To bypass the initial sanity check in - * XmDragStart we forcibly change event type to ButtonPress. - * - * This function causes an UnsatisfiedLinkError on Linux. - * Since Linux only links against Motif 2.1, we can safely remove - * this function altogether from the Linux build. - * bchristi 1/22/2001 - */ - -#ifdef __solaris__ -void -awt_motif_adjustDragTriggerEvent(XEvent* xevent) { - xevent->type = ButtonPress; -} -#endif /* __solaris__ */ - -static XmDragStartProc do_drag_start = NULL; -static Widget drag_initiator = NULL; - -static void -CheckedDragStart(XmDragContext dc, Widget src, XEvent *event) { - DASSERT(do_drag_start != NULL); - DASSERT(drag_initiator != NULL); - /* - * Fix for BugTraq ID 4407057. - * Enable the drag operation only if it is registered on the specific widget. - * We use this check to disable Motif default drag support. - */ - if (src == drag_initiator) { - do_drag_start(dc, src, event); - } else { - /* - * This is the last chance to destroy the XmDragContext widget. - * NOTE: We rely on the fact that Motif 1.2 never uses the pointer - * to XmDragContext object returned from XmDragStart. - */ - XtDestroyWidget(dc); - } -} - -void -awt_motif_enableSingleDragInitiator(Widget w) { - DASSERT(drag_initiator == NULL && do_drag_start == NULL && w != NULL); - drag_initiator = w; - do_drag_start = xmDragContextClassRec.drag_class.start; - DASSERT(do_drag_start != NULL); - xmDragContextClassRec.drag_class.start = (XmDragStartProc)CheckedDragStart; -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_motif21.c --- a/jdk/src/solaris/native/sun/awt/awt_motif21.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * Copyright 2000-2006 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. - */ - -#if MOTIF_VERSION!=2 - #error This file should only be compiled with motif 2.1 -#endif - -#include "awt_motif.h" -#include -#include "awt.h" -#include "awt_p.h" -#include "awt_Component.h" - -#define XmPER_SHELL 0 -extern int32_t _XmImGetGeo( - Widget vw) ; - -#define MAXARGS 10 -static Arg xic_vlist[MAXARGS]; - -#define SEPARATOR_HEIGHT 2 -#define MTEXTAREAPEER_CLASS_NAME "sun/awt/motif/MTextAreaPeer" -extern struct MComponentPeerIDs mComponentPeerIDs; -static jobject mTextAreaClass = NULL; - -/* - * Get the Motif text widget from the text component peer. XmImGetXIC() - * function should be issued on Motif text widgets. - */ -static Widget getTextWidget(jobject tc) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - if (mTextAreaClass == NULL) { - jclass localClass = (*env)->FindClass(env, MTEXTAREAPEER_CLASS_NAME); - mTextAreaClass = (jclass)(*env)->NewGlobalRef(env, localClass); - (*env)->DeleteLocalRef(env, localClass); - } - - if ((*env)->IsInstanceOf(env, tc, mTextAreaClass)) { - struct TextAreaData * tdata = (struct TextAreaData *) - JNU_GetLongFieldAsPtr(env, tc, mComponentPeerIDs.pData); - return tdata->txt; - } else { - struct ComponentData * tdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, tc, mComponentPeerIDs.pData); - return tdata->widget; - } -} - -/* get_im_height: returns height of the input method status area in pixels. - * - * This function assumes that if any XIM related information cannot be - * queried then the app must not have an input method status area in the - * current locale and returns zero as the status area height - */ -int32_t -awt_motif_getIMStatusHeight(Widget w, jobject tc) -{ - XIC xic = NULL; - XRectangle *im_rect=NULL; - int32_t im_height = 0; - char *ret; - - xic = XmImGetXIC(getTextWidget(tc), XmPER_SHELL, NULL, 0); - - if(xic != NULL) { - /* finally query the server for the status area geometry */ - xic_vlist[0].name = XNArea; - xic_vlist[0].value = (XtArgVal)&im_rect; - xic_vlist[1].name = NULL; - ret=XGetICValues(xic, XNStatusAttributes, &xic_vlist[0], NULL); - if (ret == NULL && im_rect != NULL) { - im_height = im_rect->height; - if (im_height > 0) { - im_height += SEPARATOR_HEIGHT; - } - XFree(im_rect); - } else { - im_height = 0; - } - } - - if (im_height == 0) { - im_height = _XmImGetGeo(w); - } - -#if defined(DEBUG) - jio_fprintf(stderr,"awt_motif_getIMStatusHeight: Height = %d",im_height); -#endif - return im_height; -} - - -static XRectangle geomRect; -static Pixmap bpm; -XVaNestedList awt_motif_getXICStatusAreaList(Widget w, jobject tc) -{ - XIC xic; - - XRectangle *im_rect; - XFontSet *im_font; - - Pixel bg ; - Pixel fg ; - Dimension height, width ; - Position x,y ; - - XVaNestedList list = NULL; - - char *ret; - Widget p=w; - - while (!XtIsShell(p)) { - p = XtParent(p); - } - - XtVaGetValues(p, - XmNx, &x, - XmNy, &y, - XmNwidth, &width, - XmNheight, &height, - XmNbackgroundPixmap, &bpm, - NULL); - - - - xic = XmImGetXIC(getTextWidget(tc), XmPER_SHELL, NULL, 0); - if(xic == NULL) - { -#if defined DEBUG - jio_fprintf(stderr,"Could not get XIC"); -#endif - return list ; - } - - /* finally query the server for the required attributes area geometry */ - xic_vlist[0].name = XNFontSet ; - xic_vlist[0].value = (XtArgVal) &im_font ; - xic_vlist[1].name = XNArea; - xic_vlist[1].value = (XtArgVal) &im_rect; - xic_vlist[2].name = XNBackground ; - xic_vlist[2].value = (XtArgVal) &bg ; - xic_vlist[3].name = XNForeground ; - xic_vlist[3].value = (XtArgVal) &fg ; - xic_vlist[4].name = NULL; - - - if(ret=XGetICValues(xic, XNStatusAttributes, &xic_vlist[0], NULL)) - { - return list ; - } else { - geomRect.x = 0 ; - geomRect.y = height - im_rect->height ; - geomRect.width = im_rect->width ; - geomRect.height = im_rect->height ; - XFree(im_rect) ; - - list = XVaCreateNestedList(0 , - XNFontSet, im_font , - XNArea, &geomRect , - XNBackground, bg , - XNForeground, fg , - XNBackgroundPixmap, &bpm , - NULL ); - } -#if defined(DEBUG) - jio_fprintf(stderr,"awt_motif_getXICStatusAreaList:\n"); - jio_fprintf(stderr,"XNArea:x=%d,y=%d,width=%d,height=%d\n", \ - geomRect.x,geomRect.y,geomRect.width,geomRect.height); - jio_fprintf(stderr,"XNBackground=0x%x\n",bg); - jio_fprintf(stderr,"XNForeground=0x%x\n",fg); - jio_fprintf(stderr,"XNBackgroundPixmap=0x%x\n",bpm); -#endif - return list ; - -} - - /* This function causes an UnsatisfiedLinkError on Linux. - * Since Linux only links against Motif 2.1 and under 2.1 this function - * is a no-op, we can safely remove - * this function altogether from the Linux build. - * bchristi 1/22/2001 - */ - -#ifdef __solaris__ -void -awt_motif_adjustDragTriggerEvent(XEvent* xevent) { - /* Do nothing. In Motif 2.1 the sanity check is corrected - to allow any imput event as a drag trigger event. */ -} -#endif /* __solaris__ */ - -static void -CheckDragInitiator(Widget w, XtPointer client_data, - XmDragStartCallbackStruct* cbstruct) { - Widget drag_initiator = (Widget)client_data; - /* - * Fix for BugTraq ID 4407057. - * Enable the drag operation only if it is registered on the specific - * widget. We use this check to disable Motif default drag support. - */ - if (drag_initiator != cbstruct->widget) { - cbstruct->doit = False; - } -} - -void -awt_motif_enableSingleDragInitiator(Widget w) { - XtAddCallback(XmGetXmDisplay(XtDisplay(w)), - XmNdragStartCallback, (XtCallbackProc)CheckDragInitiator, - (XtPointer)w); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_p.h --- a/jdk/src/solaris/native/sun/awt/awt_p.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/awt_p.h Wed Jul 05 16:41:30 2017 +0200 @@ -79,7 +79,7 @@ #ifndef XAWT #include "GLXGraphicsConfig.h" -#include +//#include #endif #ifndef HEADLESS diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/awt_xembed.c --- a/jdk/src/solaris/native/sun/awt/awt_xembed.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,430 +0,0 @@ -/* - * Copyright 2003-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" - -#include -#include -#include -#include - -/* JNI headers */ -#include "java_awt_Frame.h" /* for frame state constants */ - -#include "awt_wm.h" -#include "awt_util.h" /* for X11 error handling macros */ -#include "awt_xembed.h" -#include "awt_MToolkit.h" -#include "awt_DataTransferer.h" /* for DECLARE_XXX macros */ - -#ifdef DOTRACE -#define MTRACE(param) fprintf(myerr, param) -#define MTRACEP1(format, p1) fprintf(myerr, format, p1) -#define MTRACEP2(format, p1, p2) fprintf(myerr, format, p1, p2) -#define MTRACEP3(format, p1, p2, p3) fprintf(myerr, format, p1, p2, p3) -#define MTRACEP4(format, p1, p2, p3, p4) fprintf(myerr, format, p1, p2, p3, p4) -#define MTRACEP5(format, p1, p2, p3, p4, p5) fprintf(myerr, format, p1, p2, p3, p4, p5) -#define MTRACEP6(format, p1, p2, p3, p4, p5, p6) fprintf(myerr, format, p1, p2, p3, p4, p5, p6) -#define MTRACEP7(format, p1, p2, p3, p4, p5, p6, p7) fprintf(myerr, format, p1, p2, p3, p4, p5, p6, p7) -#else -#define MTRACE(param) -#define MTRACEP1(format, p1) -#define MTRACEP2(format, p1, p2) -#define MTRACEP3(format, p1, p2, p3) -#define MTRACEP4(format, p1, p2, p3, p4) -#define MTRACEP5(format, p1, p2, p3, p4, p5) -#define MTRACEP6(format, p1, p2, p3, p4, p5, p6) -#define MTRACEP7(format, p1, p2, p3, p4, p5, p6, p7) -#endif - -#ifdef DOTRACE -static FILE* myerr; -#endif - -static Window getParent(Window window); -static Window getEmbedder(Window client); -static jmethodID handleFocusInMID; - -const char * error_msg = "UNKNOWN XEMBED MESSAGE"; - -const char * xembed_strs[] = { - "EMBEDDED_NOTIFY", - "WINDOW_ACTIVATE", - "WINDOW_DEACTIVATE", - "REQUEST_FOCUS", - "FOCUS_IN", - "FOCUS_OUT", - "FOCUS_NEXT", - "FOCUS_PREV" , - "GRAB_KEY", - "UNGRAB_KEY", - "MODALITY_ON" , - "MODALITY_OFF", - "REGISTER_ACCELERATOR", - "UNREGISTER_ACCELERATOR", - "ACTIVATE_ACCELERATOR" -}; - -const char * -msg_to_str(int msg) { - if (msg >= 0 && msg <= XEMBED_LAST_MSG) { - return xembed_strs[msg]; - } else { - return error_msg; - } -} - -DECLARE_JAVA_CLASS(MEmbeddedFramePeerClass, "sun/awt/motif/MEmbeddedFramePeer"); - -typedef struct _xembed_info { - CARD32 version; - CARD32 flags; -} xembed_info; - -typedef struct _xembed_data { - struct FrameData * wdata; // pointer to EmbeddedFrame wdata - Window client; // pointer to plugin intermediate widget, XEmbed client - Boolean active; // whether xembed is active for this client - Boolean applicationActive; // whether the embedding application is active - Window embedder; // Window ID of the embedder - struct _xembed_data * next; -} xembed_data, * pxembed_data; - -static pxembed_data xembed_list = NULL; - -static pxembed_data -getData(Window client) { - pxembed_data temp = xembed_list; - while (temp != NULL) { - if (temp->client == client) { - return temp; - } - temp = temp->next; - } - return NULL; -} - -static pxembed_data -getDataByFrame(struct FrameData* wdata) { - pxembed_data temp = xembed_list; - while (temp != NULL) { - if (temp->wdata == wdata) { - return temp; - } - temp = temp->next; - } - return NULL; -} - -static pxembed_data -addData(Window client) { - xembed_data * data = malloc(sizeof(xembed_data)); - memset(data, 0, sizeof(xembed_data)); - data->client = client; - data->next = xembed_list; - xembed_list = data; - return data; -} - -static void -removeData(Window client) { - pxembed_data * temp = &xembed_list; - while (*temp != NULL) { - if ((*temp)->client == client) { - xembed_data * data = *temp; - *temp = (*temp)->next; - free(data); - return; - } - temp = &(*temp)->next; - } -} - -static Atom XA_XEmbedInfo; -static Atom XA_XEmbed; - -void -init_xembed() { - XA_XEmbedInfo = XInternAtom(awt_display, "_XEMBED_INFO", False); - XA_XEmbed = XInternAtom(awt_display, "_XEMBED", False); -#ifdef DOTRACE - myerr = fopen("xembedclient.log","w"); -#endif -} - -static Time -getCurrentServerTime() { - return awt_util_getCurrentServerTime(); -} - - -void -sendMessageHelper(Window window, int message, long detail, - long data1, long data2) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - XEvent ev; - XClientMessageEvent * req = (XClientMessageEvent*)&ev; - memset(&ev, 0, sizeof(ev)); - - req->type = ClientMessage; - req->window = window; - req->message_type = XA_XEmbed; - req->format = 32; - req->data.l[0] = getCurrentServerTime(); - req->data.l[1] = message; - req->data.l[2] = detail; - req->data.l[3] = data1; - req->data.l[4] = data2; - AWT_LOCK(); - XSendEvent(awt_display, window, False, NoEventMask, &ev); - AWT_UNLOCK(); -} - -void -sendMessage(Window window, int message) { - sendMessageHelper(window, message, 0, 0, 0); -} - - -static Window -getParent(Window window) { - Window root, parent = None, *children = NULL; - unsigned int count; - XQueryTree(awt_display, window, &root, &parent, &children, &count); - if (children != NULL) { - XFree(children); - } - return parent; -} - -static Window -getEmbedder(Window client) { - return getParent(client); -} - - -static void -handleFocusIn(struct FrameData* wdata, int detail) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - struct WidgetInfo* winfo; - MTRACE("HandleFocusIn\n"); - winfo = findWidgetInfo(wdata->winData.comp.widget); - if (winfo != NULL) { - jobject peer = winfo->peer; - if (handleFocusInMID == NULL) { - jclass clazz = (*env)->FindClass(env, "sun/awt/motif/MEmbeddedFramePeer"); - DASSERT(clazz != NULL); - handleFocusInMID = (*env)->GetMethodID(env, clazz, "handleFocusIn", "(I)V"); - DASSERT(handleFocusInMID != NULL); - if (clazz != NULL) { - (*env)->DeleteLocalRef(env, clazz); - } - } - if (handleFocusInMID != NULL) { - (*env)->CallVoidMethod(env, peer, handleFocusInMID, (jint)detail); - } - } -} - -static void -genWindowFocus(struct FrameData *wdata, Boolean gain) { - XEvent ev; - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - memset(&ev, 0, sizeof(ev)); - - ev.type = (gain?FocusIn:FocusOut); - ev.xany.send_event = True; - ev.xany.display = awt_display; - ev.xfocus.mode = NotifyNormal; - ev.xfocus.detail = NotifyNonlinear; - ev.xfocus.window = XtWindow(wdata->winData.shell); - awt_put_back_event(env, &ev); -} - -extern Boolean skipNextFocusIn; - -static void -callNotifyStarted(JNIEnv* env, jobject peer) { - DECLARE_VOID_JAVA_METHOD(notifyStartedMID, MEmbeddedFramePeerClass, - "notifyStarted", "()V"); - - (*env)->CallVoidMethod(env, peer, notifyStartedMID); -} - -void -xembed_eventHandler(XEvent *event) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - struct FrameData *wdata; - xembed_data * data; - - data = getData(event->xany.window); - if (data == NULL) { - MTRACEP1("No XEMBED client registered for this window %x\n", event->xany.window); - if (event->xany.type == ClientMessage) { - MTRACEP7("Unprocessed handleClientMessage: type=%d 0=%ld 1=%ld(%s) 2=%ld 3=%ld 4=%ld\n", - event->xclient.message_type, event->xclient.data.l[0], - event->xclient.data.l[1], msg_to_str(event->xclient.data.l[1]), - event->xclient.data.l[2], - event->xclient.data.l[3], event->xclient.data.l[4]); - } - return; - } - - wdata = data->wdata; - - if (event->xany.type == ClientMessage) { - MTRACEP6("handleClientMessage: type=%d 0=%ld 1=%ld 2=%ld 3=%ld 4=%ld\n", - event->xclient.message_type, event->xclient.data.l[0], - event->xclient.data.l[1], event->xclient.data.l[2], - event->xclient.data.l[3], event->xclient.data.l[4]); - // Probably a message from embedder - if (event->xclient.message_type == XA_XEmbed) { - // XEmbed message, data[1] contains message - switch ((int)event->xclient.data.l[1]) { - case XEMBED_EMBEDDED_NOTIFY: - MTRACE("EMBEDDED_NOTIFY\n"); - data->active = True; - data->embedder = getEmbedder(data->client); - // If Frame has not been reparented already we should "reparent" - // it manually - if (!(wdata->reparented)) { - wdata->reparented = True; - // in XAWT we also update WM_NORMAL_HINTS here. - } - { - struct WidgetInfo* winfo = - findWidgetInfo(wdata->winData.comp.widget); - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_4); - if (winfo != NULL) { - callNotifyStarted(env, winfo->peer); - } - } - MTRACE("Embedded notify in client\n"); - break; - case XEMBED_WINDOW_DEACTIVATE: - MTRACE("DEACTIVATE\n"); - data->applicationActive = False; - break; - case XEMBED_WINDOW_ACTIVATE: - MTRACE("ACTIVATE\n"); - data->applicationActive = True; - break; - case XEMBED_FOCUS_IN: - MTRACE("FOCUS IN\n"); - skipNextFocusIn = False; - handleFocusIn(wdata, (int)(event->xclient.data.l[2])); - genWindowFocus(wdata, True); - break; - case XEMBED_FOCUS_OUT: - MTRACE("FOCUS OUT\n"); - genWindowFocus(wdata, False); - break; - } - } - } else if (event->xany.type == ReparentNotify) { - data->embedder = event->xreparent.parent; - } -} - -void -notify_ready(Window client) { - sendMessage(getEmbedder(client), _SUN_XEMBED_START); -} - -void -install_xembed(Widget client_widget, struct FrameData* wdata) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - xembed_info info = {XEMBED_VERSION, XEMBED_MAPPED}; - Window client = XtWindow(client_widget); - xembed_data * data; - - AWT_LOCK(); - data = addData(client); - data->wdata = wdata; - - // Install event handler for messages from embedder - XSelectInput(awt_display, client, StructureNotifyMask); - - // Install XEMBED_INFO information - XChangeProperty(awt_display, client, XA_XEmbedInfo, - XA_XEmbedInfo, 32, PropModeReplace, - (unsigned char*)&info, 2); - MTRACE("Installing xembed\n"); - - notify_ready(client); - - AWT_UNLOCK(); -} - -void -deinstall_xembed(struct FrameData* wdata) { - xembed_data * data = getDataByFrame(wdata); - - if (data != NULL) { - removeData(data->client); - } -} - -void -requestXEmbedFocus(struct FrameData * wdata) { - xembed_data * data = getDataByFrame(wdata); - - if (data != NULL) { - if (data->active && data->applicationActive) { - sendMessage(data->embedder, XEMBED_REQUEST_FOCUS); - } - } -} - -Boolean -isXEmbedActive(struct FrameData * wdata) { - xembed_data * data = getDataByFrame(wdata); - return (data != NULL && data->active); -} - -Boolean -isXEmbedActiveByWindow(Window client) { - xembed_data * data = getData(client); - return (data != NULL && data->active); -} - - -Boolean -isXEmbedApplicationActive(struct FrameData * wdata) { - xembed_data * data = getDataByFrame(wdata); - return (data != NULL && data->applicationActive); -} - -void -xembed_traverse_out(struct FrameData * wdata, jboolean direction) { - xembed_data * data = getDataByFrame(wdata); - sendMessage(data->embedder, (direction == JNI_TRUE)?XEMBED_FOCUS_NEXT:XEMBED_FOCUS_PREV); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/canvas.c --- a/jdk/src/solaris/native/sun/awt/canvas.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3227 +0,0 @@ -/* - * Copyright 1995-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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include /* timeval */ - -#define XK_KATAKANA -#include /* standard X keysyms */ -#include /* DEC vendor-specific */ -#include /* Sun vendor-specific */ -#include /* Apollo (HP) vendor-specific */ -/* - * #include HP vendor-specific - * I checked HPkeysym.h into the workspace because it ships - * with X11R6.4.2 (and later) but not with X11R6.4.1. - * So, it ought to ship with Solaris 9, but not Solaris 8. - * Same deal for Linux - newer versions of XFree have it. - * - * Note: this is mainly done for the hp keysyms; it does NOT - * give us the osf keysyms that are also defined in HPkeysym.h. - * This is because we are already getting /Xm/VirtKeys.h - * from awt_p.h <- /Xm/Xm.h <- /Xm/VirtKeys.h, and VirtKeys.h - * #defines _OSF_Keysyms before we get here. We are - * missing a couple of osf keysyms because of this, - * so I have #defined them below. - */ -#include "HPkeysym.h" /* HP vendor-specific */ - -#include -#include -#include "java_awt_Frame.h" -#include "java_awt_Component.h" -#include "java_awt_AWTEvent.h" -#include "java_awt_event_KeyEvent.h" -#include "java_awt_event_FocusEvent.h" -#include "java_awt_event_MouseEvent.h" -#include "java_awt_event_MouseWheelEvent.h" -#include "java_awt_event_InputEvent.h" -#include "java_awt_event_WindowEvent.h" -#include "sun_awt_motif_MComponentPeer.h" -#include "color.h" -#include "canvas.h" -#include "awt_Cursor.h" -#include "VDrawingArea.h" -#include "XDrawingArea.h" -#include "awt_Component.h" -#include "awt_AWTEvent.h" -#include "awt_Event.h" -#include "awt_KeyboardFocusManager.h" -#include "awt_MToolkit.h" -#include "awt_TopLevel.h" -#include "awt_util.h" - -#include -#include -#include -#include - -#ifdef NDEBUG /* NDEBUG overrides DEBUG */ -#undef DEBUG -#endif - -/* - * Two osf keys are not defined in standard keysym.h, - * /Xm/VirtKeys.h, or HPkeysym.h, so I added them below. - * I found them in /usr/openwin/lib/X11/XKeysymDB - */ -#ifndef osfXK_Prior -#define osfXK_Prior 0x1004FF55 -#endif -#ifndef osfXK_Next -#define osfXK_Next 0x1004FF56 -#endif -/* - * osfXK_Escape is defined in HPkeysym.h, but not in - * /Xm/VirtKeys.h, so I added it below. It is also in - * /usr/openwin/lib/X11/XKeysymDB - * Note: it is in /Xm/VirtKeys.h in the AWT motif workspace, - * but not in /usr/local/Motif/include/Xm/VirtKeys.h - * on the Solaris 7, 8, or 9 machines I tried. - */ -#ifndef osfXK_Escape -#define osfXK_Escape 0x1004FF1B -#endif - -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct AWTEventIDs awtEventIDs; -extern struct KeyEventIDs keyEventIDs; -extern struct InputEventIDs inputEventIDs; -extern struct ComponentIDs componentIDs; -extern struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; - -#ifdef DEBUG -static Boolean debugKeys = False; -#endif - -jint awt_multiclick_smudge = 4; - -extern Widget drag_source; - -Widget prevWidget = NULL; /* for bug fix 4017222 */ - -FocusListElt *focusList = NULL, *focusListEnd = NULL; - -jweak forGained = NULL; - -extern Boolean scrollBugWorkAround; -extern jobject currentX11InputMethodInstance; -extern Window currentFocusWindow; -extern Boolean awt_x11inputmethod_lookupString(XKeyPressedEvent *, KeySym *); -Boolean awt_UseType4Patch = True; -Boolean awt_ServerDetected = False; -Boolean awt_IsXsun = False; -Boolean awt_UseXKB = False; - -void awt_post_java_key_event(XtPointer client_data, jint id, - XEvent *xevent, Time when, jint keycode, - jchar keychar, jint modifiers, - jint keyLocation, XEvent *anEvent); -void awt_post_java_focus_event(XtPointer client_data, jint id, jobject cause, - XEvent *event); -void awt_post_java_mouse_event(XtPointer client_data, jint id, - XEvent *event, Time when, jint modifiers, - jint x, jint y, - jint xAbs, jint yAbs, - jint clickcount, Boolean popuptrigger, - jint wheelAmt, jint button); - -typedef struct KEYMAP_ENTRY { - jint awtKey; - KeySym x11Key; - Boolean mapsToUnicodeChar; - jint keyLocation; -} KeymapEntry; - -/* NB: XK_R? keysyms are for Type 4 keyboards. - * The corresponding XK_F? keysyms are for Type 5 - * - * Note: this table must be kept in sorted order, since it is traversed - * according to both Java keycode and X keysym. There are a number of - * keycodes that map to more than one corresponding keysym, and we need - * to choose the right one. Unfortunately, there are some keysyms that - * can map to more than one keycode, depending on what kind of keyboard - * is in use (e.g. F11 and F12). - */ - -KeymapEntry keymapTable[] = -{ - {java_awt_event_KeyEvent_VK_A, XK_a, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_B, XK_b, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_C, XK_c, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_D, XK_d, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_E, XK_e, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F, XK_f, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_G, XK_g, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_H, XK_h, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_I, XK_i, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_J, XK_j, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_K, XK_k, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_L, XK_l, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_M, XK_m, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_N, XK_n, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_O, XK_o, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_P, XK_p, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_Q, XK_q, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_R, XK_r, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_S, XK_s, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_T, XK_t, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_U, XK_u, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_V, XK_v, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_W, XK_w, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_X, XK_x, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_Y, XK_y, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_Z, XK_z, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* TTY Function keys */ - {java_awt_event_KeyEvent_VK_BACK_SPACE, XK_BackSpace, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_TAB, XK_Tab, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CLEAR, XK_Clear, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ENTER, XK_Return, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ENTER, XK_Linefeed, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAUSE, XK_Pause, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAUSE, XK_F21, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAUSE, XK_R1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_Scroll_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_F23, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_R3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ESCAPE, XK_Escape, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Other vendor-specific versions of TTY Function keys */ - {java_awt_event_KeyEvent_VK_BACK_SPACE, osfXK_BackSpace, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CLEAR, osfXK_Clear, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ESCAPE, osfXK_Escape, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Modifier keys */ - {java_awt_event_KeyEvent_VK_SHIFT, XK_Shift_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, - {java_awt_event_KeyEvent_VK_SHIFT, XK_Shift_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, - {java_awt_event_KeyEvent_VK_CONTROL, XK_Control_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, - {java_awt_event_KeyEvent_VK_CONTROL, XK_Control_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, - {java_awt_event_KeyEvent_VK_ALT, XK_Alt_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, - {java_awt_event_KeyEvent_VK_ALT, XK_Alt_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, - {java_awt_event_KeyEvent_VK_META, XK_Meta_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, - {java_awt_event_KeyEvent_VK_META, XK_Meta_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, - {java_awt_event_KeyEvent_VK_CAPS_LOCK, XK_Caps_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Misc Functions */ - {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_Print, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_F22, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_R2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CANCEL, XK_Cancel, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_HELP, XK_Help, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_NUM_LOCK, XK_Num_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - - /* Other vendor-specific versions of Misc Functions */ - {java_awt_event_KeyEvent_VK_CANCEL, osfXK_Cancel, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_HELP, osfXK_Help, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Rectangular Navigation Block */ - {java_awt_event_KeyEvent_VK_HOME, XK_Home, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_HOME, XK_R7, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, XK_Page_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, XK_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, XK_R9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_Page_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_R15, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_END, XK_End, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_END, XK_R13, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_INSERT, XK_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DELETE, XK_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Keypad equivalents of Rectangular Navigation Block */ - {java_awt_event_KeyEvent_VK_HOME, XK_KP_Home, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, XK_KP_Page_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, XK_KP_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_KP_Page_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_KP_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_END, XK_KP_End, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_INSERT, XK_KP_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_DELETE, XK_KP_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - - /* Other vendor-specific Rectangular Navigation Block */ - {java_awt_event_KeyEvent_VK_PAGE_UP, osfXK_PageUp, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_UP, osfXK_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, osfXK_PageDown, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PAGE_DOWN, osfXK_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_END, osfXK_EndLine, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_INSERT, osfXK_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DELETE, osfXK_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Triangular Navigation Block */ - {java_awt_event_KeyEvent_VK_LEFT, XK_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UP, XK_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_RIGHT, XK_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DOWN, XK_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Keypad equivalents of Triangular Navigation Block */ - {java_awt_event_KeyEvent_VK_KP_LEFT, XK_KP_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_KP_UP, XK_KP_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_KP_RIGHT, XK_KP_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_KP_DOWN, XK_KP_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - - /* Other vendor-specific Triangular Navigation Block */ - {java_awt_event_KeyEvent_VK_LEFT, osfXK_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UP, osfXK_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_RIGHT, osfXK_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DOWN, osfXK_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Remaining Cursor control & motion */ - {java_awt_event_KeyEvent_VK_BEGIN, XK_Begin, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_BEGIN, XK_KP_Begin, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - - {java_awt_event_KeyEvent_VK_0, XK_0, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_1, XK_1, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_2, XK_2, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_3, XK_3, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_4, XK_4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_5, XK_5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_6, XK_6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_7, XK_7, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_8, XK_8, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_9, XK_9, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_SPACE, XK_space, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_EXCLAMATION_MARK, XK_exclam, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_QUOTEDBL, XK_quotedbl, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_NUMBER_SIGN, XK_numbersign, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DOLLAR, XK_dollar, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_AMPERSAND, XK_ampersand, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_QUOTE, XK_apostrophe, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS, XK_parenleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS, XK_parenright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ASTERISK, XK_asterisk, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PLUS, XK_plus, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_COMMA, XK_comma, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_MINUS, XK_minus, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PERIOD, XK_period, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_SLASH, XK_slash, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_COLON, XK_colon, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_SEMICOLON, XK_semicolon, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_LESS, XK_less, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_EQUALS, XK_equal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_GREATER, XK_greater, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_AT, XK_at, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_OPEN_BRACKET, XK_bracketleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_BACK_SLASH, XK_backslash, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CLOSE_BRACKET, XK_bracketright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CIRCUMFLEX, XK_asciicircum, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UNDERSCORE, XK_underscore, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_BACK_QUOTE, XK_grave, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_BRACELEFT, XK_braceleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_BRACERIGHT, XK_braceright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_INVERTED_EXCLAMATION_MARK, XK_exclamdown, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Remaining Numeric Keypad Keys */ - {java_awt_event_KeyEvent_VK_NUMPAD0, XK_KP_0, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD1, XK_KP_1, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD2, XK_KP_2, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD3, XK_KP_3, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD4, XK_KP_4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD5, XK_KP_5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD6, XK_KP_6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD7, XK_KP_7, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD8, XK_KP_8, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_NUMPAD9, XK_KP_9, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_SPACE, XK_KP_Space, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_TAB, XK_KP_Tab, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_ENTER, XK_KP_Enter, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_EQUALS, XK_KP_Equal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_EQUALS, XK_R4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_MULTIPLY, XK_KP_Multiply, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_MULTIPLY, XK_F26, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_MULTIPLY, XK_R6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_ADD, XK_KP_Add, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_SEPARATOR, XK_KP_Separator, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_SUBTRACT, XK_KP_Subtract, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_SUBTRACT, XK_F24, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_DECIMAL, XK_KP_Decimal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_DIVIDE, XK_KP_Divide, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_DIVIDE, XK_F25, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - {java_awt_event_KeyEvent_VK_DIVIDE, XK_R5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, - - /* Function Keys */ - {java_awt_event_KeyEvent_VK_F1, XK_F1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F2, XK_F2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F3, XK_F3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F4, XK_F4, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F5, XK_F5, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F6, XK_F6, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F7, XK_F7, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F8, XK_F8, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F9, XK_F9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F10, XK_F10, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F11, XK_F11, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F12, XK_F12, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Sun vendor-specific version of F11 and F12 */ - {java_awt_event_KeyEvent_VK_F11, SunXK_F36, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_F12, SunXK_F37, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* X11 keysym names for input method related keys don't always - * match keytop engravings or Java virtual key names, so here we - * only map constants that we've found on real keyboards. - */ - /* Type 5c Japanese keyboard: kakutei */ - {java_awt_event_KeyEvent_VK_ACCEPT, XK_Execute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - /* Type 5c Japanese keyboard: henkan */ - {java_awt_event_KeyEvent_VK_CONVERT, XK_Kanji, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - /* Type 5c Japanese keyboard: nihongo */ - {java_awt_event_KeyEvent_VK_INPUT_METHOD_ON_OFF, XK_Henkan_Mode, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - /* VK_KANA_LOCK is handled separately because it generates the - * same keysym as ALT_GRAPH in spite of its different behavior. - */ - - {java_awt_event_KeyEvent_VK_COMPOSE, XK_Multi_key, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_ALT_GRAPH, XK_Mode_switch, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Editing block */ - {java_awt_event_KeyEvent_VK_AGAIN, XK_Redo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_AGAIN, XK_L2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UNDO, XK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UNDO, XK_L4, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_COPY, XK_L6, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PASTE, XK_L8, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CUT, XK_L10, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_FIND, XK_Find, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_FIND, XK_L9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PROPS, XK_L3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_STOP, XK_L1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Sun vendor-specific versions for editing block */ - {java_awt_event_KeyEvent_VK_AGAIN, SunXK_Again, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UNDO, SunXK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_COPY, SunXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PASTE, SunXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CUT, SunXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_FIND, SunXK_Find, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PROPS, SunXK_Props, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_STOP, SunXK_Stop, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Apollo (HP) vendor-specific versions for editing block */ - {java_awt_event_KeyEvent_VK_COPY, apXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CUT, apXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PASTE, apXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Other vendor-specific versions for editing block */ - {java_awt_event_KeyEvent_VK_COPY, osfXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_CUT, osfXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_PASTE, osfXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_UNDO, osfXK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Dead key mappings (for European keyboards) */ - {java_awt_event_KeyEvent_VK_DEAD_GRAVE, XK_dead_grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_ACUTE, XK_dead_acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, XK_dead_circumflex, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_TILDE, XK_dead_tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_MACRON, XK_dead_macron, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_BREVE, XK_dead_breve, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_ABOVEDOT, XK_dead_abovedot, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, XK_dead_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_ABOVERING, XK_dead_abovering, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_DOUBLEACUTE, XK_dead_doubleacute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CARON, XK_dead_caron, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, XK_dead_cedilla, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_OGONEK, XK_dead_ogonek, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_IOTA, XK_dead_iota, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND, XK_dead_voiced_sound, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND, XK_dead_semivoiced_sound, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Sun vendor-specific dead key mappings (for European keyboards) */ - {java_awt_event_KeyEvent_VK_DEAD_GRAVE, SunXK_FA_Grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, SunXK_FA_Circum, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_TILDE, SunXK_FA_Tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_ACUTE, SunXK_FA_Acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, SunXK_FA_Diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, SunXK_FA_Cedilla, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* DEC vendor-specific dead key mappings (for European keyboards) */ - {java_awt_event_KeyEvent_VK_DEAD_ABOVERING, DXK_ring_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, DXK_circumflex_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, DXK_cedilla_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_ACUTE, DXK_acute_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_GRAVE, DXK_grave_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_TILDE, DXK_tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, DXK_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - /* Other vendor-specific dead key mappings (for European keyboards) */ - {java_awt_event_KeyEvent_VK_DEAD_ACUTE, hpXK_mute_acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_GRAVE, hpXK_mute_grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, hpXK_mute_asciicircum, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, hpXK_mute_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - {java_awt_event_KeyEvent_VK_DEAD_TILDE, hpXK_mute_asciitilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, - - {java_awt_event_KeyEvent_VK_UNDEFINED, NoSymbol, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN} -}; - -static Boolean -keyboardHasKanaLockKey() -{ - static Boolean haveResult = FALSE; - static Boolean result = FALSE; - - int32_t minKeyCode, maxKeyCode, keySymsPerKeyCode; - KeySym *keySyms, *keySymsStart, keySym; - int32_t i; - int32_t kanaCount = 0; - - // Solaris doesn't let you swap keyboards without rebooting, - // so there's no need to check for the kana lock key more than once. - if (haveResult) { - return result; - } - - // There's no direct way to determine whether the keyboard has - // a kana lock key. From available keyboard mapping tables, it looks - // like only keyboards with the kana lock key can produce keysyms - // for kana characters. So, as an indirect test, we check for those. - - XDisplayKeycodes(awt_display, &minKeyCode, &maxKeyCode); - keySyms = XGetKeyboardMapping(awt_display, minKeyCode, maxKeyCode - minKeyCode + 1, &keySymsPerKeyCode); - keySymsStart = keySyms; - for (i = 0; i < (maxKeyCode - minKeyCode + 1) * keySymsPerKeyCode; i++) { - keySym = *keySyms++; - if ((keySym & 0xff00) == 0x0400) { - kanaCount++; - } - } - XFree(keySymsStart); - - // use a (somewhat arbitrary) minimum so we don't get confused by a stray function key - result = kanaCount > 10; - haveResult = TRUE; - return result; -} - -void -keysymToAWTKeyCode(KeySym x11Key, jint *keycode, Boolean *mapsToUnicodeChar, - jint *keyLocation) -{ - int32_t i; - - // Solaris uses XK_Mode_switch for both the non-locking AltGraph - // and the locking Kana key, but we want to keep them separate for - // KeyEvent. - if (x11Key == XK_Mode_switch && keyboardHasKanaLockKey()) { - *keycode = java_awt_event_KeyEvent_VK_KANA_LOCK; - *mapsToUnicodeChar = FALSE; - *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; - return; - } - - for (i = 0; - keymapTable[i].awtKey != java_awt_event_KeyEvent_VK_UNDEFINED; - i++) { - if (keymapTable[i].x11Key == x11Key) { - *keycode = keymapTable[i].awtKey; - *mapsToUnicodeChar = keymapTable[i].mapsToUnicodeChar; - *keyLocation = keymapTable[i].keyLocation; - return; - } - } - - *keycode = java_awt_event_KeyEvent_VK_UNDEFINED; - *mapsToUnicodeChar = FALSE; - *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; - - DTRACE_PRINTLN1("keysymToAWTKeyCode: no key mapping found: keysym = %x", x11Key); -} - -KeySym -awt_getX11KeySym(jint awtKey) -{ - int32_t i; - - if (awtKey == java_awt_event_KeyEvent_VK_KANA_LOCK && keyboardHasKanaLockKey()) { - return XK_Mode_switch; - } - - for (i = 0; keymapTable[i].awtKey != 0; i++) { - if (keymapTable[i].awtKey == awtKey) { - return keymapTable[i].x11Key; - } - } - - DTRACE_PRINTLN1("awt_getX11KeySym: no key mapping found: awtKey = %x", awtKey); - return NoSymbol; -} - - -typedef struct COLLAPSE_INFO { - Window win; - DamageRect *r; -} CollapseInfo; - -static void -expandDamageRect(DamageRect * drect, XEvent * xev, Boolean debug, char *str) -{ - int32_t x1 = xev->xexpose.x; - int32_t y1 = xev->xexpose.y; - int32_t x2 = x1 + xev->xexpose.width; - int32_t y2 = y1 + xev->xexpose.height; - - /* - if (debug) { - printf(" %s: collapsing (%d,%d %dx%d) into (%d,%d %dx%d) ->>", - str, x1, y1, xev->xexpose.width, xev->xexpose.height, - drect->x1, drect->y1, drect->x2 - drect->x1, drect->y2 - drect->y1); - } - */ - - drect->x1 = MIN(x1, drect->x1); - drect->y1 = MIN(y1, drect->y1); - drect->x2 = MAX(x2, drect->x2); - drect->y2 = MAX(y2, drect->y2); - - /* - if (debug) { - printf("(%d,%d %dx%d) %s\n", - drect->x1, drect->y1, drect->x2 - drect->x1, drect->y2 - drect->y1); - } - */ - -} - -static Bool -checkForExpose(Display * dpy, XEvent * evt, XPointer client_data) -{ - CollapseInfo *cinfo = (CollapseInfo *) client_data; - - if ((evt->type == Expose && evt->xexpose.window == cinfo->win && - INTERSECTS(cinfo->r->x1, cinfo->r->x2, cinfo->r->y1, cinfo->r->y2, - evt->xexpose.x, - evt->xexpose.x + evt->xexpose.width, - evt->xexpose.y, - evt->xexpose.y + evt->xexpose.height)) || - (evt->type == GraphicsExpose && evt->xgraphicsexpose.drawable == cinfo->win && - INTERSECTS(cinfo->r->x1, cinfo->r->x2, cinfo->r->y1, cinfo->r->y2, - evt->xgraphicsexpose.x, - evt->xgraphicsexpose.x + evt->xgraphicsexpose.width, - evt->xgraphicsexpose.y, - evt->xgraphicsexpose.y + evt->xgraphicsexpose.height))) { - - return True; - } - return False; -} - -/* - * javaObject is an MComponentPeer instance - */ -static void -HandleExposeEvent(Widget w, jobject javaObject, XEvent * event) -{ - jobject target; - jint wdth, hght; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - switch (event->type) { - case Expose: - case GraphicsExpose: - { - struct ComponentData *cdata; - Boolean debug = FALSE; - jint drawState; - - /* Set the draw state */ - drawState = (*env)->GetIntField(env, javaObject, - mComponentPeerIDs.drawState); - (*env)->SetIntField(env, javaObject, mComponentPeerIDs.drawState, - drawState | JAWT_LOCK_CLIP_CHANGED); - cdata = (struct ComponentData *) - JNU_GetLongFieldAsPtr(env, javaObject, mComponentPeerIDs.pData); - if (JNU_IsNull(env, javaObject) || (cdata == NULL)) { - return; - } - if (event->xexpose.send_event) { - if (cdata->repaintPending & RepaintPending_REPAINT) { - cdata->repaintPending &= ~RepaintPending_REPAINT; - - JNU_CallMethodByName(env, - NULL, - javaObject, - "handleRepaint", - "(IIII)V", - (jint) cdata->repaintRect.x1, - (jint) cdata->repaintRect.y1, - (jint) cdata->repaintRect.x2 - - cdata->repaintRect.x1, - (jint) cdata->repaintRect.y2 - - cdata->repaintRect.y1); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - return; - } - if ((cdata->repaintPending & RepaintPending_EXPOSE) == 0) { - cdata->exposeRect.x1 = event->xexpose.x; - cdata->exposeRect.y1 = event->xexpose.y; - cdata->exposeRect.x2 = cdata->exposeRect.x1 + event->xexpose.width; - cdata->exposeRect.y2 = cdata->exposeRect.y1 + event->xexpose.height; - cdata->repaintPending |= RepaintPending_EXPOSE; - } else { - expandDamageRect(&(cdata->exposeRect), event, debug, "1"); - } - - /* Only post Expose/Repaint if we know others arn't following - * directly in the queue. - */ - if (event->xexpose.count == 0) { - int32_t count = 0; - CollapseInfo cinfo; - - cinfo.win = XtWindow(w); - cinfo.r = &(cdata->exposeRect); - - /* Do a little more inspecting and collapse further if there - * are additional expose events pending on this window where - * the damage rects intersect with the current exposeRect. - */ - while (TRUE) { - XEvent xev; - - if (XCheckIfEvent(XtDisplay(w), &xev - ,checkForExpose, (XtPointer) & cinfo)) { - count = xev.xexpose.count; - expandDamageRect(&(cdata->exposeRect), &xev, debug, "2"); - - } else { - /* XCheckIfEvent Failed. */ - break; - } - } - - cdata->repaintPending &= ~RepaintPending_EXPOSE; - - /* Fix for bugtraq id 4262108. Paint events should not be - * delivered to components that have one of their - * dimensions equal to zero. - */ - - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - - target = (*env)->GetObjectField(env, javaObject, - mComponentPeerIDs.target); - wdth = (*env)->GetIntField(env, target, componentIDs.width); - hght = (*env)->GetIntField(env, target, componentIDs.height); - (*env)->DeleteLocalRef(env, target); - - if ( wdth != 0 && hght != 0) { - JNU_CallMethodByName(env, - NULL, - javaObject, - "handleExpose", - "(IIII)V", - (jint) cdata->exposeRect.x1, - (jint) cdata->exposeRect.y1, - (jint) cdata->exposeRect.x2 - - cdata->exposeRect.x1, - (jint) cdata->exposeRect.y2 - - cdata->exposeRect.y1); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - } - } - } - break; - - default: - jio_fprintf(stderr, "Got event %d in HandleExposeEvent!\n", event->type); - } -} - -/* We always store and return JNI GlobalRefs. */ -static jweak focusOwnerPeer = NULL; -static jweak focusedWindowPeer = NULL; - -/* - * This function should only be called under the - * protection of AWT_LOCK(). Otherwise, multithreaded access - * can corrupt the value of focusOwnerPeer variable. - * This function returns LocalRef, result should be deleted - * explicitly if called on a thread that never returns to - * Java. - */ -jobject -awt_canvas_getFocusOwnerPeer() { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject res; - AWT_LOCK(); - res = (*env)->NewLocalRef(env, focusOwnerPeer); - AWT_UNLOCK(); - return res; -} - -/* - * This function should only be called under the - * protection of AWT_LOCK(). Otherwise, multithreaded access - * can corrupt the value of focusedWindowPeer variable. - * This function returns LocalRef, result should be deleted - * explicitly if called on a thread that never returns to - * Java. - */ -jobject -awt_canvas_getFocusedWindowPeer() { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject res; - AWT_LOCK(); - res = (*env)->NewLocalRef(env, focusedWindowPeer); - AWT_UNLOCK(); - return res; -} - -/* - * Only call this function under AWT_LOCK(). Otherwise, multithreaded - * access can corrupt the value of focusOwnerPeer variable. - */ -void -awt_canvas_setFocusOwnerPeer(jobject peer) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - AWT_LOCK(); - if (focusOwnerPeer != NULL) { - (*env)->DeleteWeakGlobalRef(env, focusOwnerPeer); - } - focusOwnerPeer = (peer != NULL) - ? (*env)->NewWeakGlobalRef(env, peer) : NULL; - AWT_UNLOCK(); -} - -/* - * Only call this function under AWT_LOCK(). Otherwise, multithreaded - * access can corrupt the value of focusedWindowPeer variable. - */ -void -awt_canvas_setFocusedWindowPeer(jobject peer) { - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - AWT_LOCK(); - if (focusedWindowPeer != NULL) { - (*env)->DeleteWeakGlobalRef(env, focusedWindowPeer); - } - focusedWindowPeer = (peer != NULL) - ? (*env)->NewWeakGlobalRef(env, peer) : NULL; - AWT_UNLOCK(); -} - -void callFocusCallback(jobject focusPeer, int focus_type, jobject cause) { - awt_post_java_focus_event(focusPeer, - focus_type, - cause, - NULL); - awt_canvas_setFocusOwnerPeer(focusPeer); -} - - -void -handleFocusEvent(Widget w, - XFocusChangeEvent * fevent, - XtPointer client_data, - Boolean * cont, - Boolean passEvent, - jobject cause) -{ - if (fevent->type == FocusIn) { - if (fevent->mode == NotifyNormal && - fevent->detail != NotifyPointer && fevent->detail != NotifyVirtual) - { -#ifdef DEBUG_FOCUS - printf("window = %d, mode = %d, detail = %d\n", fevent->window, fevent->mode, fevent->detail); - printf("----posting java FOCUS GAINED on window %d, pass = %d\n", XtWindow(w), passEvent); -#endif - awt_post_java_focus_event(client_data, - java_awt_event_FocusEvent_FOCUS_GAINED, - cause, - NULL); - awt_canvas_setFocusOwnerPeer(client_data); - } - } else { - /* FocusOut */ - if (fevent->mode == NotifyNormal && - fevent->detail != NotifyPointer && fevent->detail != NotifyVirtual) - { -#ifdef DEBUG_FOCUS - printf("window = %d, mode = %d, detail = %d\n", fevent->window, fevent->mode, fevent->detail); - printf("----posting java FOCUS LOST on window %d, pass = %d, temp = %d\n", XtWindow(w), passEvent, temp); -#endif - awt_post_java_focus_event(client_data, - java_awt_event_FocusEvent_FOCUS_LOST, - cause, - NULL); - awt_canvas_setFocusOwnerPeer(NULL); - } - } - *cont = TRUE; -} - -void callFocusHandler(Widget w, int eventType, jobject cause) { - jobject peer = NULL; - XFocusChangeEvent event; - Boolean cont; - JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2); - - if (w == NULL) { - return; - } - - peer = findPeer(&w); - if (peer == NULL) { - w = findTopLevelByShell(w); - if (w != NULL) { - peer = findPeer(&w); - } - } - if (peer == NULL) { - return; - } - memset(&event, 0, sizeof(event)); - event.type = eventType; - event.mode = NotifyNormal; - event.detail = NotifyAncestor; - event.window = XtWindow(w); - cont = FALSE; - handleFocusEvent(w, &event, (XtPointer)peer, &cont, TRUE, cause); -} - -/** - * Copy XEvent to jbyteArray and save it in AWTEvent - */ -void -awt_copyXEventToAWTEvent(JNIEnv *env, XEvent * xev, jobject jevent) -{ - jbyteArray bdata; - if (xev != NULL) { - if ((*env)->EnsureLocalCapacity(env, 1) < 0) { - return; - } - bdata = (*env)->NewByteArray(env, sizeof(XEvent)); - if (bdata != NULL) { - (*env)->SetByteArrayRegion(env, bdata, 0, sizeof(XEvent), - (jbyte *)xev); - (*env)->SetObjectField(env, jevent, awtEventIDs.bdata, bdata); - (*env)->DeleteLocalRef(env, bdata); - } - } -} - -/* Returns new modifiers set like ???_DOWN_MASK for keyboard and mouse after the event. - * The modifiers on a Java key event reflect the state of the modifier keys - * immediately AFTER the key press or release. This usually doesn't require - * us to change the modifiers: the exception is when the key pressed or - * released is a modifier key. Since the state of an XEvent represents - * the modifiers BEFORE the event, we change the modifiers according to - * the button and keycode. - */ -jint -getModifiers(uint32_t state, jint button, jint keyCode) -{ - jint modifiers = 0; - - if (((state & ShiftMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_SHIFT)) - { - modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK; - } - if (((state & ControlMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_CONTROL)) - { - modifiers |= java_awt_event_InputEvent_CTRL_DOWN_MASK; - } - if (((state & awt_MetaMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_META)) - { - modifiers |= java_awt_event_InputEvent_META_DOWN_MASK; - } - if (((state & awt_AltMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_ALT)) - { - modifiers |= java_awt_event_InputEvent_ALT_DOWN_MASK; - } - if (((state & awt_ModeSwitchMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_ALT_GRAPH)) - { - modifiers |= java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK; - } - if (((state & Button1Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON1)) { - modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK; - } - if (((state & Button2Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON2)) { - modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK; - } - if (((state & Button3Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON3)) { - modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK; - } - return modifiers; -} - -/* Returns which mouse button has changed state - */ -jint -getButton(uint32_t button) -{ - switch (button) { - case Button1: - return java_awt_event_MouseEvent_BUTTON1; - case Button2: - return java_awt_event_MouseEvent_BUTTON2; - case Button3: - return java_awt_event_MouseEvent_BUTTON3; - } - return java_awt_event_MouseEvent_NOBUTTON; -} - - -/* This function changes the state of the native XEvent AFTER - * the corresponding Java event has been processed. The XEvent - * needs to be modified before it is dispatched to the native widget. - */ -void -awt_modify_KeyEvent(JNIEnv *env, XEvent *xevent, jobject jevent) -{ - jint keyCode; - jchar keyChar; - jint modifiers; - KeySym keysym = (KeySym) java_awt_event_KeyEvent_CHAR_UNDEFINED; - - if (xevent->type != KeyPress && xevent->type != KeyRelease) { - return; - } - - keyCode = (*env)->GetIntField(env, jevent, keyEventIDs.keyCode); - keyChar = (*env)->GetCharField(env, jevent, keyEventIDs.keyChar); - modifiers = (*env)->GetIntField(env, jevent, inputEventIDs.modifiers); - - switch (keyCode) { - case java_awt_event_KeyEvent_VK_MULTIPLY: - case java_awt_event_KeyEvent_VK_SUBTRACT: - case java_awt_event_KeyEvent_VK_DIVIDE: - /* Bugid 4103229: Change the X event so these three Numpad - * keys work with the NumLock off. For some reason, Motif - * widgets ignore the events produced by these three keys - * unless the NumLock is on. It also ignores them if some - * other modifiers are set. Turn off ALL modifiers, then - * turn NumLock mask on in the X event. - */ - xevent->xkey.state = awt_NumLockMask; - return; - case java_awt_event_KeyEvent_VK_ENTER: - case java_awt_event_KeyEvent_VK_BACK_SPACE: - case java_awt_event_KeyEvent_VK_TAB: - case java_awt_event_KeyEvent_VK_ESCAPE: - case java_awt_event_KeyEvent_VK_ADD: - case java_awt_event_KeyEvent_VK_DECIMAL: - case java_awt_event_KeyEvent_VK_NUMPAD0: - case java_awt_event_KeyEvent_VK_NUMPAD1: - case java_awt_event_KeyEvent_VK_NUMPAD2: - case java_awt_event_KeyEvent_VK_NUMPAD3: - case java_awt_event_KeyEvent_VK_NUMPAD4: - case java_awt_event_KeyEvent_VK_NUMPAD5: - case java_awt_event_KeyEvent_VK_NUMPAD6: - case java_awt_event_KeyEvent_VK_NUMPAD7: - case java_awt_event_KeyEvent_VK_NUMPAD8: - case java_awt_event_KeyEvent_VK_NUMPAD9: - keysym = awt_getX11KeySym(keyCode); - break; - case java_awt_event_KeyEvent_VK_DELETE: - /* For some reason XKeysymToKeycode returns incorrect value for - * Delete, so we don't want to modify the original event - */ - break; - default: - if (keyChar < (KeySym) 256) { - keysym = (KeySym) keyChar; - } else { - keysym = awt_getX11KeySym(keyCode); - } - break; - } - - if (keysym < (KeySym) 256) { - if (modifiers & java_awt_event_InputEvent_CTRL_MASK) { - switch (keysym + 64) { - case '[': - case ']': - case '\\': - case '_': - keysym += 64; - break; - default: - if (isalpha((int32_t)(keysym + 'a' - 1))) { - keysym += ('a' - 1); - } - break; - } - } - /* - * 0xff61 is Unicode value of first XK_kana_fullstop. - * We need X Keysym to Unicode map in post1.1 release - * to support more international keyboards. - */ - if (keysym >= (KeySym) 0xff61 && keysym <= (KeySym) 0xff9f) { - keysym = keysym - 0xff61 + XK_kana_fullstop; - } - xevent->xkey.keycode = XKeysymToKeycode(awt_display, keysym); - } - - if (keysym >= 'A' && keysym <= 'Z') { - xevent->xkey.state |= ShiftMask; - } - if (modifiers & java_awt_event_InputEvent_SHIFT_DOWN_MASK) { - xevent->xkey.state |= ShiftMask; - } - if (modifiers & java_awt_event_InputEvent_CTRL_DOWN_MASK) { - xevent->xkey.state |= ControlMask; - } - if (modifiers & java_awt_event_InputEvent_META_DOWN_MASK) { - xevent->xkey.state |= awt_MetaMask; - } - if (modifiers & java_awt_event_InputEvent_ALT_DOWN_MASK) { - xevent->xkey.state |= awt_AltMask; - } - if (modifiers & java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK) { - xevent->xkey.state |= awt_ModeSwitchMask; - } - if (modifiers & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) { - xevent->xkey.state |= Button1Mask; - } - if (modifiers & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) { - xevent->xkey.state |= Button2Mask; - } - if (modifiers & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) { - xevent->xkey.state |= Button3Mask; - } -} - - -/* Called from handleKeyEvent. The purpose of this function is - * to check for a list of vendor-specific keysyms, most of which - * have values greater than 0xFFFF. Most of these keys don't map - * to unicode characters, but some do. - * - * For keys that don't map to unicode characters, the keysym - * is irrelevant at this point. We set the keysym to zero - * to ensure that the switch statement immediately below - * this function call (in adjustKeySym) won't incorrectly act - * on them after the high bits are stripped off. - * - * For keys that do map to unicode characters, we change the keysym - * to the equivalent that is < 0xFFFF - */ -static void -handleVendorKeySyms(XEvent *event, KeySym *keysym) -{ - KeySym originalKeysym = *keysym; - - switch (*keysym) { - /* Apollo (HP) vendor-specific from */ - case apXK_Copy: - case apXK_Cut: - case apXK_Paste: - /* DEC vendor-specific from */ - case DXK_ring_accent: /* syn usldead_ring */ - case DXK_circumflex_accent: - case DXK_cedilla_accent: /* syn usldead_cedilla */ - case DXK_acute_accent: - case DXK_grave_accent: - case DXK_tilde: - case DXK_diaeresis: - /* Sun vendor-specific from */ - case SunXK_FA_Grave: - case SunXK_FA_Circum: - case SunXK_FA_Tilde: - case SunXK_FA_Acute: - case SunXK_FA_Diaeresis: - case SunXK_FA_Cedilla: - case SunXK_F36: /* Labeled F11 */ - case SunXK_F37: /* Labeled F12 */ - case SunXK_Props: - case SunXK_Copy: - case SunXK_Open: - case SunXK_Paste: - case SunXK_Cut: - /* Other vendor-specific from HPkeysym.h */ - case hpXK_mute_acute: /* syn usldead_acute */ - case hpXK_mute_grave: /* syn usldead_grave */ - case hpXK_mute_asciicircum: /* syn usldead_asciicircum */ - case hpXK_mute_diaeresis: /* syn usldead_diaeresis */ - case hpXK_mute_asciitilde: /* syn usldead_asciitilde */ - case osfXK_Copy: - case osfXK_Cut: - case osfXK_Paste: - case osfXK_PageUp: - case osfXK_PageDown: - case osfXK_EndLine: - case osfXK_Clear: - case osfXK_Left: - case osfXK_Up: - case osfXK_Right: - case osfXK_Down: - case osfXK_Prior: - case osfXK_Next: - case osfXK_Insert: - case osfXK_Undo: - case osfXK_Help: - *keysym = 0; - break; - /* - * The rest DO map to unicode characters, so translate them - */ - case osfXK_BackSpace: - *keysym = XK_BackSpace; - break; - case osfXK_Escape: - *keysym = XK_Escape; - break; - case osfXK_Cancel: - *keysym = XK_Cancel; - break; - case osfXK_Delete: - *keysym = XK_Delete; - break; - default: - break; - } - - if (originalKeysym != *keysym) { - DTRACE_PRINTLN2("In handleVendorKeySyms: originalKeysym=%x, keysym=%x", - originalKeysym, *keysym); - } -} - -/* Called from handleKeyEvent. - * The purpose of this function is to adjust the keysym and XEvent - * keycode for a key event. This is basically a conglomeration of - * bugfixes that require these adjustments. - */ -static void -adjustKeySym(XEvent *event, KeySym *keysym) -{ - KeySym originalKeysym = *keysym; - - /* We have seen bits set in the high two bytes on Linux, - * which prevents this switch statement from executing - * correctly. Strip off the high order bits. - */ - *keysym &= 0x0000FFFF; - - switch (*keysym) { - case XK_Return: - *keysym = XK_Linefeed; /* fall thru */ - case XK_BackSpace: - case XK_Tab: - case XK_Linefeed: - case XK_Escape: - case XK_Delete: - /* strip off highorder bits defined in keysymdef.h - * I think doing this converts them to values that - * we can cast to jchars and use as java keychars. - * If so, it's really a hack. - */ - *keysym &= 0x007F; - break; - case XK_Cancel: - *keysym = 0x0018; /* the unicode char for Cancel */ - break; - case XK_KP_Decimal: - *keysym = '.'; - break; - case XK_KP_Add: - *keysym = '+'; - break; - case XK_F24: /* NumLock off */ - case XK_KP_Subtract: /* NumLock on */ - *keysym = '-'; - break; - case XK_F25: /* NumLock off */ - case XK_KP_Divide: /* NumLock on */ - *keysym = '/'; - break; - case XK_F26: /* NumLock off */ - case XK_KP_Multiply: /* NumLock on */ - *keysym = '*'; - break; - case XK_KP_Equal: - *keysym = '='; - break; - case XK_KP_0: - *keysym = '0'; - break; - case XK_KP_1: - *keysym = '1'; - break; - case XK_KP_2: - *keysym = '2'; - break; - case XK_KP_3: - *keysym = '3'; - break; - case XK_KP_4: - *keysym = '4'; - break; - case XK_KP_5: - *keysym = '5'; - break; - case XK_KP_6: - *keysym = '6'; - break; - case XK_KP_7: - *keysym = '7'; - break; - case XK_KP_8: - *keysym = '8'; - break; - case XK_KP_9: - *keysym = '9'; - break; - case XK_KP_Left: /* Bug 4350175 */ - *keysym = XK_Left; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Up: - *keysym = XK_Up; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Right: - *keysym = XK_Right; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Down: - *keysym = XK_Down; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Home: - *keysym = XK_Home; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_End: - *keysym = XK_End; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Page_Up: - *keysym = XK_Page_Up; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Page_Down: - *keysym = XK_Page_Down; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Begin: - *keysym = XK_Begin; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Insert: - *keysym = XK_Insert; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - break; - case XK_KP_Delete: - *keysym = XK_Delete; - event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); - *keysym &= 0x007F; - break; - case XK_KP_Enter: - *keysym = XK_Linefeed; - event->xkey.keycode = XKeysymToKeycode(awt_display, XK_Return); - *keysym &= 0x007F; - break; - default: - break; - } - - if (originalKeysym != *keysym) { - DTRACE_PRINTLN2("In adjustKeySym: originalKeysym=%x, keysym=%x", - originalKeysym, *keysym); - } -} - -/* - * What a sniffer sez? - * Xsun and Xorg if NumLock is on do two thing different: - * keep Keypad key in different places of keysyms array and - * ignore/obey "ModLock is ShiftLock", so we should choose. - * People say, it's right to use behavior and not Vendor tags to decide. - * Maybe. But why these tags were invented, then? - * TODO: use behavior, not tags. Maybe. - */ -static Boolean -isXsunServer(XEvent *event) { - if( awt_ServerDetected ) return awt_IsXsun; - if( strncmp( ServerVendor( event->xkey.display ), "Sun Microsystems, Inc.", 32) ) { - awt_ServerDetected = True; - awt_IsXsun = False; - return False; - } - // Now, it's Sun. It still may be Xorg though, eg on Solaris 10, x86. - // Today (2005), VendorRelease of Xorg is a Big Number unlike Xsun. - if( VendorRelease( event->xkey.display ) > 10000 ) { - awt_ServerDetected = True; - awt_IsXsun = False; - return False; - } - awt_ServerDetected = True; - awt_IsXsun = True; - return True; -} -static Boolean -isKPevent(XEvent *event) -{ - /* - Xlib manual, ch 12.7 says, as a first rule for choice of keysym: - The numlock modifier is on and the second KeySym is a keypad KeySym. In this case, - if the Shift modifier is on, or if the Lock modifier is on and is interpreted as ShiftLock, - then the first KeySym is used, otherwise the second KeySym is used. - - However, Xsun server does ignore ShiftLock and always takes 3-rd element from an array. - - So, is it a keypad keysym? - */ - jint mods = getModifiers(event->xkey.state, 0, event->xkey.keycode); - Boolean bsun = isXsunServer( event ); - - return IsKeypadKey( XKeycodeToKeysym(event->xkey.display, event->xkey.keycode,(bsun && !awt_UseXKB ? 2 : 1) ) ); -} -/* - * In a next redesign, get rid of this code altogether. - * - */ -static void -handleKeyEventWithNumLockMask_New(XEvent *event, KeySym *keysym) -{ - KeySym originalKeysym = *keysym; - if( !isKPevent( event ) ) { - return; - } - if( isXsunServer( event ) && !awt_UseXKB ) { - if( (event->xkey.state & ShiftMask) ) { // shift modifier is on - *keysym = XKeycodeToKeysym(event->xkey.display, - event->xkey.keycode, 3); - }else { - *keysym = XKeycodeToKeysym(event->xkey.display, - event->xkey.keycode, 2); - } - } else { - if( (event->xkey.state & ShiftMask) || // shift modifier is on - ((event->xkey.state & LockMask) && // lock modifier is on - (awt_ModLockIsShiftLock)) ) { // it is interpreted as ShiftLock - *keysym = XKeycodeToKeysym(event->xkey.display, - event->xkey.keycode, 0); - }else{ - *keysym = XKeycodeToKeysym(event->xkey.display, - event->xkey.keycode, 1); - } - } -} - -/* Called from handleKeyEvent. - * The purpose of this function is to make some adjustments to keysyms - * that have been found to be necessary when the NumLock mask is set. - * They come from various bug fixes and rearchitectures. - * This function is meant to be called when - * (event->xkey.state & awt_NumLockMask) is TRUE. - */ -static void -handleKeyEventWithNumLockMask(XEvent *event, KeySym *keysym) -{ - KeySym originalKeysym = *keysym; - -#ifndef __linux__ - /* The following code on Linux will cause the keypad keys - * not to echo on JTextField when the NumLock is on. The - * keysyms will be 0, because the last parameter 2 is not defined. - * See Xlib Programming Manual, O'Reilly & Associates, Section - * 9.1.5 "Other Keyboard-handling Routines", "The meaning of - * the keysym list beyond the first two (unmodified, Shift or - * Shift Lock) is not defined." - */ - - /* Translate again with NumLock as modifier. */ - /* ECH - I wonder why we think that NumLock corresponds to 2? - * On Linux, we've seen xmodmap -pm yield mod2 as NumLock, - * but I don't know that it will be for every configuration. - * Perhaps using the index (modn in awt_MToolkit.c:setup_modifier_map) - * would be more correct. - */ - *keysym = XKeycodeToKeysym(event->xkey.display, - event->xkey.keycode, 2); - if (originalKeysym != *keysym) { - DTRACE_PRINTLN3("%s=%x, keysym=%x", - "In handleKeyEventWithNumLockMask ifndef linux: originalKeysym", - originalKeysym, *keysym); - } -#endif - - /* Note: the XK_R? key assignments are for Type 4 kbds */ - switch (*keysym) { - case XK_R13: - *keysym = XK_KP_1; - break; - case XK_R14: - *keysym = XK_KP_2; - break; - case XK_R15: - *keysym = XK_KP_3; - break; - case XK_R10: - *keysym = XK_KP_4; - break; - case XK_R11: - *keysym = XK_KP_5; - break; - case XK_R12: - *keysym = XK_KP_6; - break; - case XK_R7: - *keysym = XK_KP_7; - break; - case XK_R8: - *keysym = XK_KP_8; - break; - case XK_R9: - *keysym = XK_KP_9; - break; - case XK_KP_Insert: - *keysym = XK_KP_0; - break; - case XK_KP_Delete: - *keysym = XK_KP_Decimal; - break; - case XK_R4: - *keysym = XK_KP_Equal; /* Type 4 kbd */ - break; - case XK_R5: - *keysym = XK_KP_Divide; - break; - case XK_R6: - *keysym = XK_KP_Multiply; - break; - /* - * Need the following keysym changes for Linux key releases. - * Sometimes the modifier state gets messed up, so we get a - * KP_Left when we should get a KP_4, for example. - * XK_KP_Insert and XK_KP_Delete were already handled above. - */ - case XK_KP_Left: - *keysym = XK_KP_4; - break; - case XK_KP_Up: - *keysym = XK_KP_8; - break; - case XK_KP_Right: - *keysym = XK_KP_6; - break; - case XK_KP_Down: - *keysym = XK_KP_2; - break; - case XK_KP_Home: - *keysym = XK_KP_7; - break; - case XK_KP_End: - *keysym = XK_KP_1; - break; - case XK_KP_Page_Up: - *keysym = XK_KP_9; - break; - case XK_KP_Page_Down: - *keysym = XK_KP_3; - break; - case XK_KP_Begin: - *keysym = XK_KP_5; - break; - default: - break; - } - - if (originalKeysym != *keysym) { - DTRACE_PRINTLN2("In handleKeyEventWithNumLockMask: originalKeysym=%x, keysym=%x", - originalKeysym, *keysym); - } -} - -static void -handleKeyEvent(jint keyEventId, - XEvent *event, - XtPointer *client_data, - Boolean *cont, - Boolean passEvent) -{ - KeySym keysym = NoSymbol; - jint keycode = java_awt_event_KeyEvent_VK_UNDEFINED; - Modifiers mods = 0; - Boolean mapsToUnicodeChar = FALSE; - jint keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; - jint modifiers = 0; - - DTRACE_PRINTLN4("\nEntered handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", - event->type, event->xkey.keycode, event->xkey.state, keysym); - - if (currentX11InputMethodInstance != NULL - && keyEventId == java_awt_event_KeyEvent_KEY_PRESSED - && event->xkey.window == currentFocusWindow) - { - /* invokes XmbLookupString to get a committed string or keysym if any. */ - if (awt_x11inputmethod_lookupString((XKeyPressedEvent*)event, &keysym)) { - *cont = FALSE; - return; - } - } - - /* Ignore the keysym found immediately above in - * awt_x11inputmethod_lookupString; the methodology in that function - * sometimes returns incorrect results. - * - * Get keysym without taking modifiers into account first. - * This keysym is not necessarily for the character that was typed: - * it is for the primary layer. So, if $ were typed by pressing - * shift-4, this call should give us 4, not $ - * - * We only want this keysym so we can use it to index into the - * keymapTable to get the Java keycode associated with the - * primary layer key that was pressed. - */ - keysym = XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 0); - - /* Linux: Sometimes the keysym returned is uppercase when CapsLock is - * on and LockMask is not set in event->xkey.state. - */ - if (keysym >= (KeySym) 'A' && keysym <= (KeySym) 'Z') { - event->xkey.state |= LockMask; - keysym = (KeySym) tolower((int32_t) keysym); - } - - DTRACE_PRINTLN4("In handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", - event->type, event->xkey.keycode, event->xkey.state, keysym); - - if (keysym == NoSymbol) { - *cont = TRUE; - return; - } - - if (keysym < (KeySym) 256) { - keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); - - /* Now get real keysym which looks at modifiers - * XtGetActionKeySym() returns wrong value with Kana Lock, - * so use XtTranslateKeycode(). - */ - XtTranslateKeycode(event->xkey.display, (KeyCode) event->xkey.keycode, - event->xkey.state, &mods, &keysym); - DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", - "In handleKeyEvent keysym<256 ", event->type, event->xkey.keycode, - event->xkey.state, keysym, mods); - - /* Linux: With caps lock on, chars echo lowercase. */ - if ((event->xkey.state & LockMask) && - (keysym >= (KeySym) 'a' && keysym <= (KeySym) 'z')) - { - keysym = (KeySym) toupper((int32_t) keysym); - } - - if ((event->xkey.state & ControlMask)) { - switch (keysym) { - case '[': - case ']': - case '\\': - case '_': - keysym -= 64; - break; - default: - if (isalpha((int32_t) keysym)) { - keysym = (KeySym) tolower((int32_t) keysym) - 'a' + 1; - } - break; - } - } - - if (keysym >= (KeySym) XK_kana_fullstop && - keysym <= (KeySym) XK_semivoicedsound) { - /* - * 0xff61 is Unicode value of first XK_kana_fullstop. - * We need X Keysym to Unicode map in post1.1 release - * to support more intenational keyboard. - */ - keysym = keysym - XK_kana_fullstop + 0xff61; - } - - modifiers = getModifiers(event->xkey.state, 0, keycode); - DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, AWTmodifiers=%d", - "In handleKeyEvent keysym<256 ", event->type, event->xkey.keycode, - event->xkey.state, keysym, modifiers); - - awt_post_java_key_event(client_data, - keyEventId, - (passEvent == TRUE) ? event : NULL, - event->xkey.time, - keycode, - (jchar) keysym, - modifiers, - keyLocation, - event); - - if (keyEventId == java_awt_event_KeyEvent_KEY_PRESSED) { - awt_post_java_key_event(client_data, - java_awt_event_KeyEvent_KEY_TYPED, - NULL, - event->xkey.time, - java_awt_event_KeyEvent_VK_UNDEFINED, - (jchar) keysym, - modifiers, - java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, - event); - - } - } else { - if (event->xkey.state & awt_NumLockMask) { - if( awt_UseType4Patch ) { - handleKeyEventWithNumLockMask(event, &keysym); - }else{ - handleKeyEventWithNumLockMask_New(event, &keysym); - } - } - - if (keysym == XK_ISO_Left_Tab) { - keysym = XK_Tab; - } - - /* The keysym here does not consider modifiers, so these results - * are relevant to the KEY_PRESSED event only, not the KEY_TYPED - */ - keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); - DTRACE_PRINTLN3("In handleKeyEvent: keysym=%x, AWTkeycode=%x, mapsToUnicodeChar=%d", - keysym, keycode, mapsToUnicodeChar); - - if (keycode == java_awt_event_KeyEvent_VK_UNDEFINED) { - *cont = TRUE; - return; - } - - /* Need to take care of keysyms > 0xFFFF here - * Most of these keys don't map to unicode characters, but some do. - * - * For keys that don't map to unicode characters, the keysym - * is irrelevant at this point. We set the keysym to zero - * to ensure that the switch statement immediately below - * this function call (in adjustKeySym) won't incorrectly act - * on them after the high bits are stripped off. - * - * For keys that do map to unicode characters, we change the keysym - * to the equivalent that is < 0xFFFF - */ - handleVendorKeySyms(event, &keysym); - - /* This function is a conglomeration of bug fixes that adjust - * the keysym and XEvent keycode for this key event. - */ - adjustKeySym(event, &keysym); - - modifiers = getModifiers(event->xkey.state, 0, keycode); - - DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", - "In handleKeyEvent keysym>=256 ", event->type, event->xkey.keycode, - event->xkey.state, keysym, mods); - DTRACE_PRINTLN2(" AWTkeycode=%x, AWTmodifiers=%d", - keycode, modifiers); - - awt_post_java_key_event(client_data, - keyEventId, - (passEvent == TRUE) ? event : NULL, - event->xkey.time, - keycode, - (jchar) (mapsToUnicodeChar ? keysym : - java_awt_event_KeyEvent_CHAR_UNDEFINED), - modifiers, - keyLocation, - event); - - /* If this was a keyPressed event, we may need to post a - * keyTyped event, too. Otherwise, return. - */ - if (keyEventId == java_awt_event_KeyEvent_KEY_RELEASED) { - return; - } - DTRACE_PRINTLN("This is a keyPressed event"); - - /* XtTranslateKeycode seems to return slightly bogus values for the - * Escape key (keysym==1004ff69==osfXK_Cancel, xmods=2) on Solaris, - * so we just create the KEY_TYPED as a special case for Escape here. - * (Linux works fine, and this was also okay running under VNC.) - */ - if (keycode == java_awt_event_KeyEvent_VK_ESCAPE) { - awt_post_java_key_event(client_data, - java_awt_event_KeyEvent_KEY_TYPED, - NULL, - event->xkey.time, - java_awt_event_KeyEvent_VK_UNDEFINED, - (jchar) keysym, - modifiers, - java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, - event); - - DTRACE_PRINTLN("Posted a keyTyped event for VK_ESCAPE"); - return; - } - - /* Now get real keysym which looks at modifiers for keyTyped event. - * XtGetActionKeySym() returns wrong value with Kana Lock, - * so use XtTranslateKeycode(). - */ - XtTranslateKeycode(event->xkey.display, (KeyCode) event->xkey.keycode, - event->xkey.state, &mods, &keysym); - DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", - "In handleKeyEvent keysym>=256 ", event->type, event->xkey.keycode, - event->xkey.state, keysym, mods); - - if (keysym == NoSymbol) { - return; - } - - if (event->xkey.state & awt_NumLockMask) { - if( awt_UseType4Patch ) { - handleKeyEventWithNumLockMask(event, &keysym); - }else{ - handleKeyEventWithNumLockMask_New(event, &keysym); - } - } - - if (keysym == XK_ISO_Left_Tab) { - keysym = XK_Tab; - } - - /* Map the real keysym to a Java keycode */ - keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); - DTRACE_PRINTLN3("In handleKeyEvent: keysym=%x, AWTkeycode=%x, mapsToUnicodeChar=%d", - keysym, keycode, mapsToUnicodeChar); - - /* If it doesn't map to a Unicode character, don't post a keyTyped event */ - if (!mapsToUnicodeChar) { - return; - } - - handleVendorKeySyms(event, &keysym); - adjustKeySym(event, &keysym); - DTRACE_PRINT4("In handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", - event->type, event->xkey.keycode, event->xkey.state, keysym); - DTRACE_PRINTLN2(", AWTkeycode=%x, AWTmodifiers=%d", keycode, modifiers); - - awt_post_java_key_event(client_data, - java_awt_event_KeyEvent_KEY_TYPED, - NULL, - event->xkey.time, - java_awt_event_KeyEvent_VK_UNDEFINED, - (jchar) keysym, - modifiers, - java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, - event); - } -} - - -static void -translateXY(Widget w, jint *xp, jint *yp) -{ - Position wx, wy; - - XtVaGetValues(w, XmNx, &wx, XmNy, &wy, NULL); - *xp += wx; - *yp += wy; -} - - -/* - * Part fix for bug id 4017222. Return the root widget of the Widget parameter. - */ -Widget -getRootWidget(Widget w) { - if(!w) return NULL; - - if(XtParent(w)) - return getRootWidget(XtParent(w)); - else - return w; -} - -#define ABS(x) ((x) < 0 ? -(x) : (x)) - -/* This proc is the major AWT engine for processing X events - * for Java components and is the proc responsible for taking - * X events and posting their corresponding Java event to the - * AWT EventQueue. It is set up to be called both from an Xt - * event handler and directly from MToolkit.c:shouldDispatchToWidget(). - * For the latter case, the "passEvent" parameter will be true, - * which means that the event is being posted on the Java queue - * BEFORE it is being passed to Xt and so a copy of the X event - * must be stored within the Java event structure so it can be - * dispatched to Xt later on. - */ -void -awt_canvas_handleEvent(Widget w, XtPointer client_data, - XEvent * event, struct WidgetInfo *winfo, - Boolean * cont, Boolean passEvent) -{ - static jint clickCount = 1; - static XtPointer lastPeer = NULL; - static Time lastTime = 0; - static jint lastx = 0; - static jint lasty = 0; - static int32_t rbutton = 0; - static int32_t lastButton = 0; - Boolean popupTrigger; - jint x, y; - jint modifiers = 0; - jint button = java_awt_event_MouseEvent_NOBUTTON; - uint32_t fullRelease = 0; - WidgetClass wclass = NULL; - - /* Any event handlers which take peer instance pointers as - * client_data should check to ensure the widget has not been - * marked as destroyed as a result of a dispose() call on the peer - * (which can result in the peer instance pointer already haven - * been gc'd by the time this event is processed) - */ - if (w->core.being_destroyed) { - return; - } - *cont = FALSE; - - switch (event->type) { - case SelectionClear: - case SelectionNotify: - case SelectionRequest: - *cont = TRUE; - break; - case GraphicsExpose: - case Expose: - HandleExposeEvent(w, (jobject) client_data, event); - break; - case FocusIn: - case FocusOut: - *cont = TRUE; - updateCursor(client_data, CACHE_UPDATE); // 4840883 - // We no longer listen to the Motif focus notifications. - // Instead we call focus callbacks in the times we think - // appropriate trying to simulate correct Motif widget system - // behavior. - break; - case ButtonPress: - x = (jint) event->xbutton.x; - y = (jint) event->xbutton.y; - - if (lastPeer == client_data && - lastButton == event->xbutton.button && - (event->xbutton.time - lastTime) <= (Time) awt_multiclick_time) { - clickCount++; - } else { - clickCount = 1; - lastPeer = client_data; - lastButton = event->xbutton.button; - lastx = x; - lasty = y; - } - lastTime = event->xbutton.time; - - /* On MouseEvent.MOUSE_PRESSED, RELEASED and CLICKED only new modifiers and - * modifier for changed mouse button are set. - */ - button = getButton(event->xbutton.button); - modifiers = getModifiers(event->xbutton.state, button, 0); - - - /* If the widget is a subwidget on a component we need to - * translate the x,y into the coordinate space of the component. - */ - if (winfo != NULL && winfo->widget != winfo->origin) { - translateXY(winfo->widget, &x, &y); - } - - if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { - passEvent = FALSE; - *cont = TRUE; - } - - /* Mouse wheel events come in as button 4 (wheel up) and - * button 5 (wheel down). - */ - if (lastButton == 4 || lastButton == 5) { - *cont = FALSE; - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_WHEEL, - (passEvent == TRUE) ? event : NULL, - event->xbutton.time, - modifiers, - x, y, - (jint) (event->xbutton.x_root), - (jint) (event->xbutton.y_root), - clickCount, - False, - lastButton == 4 ? -1 : 1, - java_awt_event_MouseEvent_NOBUTTON); - /* we're done with this event */ - break; - } - - /* (4168006) Find out out how many buttons we have - * If this is a two button system Right == 2 - * If this is a three button system Right == 3 - */ - if ( rbutton == 0 ) { - unsigned char map[5]; - rbutton = XGetPointerMapping ( awt_display, map, 3 ); - } - - if (event->xbutton.button == rbutton || event->xbutton.button > 2) { - popupTrigger = True; - } else { - popupTrigger = False; - } - - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_PRESSED, - (passEvent == TRUE) ? event : NULL, - event->xbutton.time, - modifiers, - x, y, - (jint) (event->xbutton.x_root), - (jint) (event->xbutton.y_root), - clickCount, - popupTrigger, 0, - button); - - drag_source = w; - - break; - case ButtonRelease: - if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { - passEvent = FALSE; - *cont = TRUE; - } - - /* - * For button 4 & 5 (mouse wheel) we can simply ignore this event. - * We dispatch the wheel on the ButtonPress. - */ - if (event->xbutton.button == 4 || - event->xbutton.button == 5) { - break; - } - - prevWidget = NULL; - x = (jint) event->xbutton.x; - y = (jint) event->xbutton.y; - /* On MouseEvent.MOUSE_PRESSED, RELEASED and CLICKED only new modifiers and - * modifier for changed mouse button are set. - */ - button = getButton(event->xbutton.button); - modifiers = getModifiers(event->xbutton.state, button, 0); - - fullRelease = - ((event->xbutton.state & Button1Mask) && - !(event->xbutton.state & Button2Mask) && - !(event->xbutton.state & Button3Mask) && - (event->xbutton.button == Button1)) || - (!(event->xbutton.state & Button1Mask) && - (event->xbutton.state & Button2Mask) && - !(event->xbutton.state & Button3Mask) && - (event->xbutton.button == Button2)) || - (!(event->xbutton.state & Button1Mask) && - !(event->xbutton.state & Button2Mask) && - (event->xbutton.state & Button3Mask) && - (event->xbutton.button == Button3)); - - /* If the widget is a subwidget on a component we need to - * translate the x,y into the coordinate space of the component. - */ - if (winfo != NULL && winfo->widget != winfo->origin) { - translateXY(winfo->widget, &x, &y); - } - drag_source = NULL; - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_RELEASED, - (passEvent == TRUE) ? event : NULL, - event->xbutton.time, - modifiers, - x, y, - (jint) (event->xbutton.x_root), - (jint) (event->xbutton.y_root), - clickCount, - FALSE, 0, - button); - - if (lastPeer == client_data) { - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_CLICKED, - NULL, - event->xbutton.time, - modifiers, - x, y, - (jint) (event->xbutton.x_root), - (jint) (event->xbutton.y_root), - clickCount, - FALSE, 0, - button); - } - - if (fullRelease) { - updateCursor(client_data, UPDATE_ONLY); - } - - break; - case MotionNotify: - if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { - passEvent = FALSE; - *cont = TRUE; - } - - x = (jint) event->xmotion.x; - y = (jint) event->xmotion.y; - - /* If a motion comes in while a multi-click is pending, - * allow a smudge factor so that moving the mouse by a small - * amount does not wipe out the multi-click state variables. - */ - if (!(lastPeer == client_data && - ((event->xmotion.time - lastTime) <= (Time) awt_multiclick_time) && - (ABS(lastx - x) < awt_multiclick_smudge && - ABS(lasty - y) < awt_multiclick_smudge))) { - clickCount = (jint) 0; - lastTime = (Time) 0; - lastPeer = NULL; - lastx = (jint) 0; - lasty = (jint) 0; - } - /* On other MouseEvent only new modifiers and - * old mouse modifiers are set. - */ - modifiers = getModifiers(event->xmotion.state, 0, 0); - - /* If the widget is a subwidget on a component we need to - * translate the x,y into the coordinate space of the component. - */ - if (winfo != NULL && winfo->widget != winfo->origin) { - translateXY(winfo->widget, &x, &y); - } - if (event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) { - if (!clickCount) { - - /* - Fix for bug id 4017222. A button is down, so EnterNotify and - LeaveNotify events are only being sent to this widget. If - the pointer has moved over a new widget, manually generate - MouseEnter and MouseExit and send them to the right widgets. - */ - - extern Widget awt_WidgetAtXY(Widget root, Position x, Position y); - extern Widget awt_GetWidgetAtPointer(); - Widget currentWidget=NULL, topLevelW; - Position wx=0, wy=0; - - XtTranslateCoords(w, (int32_t) x, (int32_t) y, &wx, &wy); - /* Get the top level widget underneath the mouse pointer */ - currentWidget = awt_GetWidgetAtPointer(); - /* Get the exact widget at the current XY from the top level */ - currentWidget = awt_WidgetAtXY(currentWidget, wx, wy); - if ((prevWidget != NULL) && (prevWidget != w) && - (currentWidget != prevWidget) && awt_isAwtWidget(prevWidget) && - !prevWidget->core.being_destroyed) { - XtPointer userData=NULL; - XtVaGetValues(prevWidget, XmNuserData, &userData, NULL); - if (userData) { - awt_post_java_mouse_event(userData, - java_awt_event_MouseEvent_MOUSE_EXITED, - (passEvent==TRUE) ? event : NULL, - event->xmotion.time, - modifiers, - x, y, - (jint) (event->xmotion.x_root), - (jint) (event->xmotion.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - } - } - - if ((currentWidget != NULL) && (currentWidget != w) && - (currentWidget != prevWidget) && awt_isAwtWidget(currentWidget)) { - XtPointer userData=NULL; - XtVaGetValues(currentWidget, XmNuserData, &userData, NULL); - if (userData) { - awt_post_java_mouse_event(userData, - java_awt_event_MouseEvent_MOUSE_ENTERED, - (passEvent==TRUE) ? event : NULL, - event->xmotion.time, - modifiers, - x, y, - (jint) (event->xmotion.x_root), - (jint) (event->xmotion.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - } - - updateCursor(userData, CACHE_ONLY); - awt_util_setCursor(currentWidget, None); - } - - prevWidget = currentWidget; - /* end 4017222 */ - - - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_DRAGGED, - (passEvent == TRUE) ? event : NULL, - event->xmotion.time, - modifiers, - x, y, - (jint) (event->xmotion.x_root), - (jint) (event->xmotion.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - - } - } else { - - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_MOVED, - (passEvent == TRUE) ? event : NULL, - event->xmotion.time, - modifiers, - x, y, - (jint) (event->xmotion.x_root), - (jint) (event->xmotion.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - } - break; - case KeyPress: - handleKeyEvent(java_awt_event_KeyEvent_KEY_PRESSED, - event, client_data, cont, TRUE); - break; - case KeyRelease: - handleKeyEvent(java_awt_event_KeyEvent_KEY_RELEASED, - event, client_data, cont, TRUE); - break; - case EnterNotify: - case LeaveNotify: -/* - printf("----->%s on %s(%x):mode=%d detail = %d\n", - event->type == EnterNotify?"EnterNotify":"LeaveNotify", - XtName(w), w, - ((XCrossingEvent*)event)->mode, ((XCrossingEvent*)event)->detail); -*/ - if (event->xcrossing.mode != NotifyNormal || - ((event->xcrossing.detail == NotifyVirtual || - event->xcrossing.detail == NotifyNonlinearVirtual) && - !XtIsSubclass(w, xmScrolledWindowWidgetClass))) { - *cont = TRUE; - return; - } - - /* fix for 4454304. - * We should not post MOUSE_ENTERED and MOUSE_EXITED events - * if the mouse pointer is in the place between component - * and its scrollbars. - * kdm@sparc.spb.su - */ - if (winfo != NULL && winfo->widget != NULL) { - wclass = XtClass(winfo->widget); - if (event->xcrossing.subwindow == NULL - && event->xcrossing.detail == NotifyInferior - && (wclass == xmTextWidgetClass - || wclass == xmListWidgetClass)) { - *cont = TRUE; - return; - } - } - - clickCount = (jint) 0; - lastTime = (Time) 0; - lastPeer = NULL; - - /* On other MouseEvent only new modifiers and - * old mouse modifiers are set. - */ - modifiers = getModifiers(event->xcrossing.state, 0, 0); - - switch (event->type) { - case EnterNotify: - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_ENTERED, - (passEvent == TRUE) ? event : NULL, - event->xcrossing.time, - modifiers, - (jint) (event->xcrossing.x), - (jint) (event->xcrossing.y), - (jint) (event->xcrossing.x_root), - (jint) (event->xcrossing.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - if (!(event->xcrossing.state - & (Button1Mask | Button2Mask | Button3Mask))) { - updateCursor(client_data, CACHE_UPDATE); - } - - break; - case LeaveNotify: - awt_post_java_mouse_event(client_data, - java_awt_event_MouseEvent_MOUSE_EXITED, - (passEvent == TRUE) ? event : NULL, - event->xcrossing.time, - modifiers, - (jint) (event->xcrossing.x), - (jint) (event->xcrossing.y), - (jint) (event->xcrossing.x_root), - (jint) (event->xcrossing.y_root), - clickCount, - FALSE, 0, - java_awt_event_MouseEvent_NOBUTTON); - break; - } - break; - - default: - break; - } -} - -/* - * client_data is MComponentPeer subclass - */ -void -awt_canvas_event_handler(Widget w, XtPointer client_data, - XEvent * event, Boolean * cont) -{ - awt_canvas_handleEvent(w, client_data, event, NULL, cont, FALSE); -} - -void -awt_canvas_reconfigure(struct FrameData *wdata) -{ - Dimension w, h; - - if (wdata->winData.comp.widget == NULL || - XtParent(wdata->winData.comp.widget) == NULL) { - return; - } - XtVaGetValues(XtParent(wdata->winData.comp.widget), XmNwidth, &w, XmNheight, &h, NULL); - XtConfigureWidget(wdata->winData.comp.widget, - -(wdata->left), - -(wdata->top), - w + (wdata->left + wdata->right), - h + (wdata->top + wdata->bottom), - 0); -} - -static void -Wrap_event_handler(Widget widget, - XtPointer client_data, - XmDrawingAreaCallbackStruct * call_data) -{ - awt_canvas_reconfigure((struct FrameData *) client_data); -} - - -Widget -awt_canvas_create(XtPointer this, - Widget parent, - char *base, - int32_t width, - int32_t height, - Boolean parentIsFrame, - struct FrameData *wdata, - AwtGraphicsConfigDataPtr awtData) -{ - Widget newCanvas; - Widget wrap; -#define MAX_ARGC 20 - Arg args[MAX_ARGC]; - int32_t argc; - char name[128]; - static XtTranslations translationKeyDown = NULL; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - - if (parent == NULL) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return NULL; - } - if (width == 0) { - width = 1; - } - if (height == 0) { - height = 1; - } - - if (wdata != NULL) { - argc = 0; - if (!parentIsFrame) - { - XtSetArg(args[argc], XmNwidth, width); - argc++; - XtSetArg(args[argc], XmNheight, height); - argc++; - } - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNspacing, 0); - argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); - argc++; - /* check for overflowing name? */ - strcpy(name, base); - strcat(name, "wrap"); - - DASSERT(!(argc > MAX_ARGC)); - wrap = XmCreateDrawingArea(parent, name, args, argc); - if (!parentIsFrame) - { - /* Fixing bugs in frame module (awt_Frame.c). It will now - provide the resize handling for this inner/parent canvas.*/ - XtAddCallback(wrap, XmNresizeCallback, - (XtCallbackProc) Wrap_event_handler, wdata); - } - XtManageChild(wrap); - } else { - wrap = parent; - } - - /* check for overflowing name? */ - strcpy(name, base); - strcat(name, "canvas"); - - argc = 0; - XtSetArg(args[argc], XmNspacing, 0); - argc++; - if (!parentIsFrame) - { - XtSetArg(args[argc], XmNwidth, width); - argc++; - XtSetArg(args[argc], XmNheight, height); - argc++; - } - XtSetArg(args[argc], XmNmarginHeight, 0); - argc++; - XtSetArg(args[argc], XmNmarginWidth, 0); - argc++; - XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); - argc++; - XtSetArg(args[argc], XmNuserData, this); - argc++; - /* Fixed 4059430, 3/11/98, robi.khan@eng - * install insert proc callback so components are ordered correctly - * when added directly to frame/dialogs/windows - */ - XtSetArg(args[argc], XmNinsertPosition, (XtPointer) awt_util_insertCallback); - argc++; - - if (awtData != getDefaultConfig(awtData->awt_visInfo.screen)) { - XtSetArg (args[argc], XtNvisual, awtData->awt_visInfo.visual); argc++; - XtSetArg (args[argc], XmNdepth, awtData->awt_depth); argc++; - XtSetArg (args[argc], XmNscreen, - ScreenOfDisplay(awt_display, - awtData->awt_visInfo.screen)); argc++; - - if (awtData->awt_cmap == None) { - awtJNI_CreateColorData (env, awtData, 1); - } - - XtSetArg (args[argc], XmNcolormap, awtData->awt_cmap); argc++; - - DASSERT(!(argc > MAX_ARGC)); - newCanvas = XtCreateWidget(name, vDrawingAreaClass, wrap, - args, argc); - - } else { - newCanvas = XtCreateWidget(name, xDrawingAreaClass, - wrap, args, argc); - } - - XtSetMappedWhenManaged(newCanvas, False); - XtManageChild(newCanvas); -/* - XXX: causes problems on 2.5 - if (!scrollBugWorkAround) { - awt_setWidgetGravity(newCanvas, StaticGravity); - } -*/ - /* Fixed 4250354 7/28/99 ssi@sparc.spb.su - * XtParseTranslationTable leaks in old ver of Xtoolkit - * and result should be deletetd in any case - * - * XtOverrideTranslations(newCanvas, - * XtParseTranslationTable(":DrawingAreaInput()")); - */ - if (NULL==translationKeyDown) - translationKeyDown=XtParseTranslationTable(":DrawingAreaInput()"); - XtOverrideTranslations(newCanvas,translationKeyDown); - - XtSetSensitive(newCanvas, True); - - return newCanvas; -} - -static void -messWithGravity(Widget w, int32_t gravity) -{ - extern void awt_changeAttributes(Display * dpy, Widget w, - unsigned long mask, - XSetWindowAttributes * xattr); - XSetWindowAttributes xattr; - - xattr.bit_gravity = gravity; - xattr.win_gravity = gravity; - - awt_changeAttributes(XtDisplay(w), w, (CWBitGravity | CWWinGravity), &xattr); - -} - -struct MoveRecord { - long dx; - long dy; -}; - -void -moveWidget(Widget w, void *data) -{ - struct MoveRecord *rec = (struct MoveRecord *) data; - - if (XtIsRealized(w) && XmIsRowColumn(w)) { - w->core.x -= rec->dx; - w->core.y -= rec->dy; - } -} - -#if 0 -/* Scroll entire contents of window by dx and dy. Currently only - dy is supported. A negative dy means scroll backwards, i.e., - contents in window move down. */ -void -awt_canvas_scroll(XtPointer this, - struct CanvasData *wdata, - long dx, - long dy) -{ - - Window win; - XWindowChanges xchgs; - Window root; - int x, y; - unsigned int width, height, junk; - Display *dpy; - struct MoveRecord mrec; - - mrec.dx = dx; - mrec.dy = dy; - - dpy = XtDisplay(wdata->comp.widget); - win = XtWindow(wdata->comp.widget); - - /* REMIND: consider getting rid of this! */ - XGetGeometry(awt_display, - win, - &root, - &x, - &y, - &width, - &height, - &junk, - &junk); - - /* we need to actually update the coordinates for manager widgets, */ - /* otherwise the parent won't pass down events to them properly */ - /* after scrolling... */ - awt_util_mapChildren(wdata->comp.widget, moveWidget, 0, &mrec); - - if (dx < 0) { - /* scrolling backward */ - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthWestGravity); - } - xchgs.x = x + dx; - xchgs.y = y; - xchgs.width = width - dx; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWX | CWY | CWWidth | CWHeight, - &xchgs); - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthWestGravity); - } - xchgs.x = x; - xchgs.y = y; - XConfigureWindow(awt_display, - win, - CWX | CWY, - &xchgs); - - xchgs.width = width; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWWidth | CWHeight, - &xchgs); - } else { - /* forward scrolling */ - - /* make window a little taller */ - xchgs.width = width + dx; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWWidth | CWHeight, - &xchgs); - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthEastGravity); - } - /* move window by amount we're scrolling */ - xchgs.x = x - dx; - xchgs.y = y; - XConfigureWindow(awt_display, - win, - CWX | CWY, - &xchgs); - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthWestGravity); - } - /* resize to original size */ - xchgs.x = x; - xchgs.y = y; - xchgs.width = width; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWX | CWY | CWWidth | CWHeight, - &xchgs); - } - /* Because of the weird way we're scrolling this window, - we have to eat all the exposure events that result from - scrolling forward, and translate them up by the amount we're - scrolling by. - - Rather than just eating all the exposures and having the - java code fill in what it knows is exposed, we do it this - way. The reason is that there might be some other exposure - events caused by overlapping windows on top of us that we - also need to deal with. */ - { - XRectangle rect; - - rect.x = -1; - eatAllExposures(dpy, win, &rect); - if (rect.x != -1) { /* we got at least one expose event */ - if (dx > 0) { - rect.x -= dx; - rect.width += dx; - } -/* - printf("EXPOSE (%d): %d, %d, %d, %d\n", - dy, rect.x, rect.y, rect.width, rect.height); -*/ - callJavaExpose(this, &rect); - XSync(awt_display, False); - } - } - if (dy < 0) { - /* scrolling backward */ - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, SouthGravity); - } - xchgs.x = x; - xchgs.y = y + dy; - xchgs.width = width; - xchgs.height = height - dy; - XConfigureWindow(awt_display, - win, - CWX | CWY | CWWidth | CWHeight, - &xchgs); - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthWestGravity); - } - xchgs.x = x; - xchgs.y = y; - XConfigureWindow(awt_display, - win, - CWX | CWY, - &xchgs); - - xchgs.width = width; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWWidth | CWHeight, - &xchgs); - } else { - /* forward scrolling */ - - /* make window a little taller */ - xchgs.width = width; - xchgs.height = height + dy; - XConfigureWindow(awt_display, - win, - CWWidth | CWHeight, - &xchgs); - - /* move window by amount we're scrolling */ - xchgs.x = x; - xchgs.y = y - dy; - XConfigureWindow(awt_display, - win, - CWX | CWY, - &xchgs); - - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, SouthGravity); - } - /* resize to original size */ - xchgs.x = x; - xchgs.y = y; - xchgs.width = width; - xchgs.height = height; - XConfigureWindow(awt_display, - win, - CWX | CWY | CWWidth | CWHeight, - &xchgs); - if (scrollBugWorkAround) { - messWithGravity(wdata->comp.widget, NorthWestGravity); - } - } - /* Because of the weird way we're scrolling this window, - we have to eat all the exposure events that result from - scrolling forward, and translate them up by the amount we're - scrolling by. - - Rather than just eating all the exposures and having the - java code fill in what it knows is exposed, we do it this - way. The reason is that there might be some other exposure - events caused by overlapping windows on top of us that we - also need to deal with. */ - { - XRectangle rect; - - rect.x = -1; - eatAllExposures(dpy, win, &rect); - if (rect.x != -1) { /* we got at least one expose event */ - if (dy > 0) { - rect.y -= dy; - rect.height += dy; - } - if (dx > 0) { - rect.x -= dx; - rect.width += dx; - } -/* - printf("EXPOSE (%d): %d, %d, %d, %d\n", - dy, rect.x, rect.y, rect.width, rect.height); -*/ - callJavaExpose(this, &rect); - XSync(awt_display, False); - } - } -} -#endif - -extern Window focusProxyWindow; -/* - * client_data is MComponentPeer instance - */ -void -awt_post_java_key_event(XtPointer client_data, jint id, XEvent *event, - Time when, jint keycode, jchar keychar, jint modifiers, jint keyLocation, XEvent *anEvent) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject peer = (jobject) client_data; - jobject target; - static jclass classKeyEvent = NULL; - static jmethodID mid = NULL; - char *clsName = "java/awt/event/KeyEvent"; - jobject hEvent; - jlong jWhen; - Boolean isProxyActive = (focusProxyWindow != None); - - if (anEvent != NULL && anEvent->xany.send_event == 2){ - isProxyActive = False; - if (event != NULL) { - event->xany.send_event = 0; - } - } - if ((*env)->PushLocalFrame(env, 16) < 0) - return; - - target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - - if (classKeyEvent == NULL) { - jobject sysClass; - - sysClass = (*env)->FindClass(env, clsName); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - classKeyEvent = (*env)->NewGlobalRef(env, sysClass); - mid = (*env)->GetMethodID(env, classKeyEvent, "", - "(Ljava/awt/Component;IJIICIZ)V"); - } - if (JNU_IsNull(env, classKeyEvent) || mid == NULL) { - JNU_ThrowClassNotFoundException(env, clsName); - (*env)->PopLocalFrame(env, 0); - return; - } - } - - jWhen = awt_util_nowMillisUTC_offset(when); /* convert Time to UTC */ - - hEvent = (*env)->NewObject(env, classKeyEvent, mid, - target, id, jWhen, modifiers, - keycode, keychar, keyLocation, - isProxyActive?JNI_TRUE:JNI_FALSE); - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (JNU_IsNull(env, hEvent)) { - JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); - (*env)->PopLocalFrame(env, 0); - return; - } - awt_copyXEventToAWTEvent(env, event, hEvent); - #ifdef DEBUG - if (debugKeys) { - jio_fprintf(stderr, "native posting event id:%d keychar:%c\n", (int)id, (char)keychar); - } - #endif - JNU_CallMethodByName(env, NULL, peer, - "postEvent", "(Ljava/awt/AWTEvent;)V", hEvent); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - (*env)->PopLocalFrame(env, 0); -} /* awt_post_java_key_event() */ - -/* - * Note: this routine returns a global reference which should be deleted - * after use. - */ -jobject -awt_canvas_wrapInSequenced(jobject awtevent) { - static jclass classSequencedEvent = NULL; - static jmethodID mid = NULL; - jobject wrapperEventLocal = NULL; - jobject wrapperEvent = NULL; - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - if ((*env)->PushLocalFrame(env, 5) < 0) - return NULL; - - if (classSequencedEvent == NULL) { - jobject sysClass = (*env)->FindClass(env, "java/awt/SequencedEvent"); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - classSequencedEvent = (*env)->NewGlobalRef(env, sysClass); - if (mid == NULL) { - mid = (*env)->GetMethodID(env, classSequencedEvent - ,"" - ,"(Ljava/awt/AWTEvent;)V"); - } - } - if (JNU_IsNull(env, classSequencedEvent) || mid == NULL) { - JNU_ThrowClassNotFoundException(env, "java/awt/SequencedEvent"); - (*env)->PopLocalFrame(env, 0); - return NULL; - } - } - wrapperEventLocal = (*env)->NewObject(env, classSequencedEvent, mid, awtevent); - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (JNU_IsNull(env, wrapperEventLocal)) { - JNU_ThrowNullPointerException(env, "constructor failed."); - (*env)->PopLocalFrame(env, 0); - return NULL; - } - wrapperEvent = (*env)->NewGlobalRef(env, wrapperEventLocal); - if (!JNU_IsNull(env, ((*env)->ExceptionOccurred(env)))) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - (*env)->PopLocalFrame(env, 0); - return NULL; - } - if (JNU_IsNull(env, wrapperEvent)) { - JNU_ThrowNullPointerException(env, "NewGlobalRef failed."); - (*env)->PopLocalFrame(env, 0); - return NULL; - } - - (*env)->PopLocalFrame(env, 0); - return wrapperEvent; -} - -jobject -findTopLevelOpposite(JNIEnv *env, jint eventType) -{ - jobject target, peer, opposite; - - if ((*env)->EnsureLocalCapacity(env, 2) < 0) { - return NULL; - } - - /* 4462056: Get a usable handle for a weakly referenced object */ - target = (*env)->NewLocalRef(env, - (eventType == java_awt_event_WindowEvent_WINDOW_GAINED_FOCUS) - ? forGained - : focusList->requestor); - if (target == NULL) { - return NULL; - } - - peer = (*env)->GetObjectField(env, target, componentIDs.peer); - (*env)->DeleteLocalRef(env, target); - if (peer == NULL) { - return NULL; - } - - opposite = findTopLevel(peer, env); - (*env)->DeleteLocalRef(env, peer); - - return opposite; -} - -void -cleanFocusList(JNIEnv *env){ - - while(focusList) { - FocusListElt *tmp = focusList->next; - (*env)->DeleteWeakGlobalRef(env, focusList->requestor); - free(focusList); - focusList = tmp; - } - focusListEnd = NULL; -} - -static jweak -computeOpposite(jint id, jobject target) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject top; - jboolean isSameObject; - - if (focusList == NULL) { - return NULL; - } - - /* 4462056: Get a usable handle for a weakly referenced object */ - top = (*env)->NewLocalRef(env, focusList->requestor); - if (top == NULL) { - /* weakly referenced component was deleted -- clean up focus list */ - cleanFocusList(env); - return NULL; - } - - isSameObject = (*env)->IsSameObject(env, target, top); - (*env)->DeleteLocalRef(env, top); - - if (isSameObject) { - if (id == java_awt_event_FocusEvent_FOCUS_GAINED) { - return forGained; - } else { /* focus lost */ - FocusListElt *tmp = focusList->next; - (*env)->DeleteWeakGlobalRef(env, forGained); - forGained = focusList->requestor; - free(focusList); - focusList = tmp; - - if (focusList == NULL) { - focusListEnd = NULL; - return NULL; - } - return focusList->requestor; - } - } else { /* target does not match top of list */ - /* be gentle with focus lost for now... */ - if (id == java_awt_event_FocusEvent_FOCUS_LOST) { - (*env)->DeleteWeakGlobalRef(env, forGained); - forGained = (*env)->NewWeakGlobalRef(env, target); - return NULL; - } - - cleanFocusList(env); - return NULL; - } -} - - -/* - * client_data is MComponentPeer instance - */ -void -awt_post_java_focus_event(XtPointer client_data, - jint id, jobject cause, - XEvent* event) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject peer = (jobject) client_data; - jobject target; - jobject opposite; - static jclass classFocusEvent = NULL; - static jmethodID mid = NULL; - char *clsName = "sun/awt/CausedFocusEvent"; - jobject hEvent; - - if ((*env)->PushLocalFrame(env, 16) < 0) - return; - - target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - - opposite = (*env)->NewLocalRef(env, computeOpposite(id, target)); - - if (classFocusEvent == NULL) { - jobject sysClass; - - sysClass = (*env)->FindClass(env, clsName); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - classFocusEvent = (*env)->NewGlobalRef(env, sysClass); - mid = (*env)->GetMethodID(env, classFocusEvent - ,"" - ,"(Ljava/awt/Component;IZLjava/awt/Component;Lsun/awt/CausedFocusEvent$Cause;)V"); - } - if (JNU_IsNull(env, classFocusEvent) || mid == 0) { - JNU_ThrowClassNotFoundException(env, clsName); - (*env)->PopLocalFrame(env, 0); - return; - } - } - hEvent = (*env)->NewObject(env, classFocusEvent, mid, - target, id, JNI_FALSE, opposite, cause); - (*env)->DeleteLocalRef(env, opposite); - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (JNU_IsNull(env, hEvent)) { - JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); - (*env)->PopLocalFrame(env, 0); - return; - } - awt_copyXEventToAWTEvent(env, event, hEvent); - { - jobject awtEvent = awt_canvas_wrapInSequenced(hEvent); - JNU_CallMethodByName(env, NULL, peer, - "postEvent", "(Ljava/awt/AWTEvent;)V", - awtEvent); - (*env)->DeleteGlobalRef(env, awtEvent); - } - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - (*env)->PopLocalFrame(env, 0); -} - - -void -awt_canvas_addToFocusListDefault(jobject target) { - awt_canvas_addToFocusListWithDuplicates(target, JNI_FALSE); -} - -void -awt_canvas_addToFocusListWithDuplicates(jobject target, jboolean acceptDuplicates) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jboolean isSameObject; - - if (focusListEnd) { - jobject localRef = (*env)->NewLocalRef(env, focusListEnd->requestor); - - if (localRef == NULL) { - isSameObject = JNI_FALSE; - } else { - isSameObject = (*env)->IsSameObject(env, target, localRef); - (*env)->DeleteLocalRef(env, localRef); - } - - if (isSameObject && !acceptDuplicates) { - return; - } - - focusListEnd->next = malloc(sizeof(FocusListElt)); - focusListEnd = focusListEnd->next; - } else { - jobject l_focusOwnerPeer = awt_canvas_getFocusOwnerPeer(); - if (l_focusOwnerPeer == NULL) { - isSameObject = JNI_FALSE; - } else { - jobject l_focusOwner = - (*env)->GetObjectField(env, l_focusOwnerPeer, - mComponentPeerIDs.target); - isSameObject = - (*env)->IsSameObject(env, target, l_focusOwner); - (*env)->DeleteLocalRef(env, l_focusOwner); - (*env)->DeleteLocalRef(env, l_focusOwnerPeer); - } - - if (isSameObject && !acceptDuplicates) { - return; - } - - focusList = focusListEnd = malloc(sizeof(FocusListElt)); - } - - focusListEnd->requestor = (*env)->NewWeakGlobalRef(env, target); - focusListEnd->next = NULL; -} - -/* - * client_data is MComponentPeer instance - */ -void -awt_post_java_mouse_event(XtPointer client_data, jint id, XEvent* event, - Time when, jint modifiers, jint x, jint y, - jint xAbs, jint yAbs, - jint clickcount, - Boolean popuptrigger, - jint wheelAmt, jint button) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject peer = (jobject) client_data; - jobject target; - - static jclass classMouseEvent = NULL; - static jclass classMouseWheelEvent = NULL; - - static jmethodID mid = NULL; - static jmethodID wheelmid = NULL; - - char *clsName = "java/awt/event/MouseEvent"; - char *wheelClsName = "java/awt/event/MouseWheelEvent"; - - jobject hEvent; - jobject sysClass; - jlong jWhen; - - if ((*env)->PushLocalFrame(env, 16) < 0) - return; - - target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); - - if (classMouseEvent == NULL) { - sysClass = (*env)->FindClass(env, clsName); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - classMouseEvent = (*env)->NewGlobalRef(env, sysClass); - mid = (*env)->GetMethodID(env, classMouseEvent - ,"" - ,"(Ljava/awt/Component;IJIIIIIIZI)V"); - } - if (JNU_IsNull(env, classMouseEvent) || mid == 0) { - JNU_ThrowClassNotFoundException(env, clsName); - (*env)->PopLocalFrame(env, 0); - return; - } - } - - if (id == java_awt_event_MouseEvent_MOUSE_WHEEL && - classMouseWheelEvent == NULL) { - sysClass = (*env)->FindClass(env, wheelClsName); - if (sysClass != NULL) { - /* Make this class 'sticky', we don't want it GC'd */ - classMouseWheelEvent = (*env)->NewGlobalRef(env, sysClass); - wheelmid = (*env)->GetMethodID(env, classMouseWheelEvent, - "", - "(Ljava/awt/Component;IJIIIIIIZIII)V"); - } - if (JNU_IsNull(env, classMouseWheelEvent) || wheelmid == 0) { - JNU_ThrowClassNotFoundException(env, wheelClsName); - (*env)->PopLocalFrame(env, 0); - return; - } - } - - jWhen = awt_util_nowMillisUTC_offset(when); /* convert Time to UTC */ - - if (id == java_awt_event_MouseEvent_MOUSE_WHEEL) { - hEvent = (*env)->NewObject(env, classMouseWheelEvent, wheelmid, - target, id, jWhen, modifiers, - x, y, - xAbs, yAbs, - clickcount, popuptrigger, - /* Linux has no API for setting how a Component - * should scroll in response to the mouse wheel, - * so we have to make up our own. - * The default behavior on Windows is 3 lines of - * text, so we use that to match. - */ - java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL, - 3, - wheelAmt); - } - else { - hEvent = (*env)->NewObject(env, classMouseEvent, mid, - target, id, jWhen, modifiers, - x, y, - xAbs, yAbs, - clickcount, popuptrigger, button); - } - - - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - if (JNU_IsNull(env, hEvent)) { - JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); - (*env)->PopLocalFrame(env, 0); - return; - } - awt_copyXEventToAWTEvent(env, event, hEvent); - JNU_CallMethodByName(env, NULL, peer, - "postEvent", "(Ljava/awt/AWTEvent;)V", hEvent); - if ((*env)->ExceptionOccurred(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - (*env)->PopLocalFrame(env, 0); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/cursor.c --- a/jdk/src/solaris/native/sun/awt/cursor.c Thu Sep 11 11:25:48 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 1997-2003 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include "awt_p.h" -#include "java_awt_Cursor.h" -#include "awt_Cursor.h" -#include "sun_awt_motif_MCustomCursor.h" - -#include "jni.h" -#include "jni_util.h" - -extern struct CursorIDs cursorIDs; -static jfieldID widthID; -static jfieldID heightID; - -/* - * Class: sun_awt_motif_MCustomCursor - * Method: cacheInit - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCustomCursor_cacheInit - (JNIEnv *env, jclass cls) -{ - jclass clsDimension = (*env)->FindClass(env, "java/awt/Dimension"); - widthID = (*env)->GetFieldID(env, clsDimension, "width", "I"); - heightID = (*env)->GetFieldID(env, clsDimension, "height", "I"); -} - -/* - * Class: sun_awt_motif_MCustomCursor - * Method: queryBestCursor - * Signature: (Ljava/awt/Dimension;)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCustomCursor_queryBestCursor - (JNIEnv *env, jclass cls, jobject dimension) -{ - Window root; - uint32_t width, height; - - AWT_LOCK(); - root = RootWindow(awt_display, DefaultScreen(awt_display)); - XQueryBestCursor(awt_display, root, - (*env)->GetIntField(env, dimension, widthID), - (*env)->GetIntField(env, dimension, heightID), - &width, &height); - (*env)->SetIntField(env, dimension, widthID, (int32_t) width); - (*env)->SetIntField(env, dimension, heightID, (int32_t) height); - AWT_UNLOCK(); -} - -/* - * Class: sun_awt_motif_MCustomCursor - * Method: createCursor - * Signature: ([B[BIIII)V - */ -JNIEXPORT void JNICALL Java_sun_awt_motif_MCustomCursor_createCursor - (JNIEnv *env , jobject this, jbyteArray xorMask, jbyteArray andMask, - jint width, jint height, jint fc, jint bc, jint xHotSpot, jint yHotSpot) -{ - Cursor cursor; - char *sourceBits, *maskBits; - Window root; - Pixmap source, mask; - XColor fcolor, bcolor; - AwtGraphicsConfigDataPtr defaultConfig = - getDefaultConfig(DefaultScreen(awt_display)); - - AWT_LOCK(); - - root = RootWindow(awt_display, DefaultScreen(awt_display)); - fcolor.flags = DoRed | DoGreen | DoBlue; - fcolor.red = ((fc >> 16) & 0x000000ff) << 8; - fcolor.green = ((fc >> 8) & 0x000000ff) << 8; - fcolor.blue = ((fc >> 0) & 0x000000ff) << 8; - XAllocColor(awt_display, defaultConfig->awt_cmap, &fcolor); - bcolor.flags = DoRed | DoGreen | DoBlue; - bcolor.red = ((bc >> 16) & 0x000000ff) << 8; - bcolor.green = ((bc >> 8) & 0x000000ff) << 8; - bcolor.blue = ((bc >> 0) & 0x000000ff) << 8; - XAllocColor(awt_display, defaultConfig->awt_cmap, &bcolor); - - /* Create source pixmap. */ - sourceBits = (char *)(*env)->GetPrimitiveArrayCritical(env, xorMask, NULL); - source = XCreateBitmapFromData(awt_display, root, sourceBits, - width, height); - - /* Create mask pixmap */ - maskBits = (char *)(*env)->GetPrimitiveArrayCritical(env, andMask, NULL); - mask = XCreateBitmapFromData(awt_display, root, maskBits, - width, height); - - /* Create cursor */ - cursor = XCreatePixmapCursor(awt_display, source, mask, &fcolor, &bcolor, - xHotSpot, yHotSpot); - - /* Free resources */ - XFreePixmap(awt_display, source); - XFreePixmap(awt_display, mask); - - (*env)->ReleasePrimitiveArrayCritical(env, xorMask, sourceBits, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, andMask, maskBits, JNI_ABORT); - - JNU_SetLongFieldFromPtr(env, this, cursorIDs.pData, cursor); - - AWT_FLUSH_UNLOCK(); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/initIDs.c --- a/jdk/src/solaris/native/sun/awt/initIDs.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/initIDs.c Wed Jul 05 16:41:30 2017 +0200 @@ -26,7 +26,7 @@ #include "java_awt_Color.h" #include "java_awt_Dimension.h" #include "java_awt_MenuBar.h" -#include "java_awt_Label.h" +//#include "java_awt_Label.h" #include "java_awt_FontMetrics.h" #include "java_awt_event_MouseEvent.h" #include "java_awt_Rectangle.h" diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/multi_font.c --- a/jdk/src/solaris/native/sun/awt/multi_font.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/multi_font.c Wed Jul 05 16:41:30 2017 +0200 @@ -52,8 +52,8 @@ extern XFontStruct *loadFont(Display *, char *, int32_t); extern struct FontIDs fontIDs; -extern struct MComponentPeerIDs mComponentPeerIDs; -extern struct MMenuItemPeerIDs mMenuItemPeerIDs; +//extern struct MComponentPeerIDs mComponentPeerIDs; +//extern struct MMenuItemPeerIDs mMenuItemPeerIDs; extern struct PlatformFontIDs platformFontIDs; extern struct MFontPeerIDs mFontPeerIDs; @@ -151,8 +151,8 @@ struct gRefStruct *temp; gRef = (jobject) - JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.jniGlobalRef); - JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.jniGlobalRef, NULL); + //JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.jniGlobalRef); + //JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.jniGlobalRef, NULL); /* * Verra handy for tracking down race conditions. If you diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c --- a/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c Wed Jul 05 16:41:30 2017 +0200 @@ -40,6 +40,7 @@ #include #include #include +#include static Bool shapeSupported; static int shapeEventBase, shapeErrorBase; @@ -534,40 +535,34 @@ SplashEventLoop(Splash * splash) { /* Different from win32 implementation - this loop - uses select timeouts instead of a timer */ + uses poll timeouts instead of a timer */ /* we should have splash _locked_ on entry!!! */ int xconn = XConnectionNumber(splash->display); while (1) { + struct pollfd pfd[2]; + int timeout = -1; int ctl = splash->controlpipe[0]; - fd_set fds[2]; - int n = 0; - struct timeval tv, *ptv; int rc; - int time; int pipes_empty; - FD_ZERO(fds); - FD_SET(xconn, fds); - if (xconn+1 > n) - n = xconn+1; - FD_SET(ctl, fds); - if (ctl+1 > n) - n = ctl+1; + pfd[0].fd = xconn; + pfd[0].events = POLLIN | POLLPRI; + + pfd[1].fd = ctl; + pfd[1].events = POLLIN | POLLPRI; + errno = 0; if (splash->isVisible>0 && SplashIsStillLooping(splash)) { - time = splash->time + splash->frames[splash->currentFrame].delay + timeout = splash->time + splash->frames[splash->currentFrame].delay - SplashTime(); - if (time < 0) - time = 0; - msec2timeval(time, &tv); - ptv = &tv; - } else { - ptv = NULL; + if (timeout < 0) { + timeout = 0; + } } SplashUnlock(splash); - rc = select(n, fds, NULL, NULL, ptv); + rc = poll(pfd, 2, timeout); SplashLock(splash); if (splash->isVisible>0 && SplashTime() >= splash->time + splash->frames[splash->currentFrame].delay) { diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c --- a/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -198,7 +198,7 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, + jboolean preferIPv6, jobject fdo, jlong address, jint len, jobject dest) { jint fd = fdval(env, fdo); @@ -215,7 +215,7 @@ if (NET_InetAddressToSockaddr(env, destAddress, destPort, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c --- a/jdk/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c Wed Jul 05 16:41:30 2017 +0200 @@ -48,10 +48,18 @@ __uint64_t u64; } epoll_data_t; + +/* x86-64 has same alignment as 32-bit */ +#ifdef __x86_64__ +#define EPOLL_PACKED __attribute__((packed)) +#else +#define EPOLL_PACKED +#endif + struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ -} __attribute__ ((__packed__)); +} EPOLL_PACKED; #ifdef __cplusplus } @@ -143,6 +151,18 @@ return (jint)rlp.rlim_max; } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this) +{ + return sizeof(struct epoll_event); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPollArrayWrapper_offsetofData(JNIEnv* env, jclass this) +{ + return offsetof(struct epoll_event, data); +} + JNIEXPORT void JNICALL Java_sun_nio_ch_EPollArrayWrapper_epollCtl(JNIEnv *env, jobject this, jint epfd, jint opcode, jint fd, jint events) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/FileKey.c --- a/jdk/src/solaris/native/sun/nio/ch/FileKey.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/FileKey.c Wed Jul 05 16:41:30 2017 +0200 @@ -33,12 +33,6 @@ static jfieldID key_st_dev; /* id for FileKey.st_dev */ static jfieldID key_st_ino; /* id for FileKey.st_ino */ -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while ((_result == -1) && (errno == EINTR)); \ -} while(0) - JNIEXPORT void JNICALL Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/Net.c --- a/jdk/src/solaris/native/sun/nio/ch/Net.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/Net.c Wed Jul 05 16:41:30 2017 +0200 @@ -37,17 +37,109 @@ #include "net_util.h" #include "net_util_md.h" #include "nio_util.h" -#include "java_net_SocketOptions.h" #include "nio.h" +/** + * Definitions for source-specific multicast to allow for building + * with older header files. + */ + +#ifdef __solaris__ + +#ifndef IP_BLOCK_SOURCE + +#define IP_BLOCK_SOURCE 0x15 +#define IP_UNBLOCK_SOURCE 0x16 +#define IP_ADD_SOURCE_MEMBERSHIP 0x17 +#define IP_DROP_SOURCE_MEMBERSHIP 0x18 + +#define MCAST_BLOCK_SOURCE 0x2b +#define MCAST_UNBLOCK_SOURCE 0x2c +#define MCAST_JOIN_SOURCE_GROUP 0x2d +#define MCAST_LEAVE_SOURCE_GROUP 0x2e + +#endif /* IP_BLOCK_SOURCE */ + +struct my_ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_sourceaddr; + struct in_addr imr_interface; +}; + +/* + * Use #pragma pack() construct to force 32-bit alignment on amd64. + */ +#if defined(amd64) +#pragma pack(4) +#endif + +struct my_group_source_req { + uint32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; + +#if defined(amd64) +#pragma pack() +#endif + +#endif /* __solaris__ */ + + #ifdef __linux__ -#include + +#ifndef IP_BLOCK_SOURCE + +#define IP_BLOCK_SOURCE 38 +#define IP_UNBLOCK_SOURCE 37 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 + +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 42 +#define MCAST_LEAVE_SOURCE_GROUP 45 + +#endif /* IP_BLOCK_SOURCE */ + +struct my_ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct my_group_source_req { + uint32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; -#define IPV6_MULTICAST_IF 17 -#ifndef SO_BSDCOMPAT -#define SO_BSDCOMPAT 14 -#endif -#endif +#endif /* __linux__ */ + + +#define COPY_INET6_ADDRESS(env, source, target) \ + (*env)->GetByteArrayRegion(env, source, 0, 16, target) + +/* + * Copy IPv6 group, interface index, and IPv6 source address + * into group_source_req structure. + */ +static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, + jbyteArray source, struct my_group_source_req* req) +{ + struct sockaddr_in6* sin6; + + req->gsr_interface = (uint32_t)index; + + sin6 = (struct sockaddr_in6*)&(req->gsr_group); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); + + sin6 = (struct sockaddr_in6*)&(req->gsr_source); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); +} + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) @@ -55,43 +147,61 @@ /* Here because Windows native code does need to init IDs */ } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) +{ + return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; +} + JNIEXPORT int JNICALL -Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream, - jboolean reuse) +Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, + jboolean stream, jboolean reuse) { int fd; + int type = (stream ? SOCK_STREAM : SOCK_DGRAM); + int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; -#ifdef AF_INET6 - if (ipv6_available()) - fd = socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - else -#endif /* AF_INET6 */ - fd = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - + fd = socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } if (reuse) { int arg = 1; - if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, - sizeof(arg)) < 0) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, + sizeof(arg)) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; } } +#ifdef __linux__ + /* By default, Linux uses the route default */ + if (domain == AF_INET6 && type == SOCK_DGRAM) { + int arg = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, + sizeof(arg)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; + } + } +#endif return fd; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk */ - jobject fdo, jobject ia, int port) +Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, int port) { SOCKADDR sa; int sa_len = SOCKADDR_LEN; int rv = 0; - if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return; } @@ -101,27 +211,27 @@ } } +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) +{ + if (listen(fdval(env, fdo), backlog) < 0) + handleSocketError(env, errno); +} + JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, - jobject fdo, jobject iao, jint port, - jint trafficClass) +Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, jint port) { SOCKADDR sa; int sa_len = SOCKADDR_LEN; int rv; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, + &sa_len, preferIPv6) != 0) + { return IOS_THROWN; } -#ifdef AF_INET6 -#if 0 - if (trafficClass != 0 && ipv6_available()) { /* ## FIX */ - NET_SetTrafficClass((struct sockaddr *)&sa, trafficClass); - } -#endif -#endif - rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); if (rv != 0) { if (errno == EINPROGRESS) { @@ -159,119 +269,79 @@ return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); } - -#ifdef NEEDED - -/* ## This is gross. We should generate platform-specific constant - * ## definitions into a .java file and use those directly. - */ - -static int -mapOption(JNIEnv *env, int opt, int *klevel, int *kopt) +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) { - - switch (opt) { - - case java_net_SocketOptions_IP_TOS: - *klevel = IPPROTO_IP; - *kopt = IP_TOS; - break; + int result; + struct linger linger; + u_char carg; + void *arg; + int arglen, n; - case java_net_SocketOptions_SO_BROADCAST: - case java_net_SocketOptions_SO_KEEPALIVE: - case java_net_SocketOptions_SO_LINGER: - case java_net_SocketOptions_SO_OOBINLINE: - case java_net_SocketOptions_SO_RCVBUF: - case java_net_SocketOptions_SO_REUSEADDR: - case java_net_SocketOptions_SO_SNDBUF: - *klevel = SOL_SOCKET; - break; + /* Option value is an int except for a few specific cases */ + + arg = (void *)&result; + arglen = sizeof(result); - case java_net_SocketOptions_TCP_NODELAY: - *klevel = IPPROTO_IP; - *kopt = TCP_NODELAY; - return 0; - - default: - JNU_ThrowByName(env, "java/lang/IllegalArgumentException", NULL); - return -1; + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { + arg = (void*)&carg; + arglen = sizeof(carg); } - switch (opt) { - - case java_net_SocketOptions_SO_BROADCAST: *kopt = SO_BROADCAST; break; - case java_net_SocketOptions_SO_KEEPALIVE: *kopt = SO_KEEPALIVE; break; - case java_net_SocketOptions_SO_LINGER: *kopt = SO_LINGER; break; - case java_net_SocketOptions_SO_OOBINLINE: *kopt = SO_OOBINLINE; break; - case java_net_SocketOptions_SO_RCVBUF: *kopt = SO_RCVBUF; break; - case java_net_SocketOptions_SO_REUSEADDR: *kopt = SO_REUSEADDR; break; - case java_net_SocketOptions_SO_SNDBUF: *kopt = SO_SNDBUF; break; - - default: - return -1; + if (level == SOL_SOCKET && opt == SO_LINGER) { + arg = (void *)&linger; + arglen = sizeof(linger); } - return 0; -} -#endif - - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt) -{ - int klevel, kopt; - int result; - struct linger linger; - void *arg; - int arglen; - - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return -1; + if (mayNeedConversion) { + n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); + } else { + n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); } - - if (opt == java_net_SocketOptions_SO_LINGER) { - arg = (void *)&linger; - arglen = sizeof(linger); - } else { - arg = (void *)&result; - arglen = sizeof(result); - } - - if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) { + if (n < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.getIntOption"); return -1; } - if (opt == java_net_SocketOptions_SO_LINGER) - return linger.l_onoff ? linger.l_linger : -1; - else - return result; + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) + { + return (jint)carg; + } + + if (level == SOL_SOCKET && opt == SO_LINGER) + return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; + + return (jint)result; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt, jint arg) +Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt, jint arg) { - int klevel, kopt; int result; struct linger linger; + u_char carg; void *parg; - int arglen; + int arglen, n; + + /* Option value is an int except for a few specific cases */ - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return; + parg = (void*)&arg; + arglen = sizeof(arg); + + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { + parg = (void*)&carg; + arglen = sizeof(carg); + carg = (u_char)arg; } - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { parg = (void *)&linger; arglen = sizeof(linger); if (arg >= 0) { @@ -281,19 +351,199 @@ linger.l_onoff = 0; linger.l_linger = 0; } - } else { - parg = (void *)&arg; - arglen = sizeof(arg); } - if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) { + if (mayNeedConversion) { + n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); + } else { + n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); + } + if (n < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.setIntOption"); } } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jint group, jint interf, jint source) +{ + struct ip_mreq mreq; + struct my_ip_mreq_source mreq_source; + int opt, n, optlen; + void* optval; + if (source == 0) { + mreq.imr_multiaddr.s_addr = htonl(group); + mreq.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + optval = (void*)&mreq; + optlen = sizeof(mreq); + } else { + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; + optval = (void*)&mreq_source; + optlen = sizeof(mreq_source); + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); + if (n < 0) { + if (join && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jint group, jint interf, jint source) +{ + struct my_ip_mreq_source mreq_source; + int n; + int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; + + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, + (void*)&mreq_source, sizeof(mreq_source)); + if (n < 0) { + if (block && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct ipv6_mreq mreq6; + struct my_group_source_req req; + int opt, n, optlen; + void* optval; + + if (source == NULL) { + COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = (int)index; + opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + optval = (void*)&mreq6; + optlen = sizeof(mreq6); + } else { +#ifdef __linux__ + /* Include-mode filtering broken on Linux at least to 2.6.24 */ + return IOS_UNAVAILABLE; +#else + initGroupSourceReq(env, group, index, source, &req); + opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; + optval = (void*)&req; + optlen = sizeof(req); +#endif + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); + if (n < 0) { + if (join && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct my_group_source_req req; + int n; + int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; + + initGroupSourceReq(env, group, index, source, &req); + + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, + (void*)&req, sizeof(req)); + if (n < 0) { + if (block && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + in.s_addr = htonl(interf); + + n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, + (void*)&(in.s_addr), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return ntohl(in.s_addr); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) +{ + int value = (jint)index; + int arglen = sizeof(value); + int n; + + n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, + (void*)&(index), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) +{ + int index; + int arglen = sizeof(index); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return (jint)index; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) +{ + int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : + (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; + if (shutdown(fdval(env, fdo), how) < 0) + handleSocketError(env, errno); +} /* Declared in nio_util.h */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c --- a/jdk/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -65,14 +65,6 @@ "(Ljava/net/InetAddress;I)V"); } -JNIEXPORT void JNICALL -Java_sun_nio_ch_ServerSocketChannelImpl_listen(JNIEnv *env, jclass cl, - jobject fdo, jint backlog) -{ - if (listen(fdval(env, fdo), backlog) < 0) - handleSocketError(env, errno); -} - JNIEXPORT jint JNICALL Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, jobject ssfdo, jobject newfdo, diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/SocketChannelImpl.c --- a/jdk/src/solaris/native/sun/nio/ch/SocketChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/SocketChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -35,10 +35,6 @@ #include #endif -#if defined(__solaris__) && !defined(_SOCKLEN_T) -typedef size_t socklen_t; /* New in SunOS 5.7, so need this for 5.6 */ -#endif - #include "jni.h" #include "jni_util.h" #include "net_util.h" @@ -88,12 +84,3 @@ } return 0; } - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl, - jobject fdo, jint how) -{ - if (shutdown(fdval(env, fdo), how) < 0) - handleSocketError(env, errno); -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/solaris/native/sun/nio/ch/nio_util.h --- a/jdk/src/solaris/native/sun/nio/ch/nio_util.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/nio_util.h Wed Jul 05 16:41:30 2017 +0200 @@ -27,8 +27,15 @@ #include "jni_util.h" #include "jvm.h" #include "jlong.h" +#include #include +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + /* NIO utility procedures */ diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/bin/java_md.c --- a/jdk/src/windows/bin/java_md.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/bin/java_md.c Wed Jul 05 16:41:30 2017 +0200 @@ -105,26 +105,26 @@ } } if (running != wanted) { - ReportErrorMessage(JRE_ERROR2, wanted); + JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { - ReportErrorMessage(JRE_ERROR1); + JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { - ReportErrorMessage(CFG_ERROR7); + JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { - ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); + JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* If we got here, jvmpath has been correctly initialized. */ @@ -160,7 +160,7 @@ goto found; } - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -212,7 +212,7 @@ JLI_TraceLauncher("CRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { - ReportErrorMessage(DLL_ERROR4, crtpath); + JLI_ReportErrorMessage(DLL_ERROR4, crtpath); return JNI_FALSE; } } @@ -220,7 +220,7 @@ /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { - ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); + JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); return JNI_FALSE; } @@ -230,7 +230,7 @@ ifn->GetDefaultJavaVMInitArgs = (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { - ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); + JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); return JNI_FALSE; } @@ -292,19 +292,19 @@ /* Find the current version of the JRE */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) { - ReportErrorMessage(REG_ERROR1, JRE_KEY); + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY); return JNI_FALSE; } if (!GetStringFromRegistry(key, "CurrentVersion", version, sizeof(version))) { - ReportErrorMessage(REG_ERROR2, JRE_KEY); + JLI_ReportErrorMessage(REG_ERROR2, JRE_KEY); RegCloseKey(key); return JNI_FALSE; } if (JLI_StrCmp(version, GetDotVersion()) != 0) { - ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() + JLI_ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() ); RegCloseKey(key); return JNI_FALSE; @@ -312,13 +312,13 @@ /* Find directory where the current version is installed. */ if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { - ReportErrorMessage(REG_ERROR1, JRE_KEY, version); + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY, version); RegCloseKey(key); return JNI_FALSE; } if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) { - ReportErrorMessage(REG_ERROR4, JRE_KEY, version); + JLI_ReportErrorMessage(REG_ERROR4, JRE_KEY, version); RegCloseKey(key); RegCloseKey(subkey); return JNI_FALSE; @@ -370,7 +370,7 @@ } void -ReportErrorMessage(const char* fmt, ...) { +JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl,fmt); @@ -394,12 +394,12 @@ } /* - * Just like ReportErrorMessage, except that it concatenates the system + * Just like JLI_ReportErrorMessage, except that it concatenates the system * error message if any, its upto the calling routine to correctly * format the separation of the messages. */ void -ReportErrorMessageSys(const char *fmt, ...) +JLI_ReportErrorMessageSys(const char *fmt, ...) { va_list vl; @@ -462,7 +462,7 @@ va_end(vl); } -void ReportExceptionDescription(JNIEnv * env) { +void JLI_ReportExceptionDescription(JNIEnv * env) { if (IsJavaw()) { /* * This code should be replaced by code which opens a window with @@ -733,7 +733,7 @@ */ len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); if (len == 0 || len > MAXPATHLEN) { - ReportErrorMessageSys(JRE_ERROR9, progname); + JLI_ReportErrorMessageSys(JRE_ERROR9, progname); exit(1); } @@ -766,7 +766,7 @@ * If it weren't for this semantic flaw, the code below would be ... * * execv(path, argv); - * ReportErrorMessage("Error: Exec of %s failed\n", path); + * JLI_ReportErrorMessage("Error: Exec of %s failed\n", path); * exit(1); * * The incorrect exec semantics could be addressed by: @@ -876,7 +876,7 @@ (LPCTSTR)NULL, /* current directory */ (LPSTARTUPINFO)&si, /* (in) startup information */ (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ - ReportErrorMessageSys(SYS_ERROR1, path); + JLI_ReportErrorMessageSys(SYS_ERROR1, path); exit(1); } @@ -884,7 +884,7 @@ if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) exitCode = 1; } else { - ReportErrorMessage(SYS_ERROR2); + JLI_ReportErrorMessage(SYS_ERROR2); exitCode = 1; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/java/net/net_util_md.c --- a/jdk/src/windows/native/java/net/net_util_md.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/java/net/net_util_md.c Wed Jul 05 16:41:30 2017 +0200 @@ -889,7 +889,7 @@ return 0; } -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { if (him->sa_family == AF_INET6) { return ntohs(((struct sockaddr_in6*)him)->sin6_port); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c --- a/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -39,46 +39,9 @@ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ -static jfieldID ia_addrID; -static jfieldID ia_famID; static jclass isa_class; /* java.net.InetSocketAddress */ -static jclass ia_class; -static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */ -static jmethodID ia_ctorID; - -/* - * Returns JNI_TRUE if DatagramChannelImpl has already cached an - * InetAddress/port corresponding to the socket address. - */ -static jboolean isSenderCached(JNIEnv *env, jobject this, struct sockaddr_in *sa) { - jobject senderAddr; - - /* shouldn't happen until we have dual IPv4/IPv6 stack (post-XP ?) */ - if (sa->sin_family != AF_INET) { - return JNI_FALSE; - } +static jmethodID isa_ctorID; /* java.net.InetSocketAddress(InetAddress, int) */ - /* - * Compare source address to cached InetAddress - */ - senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); - if (senderAddr == NULL) { - return JNI_FALSE; - } - if ((jint)ntohl(sa->sin_addr.s_addr) != - (*env)->GetIntField(env, senderAddr, ia_addrID)) { - return JNI_FALSE; - } - - /* - * Compare source port to cached port - */ - if ((jint)ntohs(sa->sin_port) != - (*env)->GetIntField(env, this, dci_senderPortID)) { - return JNI_FALSE; - } - return JNI_TRUE; -} JNIEXPORT void JNICALL Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) @@ -99,32 +62,6 @@ "Ljava/net/InetAddress;"); dci_senderPortID = (*env)->GetFieldID(env, clazz, "cachedSenderPort", "I"); - clazz = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, clazz); - ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I"); - ia_famID = (*env)->GetFieldID(env, clazz, "family", "I"); - ia_ctorID = (*env)->GetMethodID(env, clazz, "", "()V"); -} - -/* - * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable - */ -__inline static jboolean supportPortUnreachable() { - static jboolean initDone; - static jboolean portUnreachableSupported; - - if (!initDone) { - OSVERSIONINFO ver; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 5) { - portUnreachableSupported = JNI_TRUE; - } else { - portUnreachableSupported = JNI_FALSE; - } - initDone = JNI_TRUE; - } - return portUnreachableSupported; } /* @@ -140,15 +77,8 @@ char buf[1]; fd_set tbl; struct timeval t = { 0, 0 }; - struct sockaddr_in rmtaddr; - int addrlen = sizeof(rmtaddr); - - /* - * A no-op if this OS doesn't support it. - */ - if (!supportPortUnreachable()) { - return JNI_FALSE; - } + SOCKETADDRESS sa; + int addrlen = sizeof(sa); /* * Peek at the queue to see if there is an ICMP port unreachable. If there @@ -161,7 +91,7 @@ break; } if (recvfrom(fd, buf, 1, MSG_PEEK, - (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) { + (struct sockaddr *)&sa, &addrlen) != SOCKET_ERROR) { break; } if (WSAGetLastError() != WSAECONNRESET) { @@ -169,7 +99,7 @@ break; } - recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen); + recvfrom(fd, buf, 1, 0, (struct sockaddr *)&sa, &addrlen); got_icmp = JNI_TRUE; } @@ -182,12 +112,12 @@ { jint fd = fdval(env, fdo); int rv = 0; - struct sockaddr_in psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len = sizeof(sa); - memset(&psa, 0, sa_len); + memset(&sa, 0, sa_len); - rv = connect((SOCKET)fd, (struct sockaddr *)&psa, sa_len); + rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { handleSocketError(env, WSAGetLastError()); } @@ -200,10 +130,11 @@ { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); - struct sockaddr_in psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len = sizeof(sa); BOOL retry = FALSE; jint n; + jobject senderAddr; do { retry = FALSE; @@ -211,7 +142,7 @@ (char *)buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, &sa_len); if (n == SOCKET_ERROR) { @@ -233,21 +164,30 @@ } } while (retry); - if (!isSenderCached(env, this, &psa)) { - int port = ntohs(psa.sin_port); - jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID); + /* + * If the source address and port match the cached address + * and port in DatagramChannelImpl then we don't need to + * create InetAddress and InetSocketAddress objects. + */ + senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); + if (senderAddr != NULL) { + if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa, + senderAddr)) { + senderAddr = NULL; + } else { + jint port = (*env)->GetIntField(env, this, dci_senderPortID); + if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) { + senderAddr = NULL; + } + } + } + if (senderAddr == NULL) { jobject isa = NULL; - - if (psa.sin_family != AF_INET) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", - "Protocol family unavailable"); - } + int port; + jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, + &port); if (ia != NULL) { - // populate InetAddress (assumes AF_INET) - (*env)->SetIntField(env, ia, ia_addrID, ntohl(psa.sin_addr.s_addr)); - - // create InetSocketAddress isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); } @@ -258,9 +198,8 @@ // update cachedSenderInetAddress/cachedSenderPort (*env)->SetObjectField(env, this, dci_senderAddrID, ia); - (*env)->SetIntField(env, this, dci_senderPortID, port); - - // update sender + (*env)->SetIntField(env, this, dci_senderPortID, + NET_GetPortFromSockaddr((struct sockaddr *)&sa)); (*env)->SetObjectField(env, this, dci_senderID, isa); } return n; @@ -268,21 +207,20 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, - jint len, jobject dest) + jboolean preferIPv6, jobject fdo, + jlong address, jint len, jobject dest) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); - SOCKETADDRESS psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len; jint rv = 0; jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); jint destPort = (*env)->GetIntField(env, dest, isa_portID); - if (NET_InetAddressToSockaddr(env, destAddress, destPort, - (struct sockaddr *)&psa, - &sa_len, JNI_FALSE) != 0) { + (struct sockaddr *)&sa, + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } @@ -290,7 +228,7 @@ buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/nio/ch/Net.c --- a/jdk/src/windows/native/sun/nio/ch/Net.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/nio/ch/Net.c Wed Jul 05 16:41:30 2017 +0200 @@ -36,51 +36,95 @@ #include "sun_nio_ch_Net.h" +/** + * Definitions to allow for building with older SDK include files. + */ -static jfieldID ia_addrID; -static jclass ia_class; -static jmethodID ia_ctorID; -static jfieldID ia_famID; +#ifndef MCAST_BLOCK_SOURCE + +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 45 +#define MCAST_LEAVE_SOURCE_GROUP 46 + +#endif /* MCAST_BLOCK_SOURCE */ -/************************************************************** - * static method to store field IDs in initializers +typedef struct my_ip_mreq_source { + IN_ADDR imr_multiaddr; + IN_ADDR imr_sourceaddr; + IN_ADDR imr_interface; +}; + +typedef struct my_group_source_req { + ULONG gsr_interface; + SOCKADDR_STORAGE gsr_group; + SOCKADDR_STORAGE gsr_source; +}; + +/** + * Copy IPv6 address as jbytearray to target */ +#define COPY_INET6_ADDRESS(env, source, target) \ + (*env)->GetByteArrayRegion(env, source, 0, 16, target) + + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { - clazz = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, clazz); - ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I"); - ia_famID = (*env)->GetFieldID(env, clazz, "family", "I"); - ia_ctorID = (*env)->GetMethodID(env, clazz, "", "()V"); + /* nothing to do */ } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) +{ + /* + * Return true if Windows Vista or newer, and IPv6 is configured + */ + OSVERSIONINFO ver; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx(&ver); + if ((ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && + (ver.dwMajorVersion >= 6) && ipv6_available()) + { + return JNI_TRUE; + } + return JNI_FALSE; +} JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream, - jboolean reuse) +Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, + jboolean stream, jboolean reuse) { SOCKET s; + int domain = (preferIPv6) ? AF_INET6 : AF_INET; - s = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); + s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); if (s != INVALID_SOCKET) { SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); + + /* IPV6_V6ONLY is true by default */ + if (domain == AF_INET6) { + int opt = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const char *)&opt, sizeof(opt)); + } } else { NET_ThrowNew(env, WSAGetLastError(), "socket"); } + return (jint)s; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, - jobject fdo, jobject iao, jint port) +Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, jint port) { SOCKETADDRESS sa; int rv; - int sa_len = sizeof(sa); + int sa_len; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return; } @@ -89,16 +133,25 @@ NET_ThrowNew(env, WSAGetLastError(), "bind"); } +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) +{ + if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "listen"); + } +} + + JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao, - jint port, jint trafficClass) +Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo, + jobject iao, jint port) { SOCKETADDRESS sa; int rv; - int sa_len = sizeof(sa); + int sa_len; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) { - return IOS_THROWN; + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { + return IOS_THROWN; } rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); @@ -116,7 +169,7 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) { - struct sockaddr_in sa; + SOCKETADDRESS sa; int sa_len = sizeof(sa); if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { @@ -127,50 +180,64 @@ NET_ThrowNew(env, error, "getsockname"); return IOS_THROWN; } - return (jint)ntohs(sa.sin_port); + return NET_GetPortFromSockaddr((struct sockaddr *)&sa); } JNIEXPORT jobject JNICALL Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) { - struct sockaddr_in sa; + SOCKETADDRESS sa; int sa_len = sizeof(sa); - jobject iao; + int port; if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return NULL; } - - iao = (*env)->NewObject(env, ia_class, ia_ctorID); - if (iao == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); - } else { - (*env)->SetIntField(env, iao, ia_addrID, ntohl(sa.sin_addr.s_addr)); - } - - return iao; + return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); } - JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt) +Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) { - int klevel, kopt; - int result; + SOCKETADDRESS sa; + int sa_len = sizeof(sa); + + if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + int error = WSAGetLastError(); + if (error == WSAEINVAL) { + return 0; + } + NET_ThrowNew(env, error, "getsockname"); + return IOS_THROWN; + } + return NET_GetPortFromSockaddr((struct sockaddr *)&sa); +} + +JNIEXPORT jobject JNICALL +Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) +{ + SOCKETADDRESS sa; + int sa_len = sizeof(sa); + int port; + + if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + NET_ThrowNew(env, WSAGetLastError(), "getsockname"); + return NULL; + } + return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) +{ + int result = 0; struct linger linger; char *arg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return IOS_THROWN; - } - - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { arg = (char *)&linger; arglen = sizeof(linger); } else { @@ -178,34 +245,40 @@ arglen = sizeof(result); } - if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption"); + /** + * HACK: IP_TOS is deprecated on Windows and querying the option + * returns a protocol error. NET_GetSockOpt handles this and uses + * a fallback mechanism. + */ + if (level == IPPROTO_IP && opt == IP_TOS) { + mayNeedConversion = JNI_TRUE; + } + + if (mayNeedConversion) { + n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); + } else { + n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); + } + if (n < 0) { + handleSocketError(env, WSAGetLastError()); return IOS_THROWN; } - if (opt == java_net_SocketOptions_SO_LINGER) + if (level == SOL_SOCKET && opt == SO_LINGER) return linger.l_onoff ? linger.l_linger : -1; else return result; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt, jint arg) +Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt, jint arg) { - int klevel, kopt; struct linger linger; char *parg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return; - } - - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { parg = (char *)&linger; arglen = sizeof(linger); if (arg >= 0) { @@ -220,7 +293,200 @@ arglen = sizeof(arg); } - if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption"); + if (mayNeedConversion) { + n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); + } else { + n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); + } + if (n < 0) + handleSocketError(env, WSAGetLastError()); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jint group, jint interf, jint source) +{ + struct ip_mreq mreq; + struct my_ip_mreq_source mreq_source; + int opt, n, optlen; + void* optval; + + if (source == 0) { + mreq.imr_multiaddr.s_addr = htonl(group); + mreq.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + optval = (void*)&mreq; + optlen = sizeof(mreq); + } else { + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; + optval = (void*)&mreq_source; + optlen = sizeof(mreq_source); + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); + if (n < 0) { + if (join && (WSAGetLastError() == WSAENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, WSAGetLastError()); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jint group, jint interf, jint source) +{ + struct my_ip_mreq_source mreq_source; + int n; + int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; + + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, + (void*)&mreq_source, sizeof(mreq_source)); + if (n < 0) { + if (block && (WSAGetLastError() == WSAENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, WSAGetLastError()); + } + return 0; +} + +/** + * Call setsockopt with a IPPROTO_IPV6 level socket option + * and a group_source_req structure as the option value. The + * given IPv6 group, interface index, and IPv6 source address + * are copied into the structure. + */ +static int setGroupSourceReqOption(JNIEnv* env, + jobject fdo, + int opt, + jbyteArray group, + jint index, + jbyteArray source) +{ + struct my_group_source_req req; + struct sockaddr_in6* sin6; + + req.gsr_interface = (ULONG)index; + + sin6 = (struct sockaddr_in6*)&(req.gsr_group); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); + + sin6 = (struct sockaddr_in6*)&(req.gsr_source); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); + + return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req)); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct ipv6_mreq mreq6; + int n; + + if (source == NULL) { + int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = (int)index; + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, + (void*)&mreq6, sizeof(mreq6)); + } else { + int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; + n = setGroupSourceReqOption(env, fdo, opt, group, index, source); + } + + if (n < 0) { + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; + int n = setGroupSourceReqOption(env, fdo, opt, group, index, source); + if (n < 0) { + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + in.s_addr = htonl(interf); + + n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, + (void*)&(in.s_addr), arglen); + if (n < 0) { + handleSocketError(env, WSAGetLastError()); } } + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); + if (n < 0) { + handleSocketError(env, WSAGetLastError()); + return IOS_THROWN; + } + return ntohl(in.s_addr); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) +{ + int value = (jint)index; + int arglen = sizeof(value); + int n; + + n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, + (void*)&(index), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) +{ + int index; + int arglen = sizeof(index); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return (jint)index; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) { + int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE : + (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH; + if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "shutdown"); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c --- a/jdk/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -46,10 +46,6 @@ static jfieldID fd_fdID; /* java.io.FileDescriptor.fd */ static jclass isa_class; /* java.net.InetSocketAddress */ static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ -static jclass ia_class; /* java.net.InetAddress */ -static jmethodID ia_ctorID; /* InetAddress() */ -static jfieldID ia_addrID; /* java.net.InetAddress.address */ -static jfieldID ia_famID; /* java.net.InetAddress.family */ /************************************************************** @@ -66,12 +62,6 @@ isa_class = (*env)->NewGlobalRef(env, cls); isa_ctorID = (*env)->GetMethodID(env, cls, "", "(Ljava/net/InetAddress;I)V"); - - cls = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, cls); - ia_ctorID = (*env)->GetMethodID(env, cls, "","()V"); - ia_addrID = (*env)->GetFieldID(env, cls, "address", "I"); - ia_famID = (*env)->GetFieldID(env, cls, "family", "I"); } JNIEXPORT void JNICALL @@ -90,8 +80,9 @@ { jint ssfd = (*env)->GetIntField(env, ssfdo, fd_fdID); jint newfd; - struct sockaddr_in sa; - jobject remote_ia = 0; + SOCKETADDRESS sa; + jobject remote_ia; + int remote_port; jobject isa; jobject ia; int addrlen = sizeof(sa); @@ -106,14 +97,13 @@ JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); return IOS_THROWN; } + (*env)->SetIntField(env, newfdo, fd_fdID, newfd); + remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); - ia = (*env)->NewObject(env, ia_class, ia_ctorID); - (*env)->SetIntField(env, ia, ia_addrID, ntohl(sa.sin_addr.s_addr)); - (*env)->SetIntField(env, ia, ia_famID, sa.sin_family); + isa = (*env)->NewObject(env, isa_class, isa_ctorID, + remote_ia, remote_port); + (*env)->SetObjectArrayElement(env, isaa, 0, isa); - isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, - ntohs(sa.sin_port)); - (*env)->SetObjectArrayElement(env, isaa, 0, isa); return 1; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/nio/ch/SocketChannelImpl.c --- a/jdk/src/windows/native/sun/nio/ch/SocketChannelImpl.c Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/nio/ch/SocketChannelImpl.c Wed Jul 05 16:41:30 2017 +0200 @@ -139,12 +139,3 @@ return 0; } - -JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl, - jobject fdo, jint how) -{ - if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "shutdown"); - } -} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/ComCtl32Util.cpp --- a/jdk/src/windows/native/sun/windows/ComCtl32Util.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/ComCtl32Util.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -49,6 +49,9 @@ m_bNewSubclassing = (m_lpfnSetWindowSubclass != NULL) && (m_lpfnRemoveWindowSubclass != NULL) && (m_lpfnDefSubclassProc != NULL); + + fn_InitCommonControlsEx = (ComCtl32Util::InitCommonControlsExType)::GetProcAddress(hModComCtl32, "InitCommonControlsEx"); + InitCommonControls(); } } } @@ -108,3 +111,15 @@ CATCH_BAD_ALLOC_RET(0); } + +void ComCtl32Util::InitCommonControls() +{ + if (fn_InitCommonControlsEx == NULL) { + return; + } + + INITCOMMONCONTROLSEX iccex; + memset(&iccex, 0, sizeof(INITCOMMONCONTROLSEX)); + iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); + fn_InitCommonControlsEx(&iccex); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/ComCtl32Util.h --- a/jdk/src/windows/native/sun/windows/ComCtl32Util.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/ComCtl32Util.h Wed Jul 05 16:41:30 2017 +0200 @@ -25,6 +25,8 @@ #include "awt_Component.h" +#include + #ifndef _COMCTL32UTIL_H #define _COMCTL32UTIL_H @@ -81,6 +83,11 @@ PFNREMOVEWINDOWSUBCLASS m_lpfnRemoveWindowSubclass; PFNDEFSUBCLASSPROC m_lpfnDefSubclassProc; + typedef BOOL (WINAPI * InitCommonControlsExType)(const LPINITCOMMONCONTROLSEX lpInitCtrls); + InitCommonControlsExType fn_InitCommonControlsEx; + + void InitCommonControls(); + BOOL m_bNewSubclassing; // comctl32.dll version 6 window proc diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/awt_Container.cpp --- a/jdk/src/windows/native/sun/windows/awt_Container.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Container.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2000 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 @@ -30,8 +30,6 @@ * AwtContainer fields */ -jfieldID AwtContainer::ncomponentsID; -jfieldID AwtContainer::componentID; jfieldID AwtContainer::layoutMgrID; jmethodID AwtContainer::findComponentAtMID; @@ -45,18 +43,12 @@ Java_java_awt_Container_initIDs(JNIEnv *env, jclass cls) { TRY; - AwtContainer::ncomponentsID = env->GetFieldID(cls, "ncomponents", "I"); - AwtContainer::componentID = - env->GetFieldID(cls, "component", "[Ljava/awt/Component;"); - AwtContainer::layoutMgrID = env->GetFieldID(cls, "layoutMgr", "Ljava/awt/LayoutManager;"); AwtContainer::findComponentAtMID = env->GetMethodID(cls, "findComponentAt", "(IIZ)Ljava/awt/Component;"); - DASSERT(AwtContainer::ncomponentsID != NULL); - DASSERT(AwtContainer::componentID != NULL); DASSERT(AwtContainer::layoutMgrID != NULL); DASSERT(AwtContainer::findComponentAtMID); diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/awt_Container.h --- a/jdk/src/windows/native/sun/windows/awt_Container.h Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Container.h Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1998-1999 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 @@ -37,8 +37,6 @@ public: /* java.awt.Container field ids */ - static jfieldID ncomponentsID; - static jfieldID componentID; static jfieldID layoutMgrID; static jmethodID findComponentAtMID; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/awt_TextArea.cpp --- a/jdk/src/windows/native/sun/windows/awt_TextArea.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_TextArea.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -209,15 +209,13 @@ void AwtTextArea::EditSetSel(CHARRANGE &cr) { // Fix for 5003402: added restoring/hiding selection to enable automatic scrolling - LockWindowUpdate(GetHWnd()); SendMessage(EM_HIDESELECTION, FALSE, TRUE); SendMessage(EM_EXSETSEL, 0, reinterpret_cast(&cr)); SendMessage(EM_HIDESELECTION, TRUE, TRUE); - // 6417581: LockWindowUpdate doesn't force expected drawing + // 6417581: force expected drawing if (IS_WINVISTA && cr.cpMin == cr.cpMax) { ::InvalidateRect(GetHWnd(), NULL, TRUE); } - LockWindowUpdate(NULL); } void AwtTextArea::EditGetSel(CHARRANGE &cr) { @@ -993,12 +991,10 @@ c->CheckLineSeparator(buffer); c->RemoveCR(buffer); // Fix for 5003402: added restoring/hiding selection to enable automatic scrolling - LockWindowUpdate(c->GetHWnd()); c->SendMessage(EM_HIDESELECTION, FALSE, TRUE); c->SendMessageW(EM_SETSEL, start, end); c->SendMessageW(EM_REPLACESEL, FALSE, (LPARAM)buffer); c->SendMessage(EM_HIDESELECTION, TRUE, TRUE); - LockWindowUpdate(NULL); delete[] buffer; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp --- a/jdk/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp Wed Jul 05 16:41:30 2017 +0200 @@ -1021,6 +1021,10 @@ // with the WWindowPeer object HWND hWnd = window->GetHWnd(); + jobject target = env->GetObjectField(windowPeer, AwtObject::targetID); + jboolean alwaysOnTop = JNU_GetFieldByName(env, NULL, target, "alwaysOnTop", "Z").z; + env->DeleteLocalRef(target); + if (!::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE)) { @@ -1029,6 +1033,9 @@ ::GetLastError()); } + // We should restore alwaysOnTop state as it's anyway dropped here + Java_sun_awt_windows_WWindowPeer_setAlwaysOnTopNative(env, windowPeer, alwaysOnTop); + CATCH_BAD_ALLOC; } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/com/sun/tools/extcheck/TestExtcheckArgs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/tools/extcheck/TestExtcheckArgs.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6356642 + * @summary Verify that extcheck exits appropriately when invalid args are given. + * @run shell TestExtcheckArgs.sh + * @author Dave Bristor + */ + +import java.io.File; +import com.sun.tools.extcheck.Main; + +/* + * Test extcheck by using Runtime.exec instead of invoking + * com.sun.tools.extcheck.Main.main, since the latter does its own + * System.exit under the conditions checked here. + */ +public class TestExtcheckArgs { + public static void realMain(String[] args) throws Throwable { + String testJar = System.getenv("TESTJAVA") + File.separator + + "lib" + File.separator + "jconsole.jar"; + + verify(new String[] { + }, Main.INSUFFICIENT); + verify(new String[] { + "-verbose" + }, Main.MISSING); + verify(new String[] { + "-verbose", + "foo" + }, Main.DOES_NOT_EXIST); + verify(new String[] { + testJar, + "bar" + }, Main.EXTRA); + verify(new String[] { + "-verbose", + testJar, + "bar" + }, Main.EXTRA); + } + + static void verify(String[] args, String expected) throws Throwable { + try { + Main.realMain(args); + fail(); + } catch (Exception ex) { + if (ex.getMessage().startsWith(expected)) { + pass(); + } else { + fail("Unexpected message: " + ex.getMessage()); + } + } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static boolean pass() {passed++; return true;} + static boolean fail() {failed++; Thread.dumpStack(); return false;} + static boolean fail(String msg) {System.out.println(msg); return fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static boolean equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) return pass(); + else return fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/com/sun/tools/extcheck/TestExtcheckArgs.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/tools/extcheck/TestExtcheckArgs.sh Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,47 @@ +#! /bin/sh + +# +# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +if [ "x$TESTJAVA" = x ]; then + TESTJAVA=$1; shift + TESTCLASSES=. + TESTSRC=. +fi +export TESTJAVA + +case "`uname`" in Windows*|CYGWIN* ) PS=';';; *) PS=':';; esac + +${TESTJAVA}/bin/javac -d ${TESTCLASSES} -classpath ${TESTJAVA}/lib/tools.jar${PS}${TESTCLASSES} ${TESTSRC}/TestExtcheckArgs.java +rc=$? +if [ $rc != 0 ]; then + echo Compilation failure with exit status $rc + exit $rc +fi + +${TESTJAVA}/bin/java -classpath ${TESTJAVA}/lib/tools.jar${PS}${TESTCLASSES} TestExtcheckArgs +rc=$? +if [ $rc != 0 ]; then + echo Execution failure with exit status $rc + exit $rc +fi diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/Container/CheckZOrderChange/CheckZOrderChange.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Container/CheckZOrderChange/CheckZOrderChange.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,48 @@ +/* + @test %I% %E% + @bug 2161766 + @summary Component is missing after changing the z-order of the component & focus is not transfered in + @author Andrei Dmitriev : area=awt.container + @run main CheckZOrderChange +*/ +import java.awt.*; +import java.awt.event.*; + +public class CheckZOrderChange { + + private static Button content[] = new Button[]{new Button("Button 1"), new Button("Button 2"), new Button("Button 3"), new Button("Button 4")}; + private static Frame frame; + + public static void main(String[] args) { + + frame = new Frame("Test Frame"); + frame.setLayout(new FlowLayout()); + + for (Button b: content){ + frame.add(b); + } + + frame.setSize(300, 300); + frame.setVisible(true); + + /* INITIAL ZORDERS ARE*/ + for (Button b: content){ + System.out.println("frame.getComponentZOrder("+ b +") = " + frame.getComponentZOrder(b)); + } + + //Change the Z Order + frame.setComponentZOrder(content[0], 2); + System.out.println("ZOrder of button1 changed to 2"); + + if (frame.getComponentZOrder(content[0]) != 2 || + frame.getComponentZOrder(content[1]) != 0 || + frame.getComponentZOrder(content[2]) != 1 || + frame.getComponentZOrder(content[3]) != 3) + { + for (Button b: content){ + System.out.println("frame.getComponentZOrder("+ b +") = " + frame.getComponentZOrder(b)); + } + throw new RuntimeException("TEST FAILED: getComponentZOrder did not return the correct value"); + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 4685768 + @summary Tests that auto-transfering focus doesn't stuck on a disabled component. + @author Anton Tarasov: area=awt.focus + @library ../../regtesthelpers + @build Util + @run main NoAutotransferToDisabledCompTest +*/ + +import java.awt.Robot; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.applet.Applet; +import test.java.awt.regtesthelpers.Util; + +public class NoAutotransferToDisabledCompTest extends Applet { + Robot robot; + JFrame frame = new JFrame("Frame"); + JButton b0 = new JButton("b0"); + JButton b1 = new JButton("b1"); + JButton b2 = new JButton("b2"); + + public static void main(String[] args) { + NoAutotransferToDisabledCompTest app = new NoAutotransferToDisabledCompTest(); + app.init(); + app.start(); + } + + public void init() { + robot = Util.createRobot(); + frame.add(b0); + frame.add(b1); + frame.add(b2); + frame.setLayout(new FlowLayout()); + frame.pack(); + + b1.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + b1.setEnabled(false); + b2.setEnabled(false); + } + }); + } + + public void start() { + Util.showWindowWait(frame); + + // Request focus on b1. + if (!Util.focusComponent(b1, 2000)) { + throw new TestErrorException("couldn't focus " + b1); + } + + // Activate b1. + robot.keyPress(KeyEvent.VK_SPACE); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_SPACE); + Util.waitForIdle(robot); + + // Check that focus has been transfered to b0. + if (!b0.hasFocus()) { + throw new TestFailedException("focus wasn't auto-transfered properly!"); + } + System.out.println("Test passed."); + } +} + +/** + * Thrown when the behavior being verified is found wrong. + */ +class TestFailedException extends RuntimeException { + TestFailedException(String msg) { + super("Test failed: " + msg); + } +} + +/** + * Thrown when an error not related to the behavior being verified is encountered. + */ +class TestErrorException extends RuntimeException { + TestErrorException(String msg) { + super("Unexpected error: " + msg); + } +} + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/Focus/RequestFocusToDisabledCompTest/RequestFocusToDisabledCompTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Focus/RequestFocusToDisabledCompTest/RequestFocusToDisabledCompTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 4685768 + @summary Tests that it's possible to manually request focus on a disabled component. + @author Anton Tarasov: area=awt.focus + @library ../../regtesthelpers + @build Util + @run main RequestFocusToDisabledCompTest +*/ + +import java.awt.Robot; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.applet.Applet; +import test.java.awt.regtesthelpers.Util; + +public class RequestFocusToDisabledCompTest extends Applet { + Robot robot; + JFrame frame = new JFrame("Frame"); + JButton b0 = new JButton("b0"); + JButton b1 = new JButton("b1"); + + public static void main(String[] args) { + RequestFocusToDisabledCompTest app = new RequestFocusToDisabledCompTest(); + app.init(); + app.start(); + } + + public void init() { + robot = Util.createRobot(); + frame.add(b0); + frame.add(b1); + frame.setLayout(new FlowLayout()); + frame.pack(); + + b1.setEnabled(false); + } + + public void start() { + Util.showWindowWait(frame); + + if (!b0.hasFocus()) { + // Request focus on b0. + if (!Util.focusComponent(b0, 2000)) { + throw new TestErrorException("couldn't focus " + b0); + } + } + + // Try to request focus on b1. + if (!Util.focusComponent(b1, 2000)) { + throw new TestFailedException("focus wasn't requested on disabled " + b1); + } + System.out.println("Test passed."); + } +} + +/** + * Thrown when the behavior being verified is found wrong. + */ +class TestFailedException extends RuntimeException { + TestFailedException(String msg) { + super("Test failed: " + msg); + } +} + +/** + * Thrown when an error not related to the behavior being verified is encountered. + */ +class TestErrorException extends RuntimeException { + TestErrorException(String msg) { + super("Unexpected error: " + msg); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/Mixing/Validating.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Mixing/Validating.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,405 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6682046 + @summary Mixing code does not always recalculate shapes correctly when resizing components + @author anthony.petrov@...: area=awt.mixing + @library ../regtesthelpers + @build Util + @run main Validating +*/ + +/** + * Validating.java + * + * summary: Mixing code does not always recalculate shapes correctly when resizing components + */ + +import java.awt.*; +import java.awt.event.*; +import test.java.awt.regtesthelpers.Util; + +public class Validating +{ + static volatile boolean clickPassed = false; + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + "This is an AUTOMATIC test, simply wait until it is done.", + "The result (passed or failed) will be shown in the", + "message window below." + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { + System.out.println("The test environment does not support maximization. The test cannot be performed."); + pass(); + return; + } + + // Create the frame with a button. + Frame f = new Frame(); + Button b = new Button("ok"); + b.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent e) { + clickPassed = true; + } + }); + f.add(b); + // Make the frame maximized + f.setExtendedState(Frame.MAXIMIZED_BOTH); + f.pack(); + f.setVisible(true); + + Robot robot = Util.createRobot(); + robot.setAutoDelay(20); + + Util.waitForIdle(robot); + + // Now let's attempt to click in the middle of the button + // (i.e. in the middle of the window). + // If the button doesn't receive the click, it means that the test + // failed: the shape of the button was not enlarged. + Point heavyLoc = b.getLocationOnScreen(); + robot.mouseMove(heavyLoc.x + b.getWidth() / 2, heavyLoc.y + b.getHeight() / 2); + + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + Util.waitForIdle(robot); + + if (clickPassed) { + pass(); + } else { + fail("The button cannot be clicked."); + } + }//End init() + + + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test- + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + // Not sure about what happens if multiple of this test are + // instantiated in the same VM. Being static (and using + // static vars), it aint gonna work. Not worrying about + // it for now. + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test pass nor test fail has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + //The test harness may have interrupted the test. If so, rethrow the exception + // so that the harness gets it and deals with it. + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class Validating + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// if want to make listeners, here is the recommended place for them, then instantiate +// them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + Validating.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + Validating.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + System.out.println(messageIn); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + +}// TestDialog class diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/Toolkit/HeadlessTray/HeadlessTray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Toolkit/HeadlessTray/HeadlessTray.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6737722 + @summary no tray support in headless mode + @author dmitry.cherepanov: area=awt.headless + @run main HeadlessTray +*/ + +import java.awt.*; + +public class HeadlessTray +{ + public static void main (String args[]) { + + System.setProperty("java.awt.headless", "true"); + + // We expect the method returns false and no exception thrown + boolean isSupported = SystemTray.isSupported(); + + if (isSupported) { + throw new RuntimeException("Tray shouldn't be supported in headless mode "); + } + + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java --- a/jdk/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java Wed Jul 05 16:41:30 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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 @@ -100,7 +100,7 @@ Sysout.printInstructions( instructions ); Sysout.enableNumbering(true); - MouseAdapter enterExitAdapter = new MouseAdapter { + MouseAdapter enterExitAdapter = new MouseAdapter() { public void mouseEntered(MouseEvent e){ Sysout.println("Entered on " + e.getSource().getClass().getName()); } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/awt/regtesthelpers/Util.java --- a/jdk/test/java/awt/regtesthelpers/Util.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/java/awt/regtesthelpers/Util.java Wed Jul 05 16:41:30 2017 +0200 @@ -124,6 +124,14 @@ } /** + * Makes the window visible and waits until it's shown. + */ + public static void showWindowWait(Window win) { + win.setVisible(true); + waitTillShown(win); + } + + /** * Moves mouse pointer in the center of given {@code comp} component * using {@code robot} parameter. */ @@ -574,4 +582,22 @@ public static boolean trackActionPerformed(Button button, Runnable action, int time, boolean printEvent) { return trackEvent(ActionEvent.ACTION_PERFORMED, button, action, time, printEvent); } + + /* + * Requests focus on the component provided and waits for the result. + * @return true if the component has been focused, false otherwise. + */ + public static boolean focusComponent(Component comp, int time) { + return focusComponent(comp, time, false); + } + public static boolean focusComponent(final Component comp, int time, boolean printEvent) { + return trackFocusGained(comp, + new Runnable() { + public void run() { + comp.requestFocus(); + } + }, + time, printEvent); + + } } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/lang/ThreadGroup/NullThreadName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ThreadGroup/NullThreadName.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6576763 + * @summary (thread) Thread constructors throw undocumented NPE for null name + */ + +/* + * Verify that threads constructed with a null thread name do not get added + * to the list of unstarted thread for a thread group. We can do this by + * checking that a daemon threadGroup is desroyed after its final valid thread + * has completed. + */ + +import java.util.concurrent.CountDownLatch; +import static java.lang.System.out; + +public class NullThreadName +{ + static CountDownLatch done = new CountDownLatch(1); + + public static void main(String args[]) throws Exception { + ThreadGroup tg = new ThreadGroup("chegar-threads"); + Thread goodThread = new Thread(tg, new GoodThread(), "goodThread"); + try { + Thread badThread = new Thread(tg, new Runnable(){ + @Override + public void run() {} }, null); + } catch (NullPointerException npe) { + out.println("OK, caught expected " + npe); + } + tg.setDaemon(true); + goodThread.start(); + + done.await(); + + int count = 0; + while (goodThread.isAlive()) { + /* Hold off a little to allow the thread to complete */ + out.println("GoodThread still alive, sleeping..."); + try { Thread.sleep(2000); } + catch (InterruptedException unused) {} + + /* do not wait forever */ + if (count++ > 5) + throw new AssertionError("GoodThread is still alive!"); + } + + if (!tg.isDestroyed()) { + throw new AssertionError("Failed: Thread group is not destroyed."); + } + } + + static class GoodThread implements Runnable + { + @Override + public void run() { + out.println("Good Thread started..."); + out.println("Good Thread finishing"); + done.countDown(); + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,156 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 5041784 + * @summary Check that plain arrays like String[] are never represented as + * GenericArrayType. + * @author Eamonn McManus + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class TestPlainArrayNotGeneric { + public String[] m1(List p1) {return null;} + public List m2(String[] p1) {return null;} + public void m3(List p1, String[] p2) {} + public void m4(List p1) {} + public TestPlainArrayNotGeneric(List p1) {} + public TestPlainArrayNotGeneric(List p1, String[] p2) {} + + public > T m5(T p1) {return null;} + public T[] m6(T[] p1, List p2) {return null;} + + public List m6(List p1) {return null;} + public > T m7(T[] p1) {return null;} + public List m8(List p1) {return null;} + public > T[] m9(T[] p1) {return null;} + + public static interface XMap extends Map, String[]> {} + public static interface YMap, V> + extends Map {} + + + private static String lastFailure; + private static int failureCount; + + public static void main(String[] args) throws Exception { + checkClass(TestPlainArrayNotGeneric.class); + + if (failureCount == 0) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: Last failure: " + lastFailure); + } + + private static void checkClass(Class c) throws Exception { + Method[] methods = c.getMethods(); + for (Method m : methods) { + check(m.getGenericReturnType(), "return type of method " + m); + check(m.getGenericParameterTypes(), "parameter", "method " + m); + check(m.getTypeParameters(), "type parameter", "method " + m); + } + + Constructor[] constructors = c.getConstructors(); + for (Constructor constr : constructors) { + check(constr.getGenericParameterTypes(), "parameter", + "constructor " + constr); + check(constr.getTypeParameters(), "type parameter", + "constructor " + constr); + } + + Class[] inners = c.getDeclaredClasses(); + for (Class inner : inners) + checkClass(inner); + } + + private static void check(Type[] types, String elementKind, String what) { + for (int i = 0; i < types.length; i++) { + Type t = types[i]; + check(t, elementKind + " " + (i+1) + " of " + what); + } + } + + private static final Set checking = new HashSet(); + + private static void check(Type t, String what) { + if (t == null || !checking.add(t)) + return; + // Avoid infinite recursion. t can be null e.g. for superclass of Object. + try { + check2(t, what); + } finally { + checking.remove(t); + } + } + + private static void check2(Type t, String what) { + if (t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) t; + check(pt.getActualTypeArguments(), "type argument", what); + } else if (t instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) t; + check(tv.getBounds(), "bound", what); + GenericDeclaration gd = tv.getGenericDeclaration(); + if (gd instanceof Type) + check((Type) gd, "declaration containing " + what); + } else if (t instanceof WildcardType) { + WildcardType wt = (WildcardType) t; + check(wt.getLowerBounds(), "lower bound", "wildcard type in " + what); + check(wt.getUpperBounds(), "upper bound", "wildcard type in " + what); + } else if (t instanceof Class) { + Class c = (Class) t; + check(c.getGenericInterfaces(), "superinterface", c.toString()); + check(c.getGenericSuperclass(), "superclass of " + c); + check(c.getTypeParameters(), "type parameter", c.toString()); + } else if (t instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType) t; + Type comp = gat.getGenericComponentType(); + if (comp instanceof Class) { + fail("Type " + t + " uses GenericArrayType when plain " + + "array would do, in " + what); + } else + check(comp, "component type of " + what); + } else { + fail("TEST BUG: mutant Type " + t + " (a " + t.getClass().getName() + ")"); + } + } + + private static void fail(String why) { + System.out.println("FAIL: " + why); + lastFailure = why; + failureCount++; + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/BufferPoolMXBean/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/BufferPoolMXBean/Basic.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,106 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6606598 + * @summary Unit test for java.nio.BufferPoolMXBean + */ + +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.BufferPoolMXBean; +import java.nio.channels.FileChannel; +import java.io.File; +import java.io.RandomAccessFile; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.util.*; + +public class Basic { + + // static fields to ensure buffers aren't GC'ed + static List buffers; + static MappedByteBuffer mbb; + + // check counters + static void check(List pools, + int minBufferCount, + long minTotalCapacity) + { + int bufferCount = 0; + long totalCap = 0; + long totalMem = 0; + for (BufferPoolMXBean pool: pools) { + bufferCount += pool.getCount(); + totalCap += pool.getTotalCapacity(); + totalMem += pool.getMemoryUsed(); + } + if (bufferCount < minBufferCount) + throw new RuntimeException("Count less than expected"); + if (totalMem < minTotalCapacity) + throw new RuntimeException("Memory usage less than expected"); + if (totalCap < minTotalCapacity) + throw new RuntimeException("Total capacity less than expected"); + } + + public static void main(String[] args) throws Exception { + Random rand = new Random(); + + // allocate a few direct buffers + int bufferCount = 5 + rand.nextInt(20); + buffers = new ArrayList(bufferCount); + long totalCapacity = 0L; + for (int i=0; i pools = + ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + check(pools, bufferCount, totalCapacity); + + // using MBeanServer + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Set mbeans = server.queryNames( + new ObjectName("java.nio:type=BufferPool,*"), null); + pools = new ArrayList(); + for (ObjectName name: mbeans) { + BufferPoolMXBean pool = ManagementFactory + .newPlatformMXBeanProxy(server, name.toString(), BufferPoolMXBean.class); + pools.add(pool); + } + check(pools, bufferCount, totalCapacity); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,220 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4527345 + * @summary Unit test for DatagramChannel's multicast support + * @build BasicMulticastTests NetworkConfiguration + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.io.IOException; + +public class BasicMulticastTests { + + /** + * Tests that existing membership key is returned by join methods and that + * membership key methods return the expected results + */ + static void membershipKeyTests(NetworkInterface nif, + InetAddress group, + InetAddress source) + throws IOException + { + System.out.format("MembershipKey test using %s @ %s\n", + group.getHostAddress(), nif.getName()); + + ProtocolFamily family = (group instanceof Inet4Address) ? + StandardProtocolFamily.INET : StandardProtocolFamily.INET6; + + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(source, 0)); + + // check existing key is returned + MembershipKey key = dc.join(group, nif); + MembershipKey other = dc.join(group, nif); + if (other != key) { + throw new RuntimeException("existing key not returned"); + } + + // check key + if (!key.isValid()) + throw new RuntimeException("key is not valid"); + if (!key.getGroup().equals(group)) + throw new RuntimeException("group is incorrect"); + if (!key.getNetworkInterface().equals(nif)) + throw new RuntimeException("network interface is incorrect"); + if (key.getSourceAddress() != null) + throw new RuntimeException("key is source specific"); + + // drop membership + key.drop(); + if (key.isValid()) { + throw new RuntimeException("key is still valid"); + } + + // source-specific + try { + key = dc.join(group, nif, source); + other = dc.join(group, nif, source); + if (other != key) { + throw new RuntimeException("existing key not returned"); + } + if (!key.isValid()) + throw new RuntimeException("key is not valid"); + if (!key.getGroup().equals(group)) + throw new RuntimeException("group is incorrect"); + if (!key.getNetworkInterface().equals(nif)) + throw new RuntimeException("network interface is incorrect"); + if (!key.getSourceAddress().equals(source)) + throw new RuntimeException("key's source address incorrect"); + + // drop membership + key.drop(); + if (key.isValid()) { + throw new RuntimeException("key is still valid"); + } + } catch (UnsupportedOperationException x) { + } + + // done + dc.close(); + } + + /** + * Tests exceptions for invalid arguments or scenarios + */ + static void exceptionTests(NetworkInterface nif) + throws IOException + { + System.out.println("Exception Tests"); + + DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + InetAddress group = InetAddress.getByName("225.4.5.6"); + InetAddress notGroup = InetAddress.getByName("1.2.3.4"); + InetAddress thisHost = InetAddress.getLocalHost(); + + // IllegalStateException + MembershipKey key; + key = dc.join(group, nif); + try { + dc.join(group, nif, thisHost); + throw new RuntimeException("IllegalStateException not thrown"); + } catch (IllegalStateException x) { + } catch (UnsupportedOperationException x) { + } + key.drop(); + try { + key = dc.join(group, nif, thisHost); + try { + dc.join(group, nif); + throw new RuntimeException("IllegalStateException not thrown"); + } catch (IllegalStateException x) { + } + key.drop(); + } catch (UnsupportedOperationException x) { + } + + // IllegalArgumentException + try { + dc.join(notGroup, nif); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } + try { + dc.join(notGroup, nif, thisHost); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } catch (UnsupportedOperationException x) { + } + + // NullPointerException + try { + dc.join(null, nif); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.join(group, null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.join(group, nif, null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } catch (UnsupportedOperationException x) { + } + + dc.close(); + + // ClosedChannelException + try { + dc.join(group, nif); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + try { + dc.join(group, nif, thisHost); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } catch (UnsupportedOperationException x) { + } + } + + + /** + * Probe interfaces to get interfaces that support IPv4 or IPv6 multicasting + * and invoke tests. + */ + public static void main(String[] args) throws IOException { + + // multicast groups used for the test + InetAddress ip4Group = InetAddress.getByName("225.4.5.6"); + InetAddress ip6Group = InetAddress.getByName("ff02::a"); + + + NetworkConfiguration config = NetworkConfiguration.probe(); + + NetworkInterface nif = config.ip4Interfaces().iterator().next(); + InetAddress anySource = config.ip4Addresses(nif).iterator().next(); + membershipKeyTests(nif, ip4Group, anySource); + exceptionTests(nif); + + // re-run the membership key tests with IPv6 if available + + Iterator iter = config.ip6Interfaces().iterator(); + if (iter.hasNext()) { + nif = iter.next(); + anySource = config.ip6Addresses(nif).iterator().next(); + membershipKeyTests(nif, ip6Group, anySource); + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,220 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4527345 + * @summary Unit test for DatagramChannel's multicast support + * @build MulticastSendReceiveTests NetworkConfiguration + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.io.IOException; + +public class MulticastSendReceiveTests { + + static Random rand = new Random(); + + /** + * Send datagram from given local address to given multicast + * group. + */ + static int sendDatagram(InetAddress local, + NetworkInterface nif, + InetAddress group, + int port) + throws IOException + { + ProtocolFamily family = (group instanceof Inet6Address) ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + DatagramChannel dc = DatagramChannel.open(family) + .bind(new InetSocketAddress(local, 0)) + .setOption(StandardSocketOption.IP_MULTICAST_IF, nif); + int id = rand.nextInt(); + byte[] msg = Integer.toString(id).getBytes("UTF-8"); + ByteBuffer buf = ByteBuffer.wrap(msg); + System.out.format("Send message from %s -> group %s (id=0x%x)\n", + local.getHostAddress(), group.getHostAddress(), id); + dc.send(buf, new InetSocketAddress(group, port)); + dc.close(); + return id; + } + + /** + * Wait (with timeout) for datagram. + * + * @param expectedSender - expected sender address, or + * null if no datagram expected + * @param id - expected id of datagram + */ + static void receiveDatagram(DatagramChannel dc, + InetAddress expectedSender, + int id) + throws IOException + { + Selector sel = Selector.open(); + dc.configureBlocking(false); + dc.register(sel, SelectionKey.OP_READ); + ByteBuffer buf = ByteBuffer.allocateDirect(100); + + try { + for (;;) { + System.out.println("Waiting to receive message"); + sel.select(5*1000); + SocketAddress sa = dc.receive(buf); + + // no datagram received + if (sa == null) { + if (expectedSender != null) { + throw new RuntimeException("Expected message not recieved"); + } + System.out.println("No message received (correct)"); + return; + } + + // datagram received + + InetAddress sender = ((InetSocketAddress)sa).getAddress(); + buf.flip(); + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes); + int receivedId = Integer.parseInt(new String(bytes)); + + System.out.format("Received message from %s (id=0x%x)\n", + sender, receivedId); + + if (expectedSender == null) { + if (receivedId == id) + throw new RuntimeException("Message not expected"); + System.out.println("Message ignored (has wrong id)"); + } else { + if (sender.equals(expectedSender)) { + System.out.println("Message expected"); + return; + } + System.out.println("Message ignored (wrong sender)"); + } + + sel.selectedKeys().clear(); + buf.rewind(); + } + } finally { + sel.close(); + } + } + + + /** + * Exercise multicast send/receive on given group/interface + */ + static void test(NetworkInterface nif, InetAddress group, InetAddress source) + throws IOException + { + ProtocolFamily family = (group instanceof Inet6Address) ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + System.out.format("create channel to %s socket\n", family.name()); + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + // join group + System.out.format("join %s @ %s\n", group.getHostAddress(), + nif.getName()); + MembershipKey key = dc.join(group, nif); + + // send message to group + int port = ((InetSocketAddress)dc.getLocalAddress()).getPort(); + int id = sendDatagram(source, nif, group, port); + + // receive message and check id matches + receiveDatagram(dc, source, id); + + // exclude-mode filtering + + try { + System.out.format("block %s\n", source.getHostAddress()); + + // may throw UOE + key.block(source); + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, null, id); + + // unblock source, send message, message should be received + System.out.format("unblock %s\n", source.getHostAddress()); + key.unblock(source); + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, source, id); + } catch (UnsupportedOperationException x) { + System.out.println("Exclude-mode filtering not supported!"); + } + + key.drop(); + + // include-mode filtering + + InetAddress bogus = (group instanceof Inet6Address) ? + InetAddress.getByName("fe80::1234") : + InetAddress.getByName("1.2.3.4"); + System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), + nif.getName(), bogus.getHostAddress()); + try { + // may throw UOE + key = dc.join(group, nif, bogus); + + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, null, id); + + System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), + nif.getName(), source.getHostAddress()); + key = dc.join(group, nif, source); + + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, source, id); + } catch (UnsupportedOperationException x) { + System.out.println("Include-mode filtering not supported!"); + } + + // done + dc.close(); + } + + public static void main(String[] args) throws IOException { + NetworkConfiguration config = NetworkConfiguration.probe(); + + // multicast groups used for the test + InetAddress ip4Group = InetAddress.getByName("225.4.5.6"); + InetAddress ip6Group = InetAddress.getByName("ff02::a"); + + for (NetworkInterface nif: config.ip4Interfaces()) { + InetAddress source = config.ip4Addresses(nif).iterator().next(); + test(nif, ip4Group, source); + } + + for (NetworkInterface nif: config.ip6Interfaces()) { + InetAddress source = config.ip6Addresses(nif).iterator().next(); + test(nif, ip6Group, source); + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,97 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.*; +import java.util.*; +import java.io.IOException; + +/** + * Helper class for multicasting tests. + */ + +class NetworkConfiguration { + + private Map> ip4Interfaces; + private Map> ip6Interfaces; + + private NetworkConfiguration(Map> ip4Interfaces, + Map> ip6Interfaces) + { + this.ip4Interfaces = ip4Interfaces; + this.ip6Interfaces = ip6Interfaces; + } + + Iterable ip4Interfaces() { + return ip4Interfaces.keySet(); + } + + Iterable ip6Interfaces() { + return ip6Interfaces.keySet(); + } + + Iterable ip4Addresses(NetworkInterface nif) { + return ip4Interfaces.get(nif); + } + + Iterable ip6Addresses(NetworkInterface nif) { + return ip6Interfaces.get(nif); + } + + static NetworkConfiguration probe() throws IOException { + Map> ip4Interfaces = + new HashMap>(); + Map> ip6Interfaces = + new HashMap>(); + + // find the interfaces that support IPv4 and IPv6 + List nifs = Collections + .list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface nif: nifs) { + // ignore intertaces that are down or don't support multicast + if (!nif.isUp() || !nif.supportsMulticast() || nif.isLoopback()) + continue; + + List addrs = Collections.list(nif.getInetAddresses()); + for (InetAddress addr: addrs) { + if (addr instanceof Inet4Address) { + List list = ip4Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip4Interfaces.put(nif, list); + } + if (addr instanceof Inet6Address) { + List list = ip6Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip6Interfaces.put(nif, list); + + } + } + } + return new NetworkConfiguration(ip4Interfaces, ip6Interfaces); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,115 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for setOption/getOption/options methods + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(DatagramChannel dc, + SocketOption name, + T expectedValue) + throws IOException + { + T value = dc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + DatagramChannel dc = DatagramChannel.open(); + + // check supported options + Set> options = dc.options(); + List> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, + IP_MULTICAST_LOOP); + for (SocketOption opt: expected) { + if (!options.contains(opt)) + throw new RuntimeException(opt.name() + " should be supported"); + } + + // check specified defaults + checkOption(dc, SO_BROADCAST, false); + checkOption(dc, IP_MULTICAST_TTL, 1); // true on supported platforms + checkOption(dc, IP_MULTICAST_LOOP, true); // true on supported platforms + + // allowed to change when not bound + dc.setOption(SO_BROADCAST, true); + checkOption(dc, SO_BROADCAST, true); + dc.setOption(SO_BROADCAST, false); + checkOption(dc, SO_BROADCAST, false); + dc.setOption(SO_SNDBUF, 16*1024); // can't check + dc.setOption(SO_RCVBUF, 16*1024); // can't check + dc.setOption(SO_REUSEADDR, true); + checkOption(dc, SO_REUSEADDR, true); + dc.setOption(SO_REUSEADDR, false); + checkOption(dc, SO_REUSEADDR, false); + + // bind socket + dc.bind(new InetSocketAddress(0)); + + // allow to change when bound + dc.setOption(SO_BROADCAST, true); + checkOption(dc, SO_BROADCAST, true); + dc.setOption(SO_BROADCAST, false); + checkOption(dc, SO_BROADCAST, false); + dc.setOption(IP_TOS, 0x08); // can't check + dc.setOption(IP_MULTICAST_TTL, 2); + checkOption(dc, IP_MULTICAST_TTL, 2); + dc.setOption(IP_MULTICAST_LOOP, false); + checkOption(dc, IP_MULTICAST_LOOP, false); + dc.setOption(IP_MULTICAST_LOOP, true); + checkOption(dc, IP_MULTICAST_LOOP, true); + + + // NullPointerException + try { + dc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + dc.close(); + try { + dc.setOption(IP_MULTICAST_LOOP, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,84 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for ServerSocketChannel setOption/getOption/options + * methods. + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(ServerSocketChannel ssc, SocketOption name, Object expectedValue) + throws IOException + { + Object value = ssc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + ServerSocketChannel ssc = ServerSocketChannel.open(); + + // check supported options + Set> options = ssc.options(); + if (!options.contains(SO_REUSEADDR)) + throw new RuntimeException("SO_REUSEADDR should be supported"); + if (!options.contains(SO_RCVBUF)) + throw new RuntimeException("SO_RCVBUF should be supported"); + + // allowed to change when not bound + ssc.setOption(SO_RCVBUF, 256*1024); // can't check + ssc.setOption(SO_REUSEADDR, true); + checkOption(ssc, SO_REUSEADDR, true); + ssc.setOption(SO_REUSEADDR, false); + checkOption(ssc, SO_REUSEADDR, false); + + // NullPointerException + try { + ssc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + ssc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + ssc.close(); + try { + ssc.setOption(SO_REUSEADDR, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,129 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4640544 + * @summary Unit test to check SocketChannel setOption/getOption/options + * methods. + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(SocketChannel sc, SocketOption name, Object expectedValue) + throws IOException + { + Object value = sc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + SocketChannel sc = SocketChannel.open(); + + // check supported options + Set> options = sc.options(); + List expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY); + for (SocketOption opt: expected) { + if (!options.contains(opt)) + throw new RuntimeException(opt.name() + " should be supported"); + } + + // check specified defaults + int linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("initial value of SO_LINGER should be < 0"); + checkOption(sc, SO_KEEPALIVE, false); + checkOption(sc, TCP_NODELAY, false); + + // allowed to change when not bound + sc.setOption(SO_KEEPALIVE, true); + checkOption(sc, SO_KEEPALIVE, true); + sc.setOption(SO_KEEPALIVE, false); + checkOption(sc, SO_KEEPALIVE, false); + sc.setOption(SO_SNDBUF, 128*1024); // can't check + sc.setOption(SO_RCVBUF, 256*1024); // can't check + sc.setOption(SO_REUSEADDR, true); + checkOption(sc, SO_REUSEADDR, true); + sc.setOption(SO_REUSEADDR, false); + checkOption(sc, SO_REUSEADDR, false); + sc.setOption(SO_LINGER, 10); + linger = sc.getOption(SO_LINGER); + if (linger < 1) + throw new RuntimeException("expected linger to be enabled"); + sc.setOption(SO_LINGER, -1); + linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("expected linger to be disabled"); + sc.setOption(TCP_NODELAY, true); + checkOption(sc, TCP_NODELAY, true); + sc.setOption(TCP_NODELAY, false); // can't check + + // bind socket + sc.bind(new InetSocketAddress(0)); + + // allow to change when bound + sc.setOption(SO_KEEPALIVE, true); + checkOption(sc, SO_KEEPALIVE, true); + sc.setOption(SO_KEEPALIVE, false); + checkOption(sc, SO_KEEPALIVE, false); + + sc.setOption(SO_LINGER, 10); + linger = sc.getOption(SO_LINGER); + if (linger < 1) + throw new RuntimeException("expected linger to be enabled"); + sc.setOption(SO_LINGER, -1); + linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("expected linger to be disabled"); + sc.setOption(TCP_NODELAY, true); // can't check + sc.setOption(TCP_NODELAY, false); // can't check + + // NullPointerException + try { + sc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + sc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + sc.close(); + try { + sc.setOption(TCP_NODELAY, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/TestUtil.java --- a/jdk/test/java/nio/channels/TestUtil.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/java/nio/channels/TestUtil.java Wed Jul 05 16:41:30 2017 +0200 @@ -38,7 +38,7 @@ // executing in a different network. public static final String HOST = "javaweb.sfbay.sun.com"; public static final String REFUSING_HOST = "jano1.sfbay.sun.com"; - public static final String FAR_HOST = "theclub.ireland.sun.com"; + public static final String FAR_HOST = "irejano.ireland.sun.com"; public static final String UNRESOLVABLE_HOST = "blah-blah.blah-blah.blah"; private TestUtil() { } @@ -102,5 +102,4 @@ static boolean onWindows() { return osName.startsWith("Windows"); } - } diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/java/nio/channels/etc/NetworkChannelTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,187 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for channels that implement NetworkChannel + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; + +public class NetworkChannelTests { + + static interface ChannelFactory { + NetworkChannel open() throws IOException; + } + + static class BogusSocketAddress extends SocketAddress { + } + + /** + * Exercise bind method. + */ + static void bindTests(ChannelFactory factory) throws IOException { + NetworkChannel ch; + + // AlreadyBoundException + ch = factory.open().bind(new InetSocketAddress(0)); + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("AlreadyBoundException not thrown"); + } catch (AlreadyBoundException x) { + } + ch.close(); + + // bind(null) + ch = factory.open().bind(null); + if (ch.getLocalAddress() == null) + throw new RuntimeException("socket not found"); + ch.close(); + + // UnsupportedAddressTypeException + ch = factory.open(); + try { + ch.bind(new BogusSocketAddress()); + throw new RuntimeException("UnsupportedAddressTypeException not thrown"); + } catch (UnsupportedAddressTypeException x) { + } + ch.close(); + + // ClosedChannelException + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } + + /** + * Exercise getLocalAddress method. + */ + static void localAddressTests(ChannelFactory factory) throws IOException { + NetworkChannel ch; + + // not bound + ch = factory.open(); + if (ch.getLocalAddress() != null) { + throw new RuntimeException("Local address returned when not bound"); + } + + // bound + InetSocketAddress local = + (InetSocketAddress)(ch.bind(new InetSocketAddress(0)).getLocalAddress()); + if (!local.getAddress().isAnyLocalAddress()) { + if (NetworkInterface.getByInetAddress(local.getAddress()) == null) + throw new RuntimeException("not bound to local address"); + } + if (local.getPort() <= 0) + throw new RuntimeException("not bound to local port"); + + // closed + ch.close(); + if (ch.getLocalAddress() != null) { + throw new RuntimeException("Local address return when closed"); + } + } + + /** + * Exercise getConnectedAddress method (SocketChannel only) + */ + static void connectedAddressTests() throws IOException { + ServerSocketChannel ssc = ServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + InetSocketAddress local = (InetSocketAddress)(ssc.getLocalAddress()); + int port = local.getPort(); + InetSocketAddress server = new InetSocketAddress(InetAddress.getLocalHost(), port); + + SocketChannel sc = SocketChannel.open(); + + // not connected + if (sc.getConnectedAddress() != null) + throw new RuntimeException("getConnectedAddress returned address when not connected"); + + // connected + sc.connect(server); + SocketAddress remote = sc.getConnectedAddress(); + if (!remote.equals(server)) + throw new RuntimeException("getConnectedAddress returned incorrect address"); + + // closed + sc.close(); + if (sc.getConnectedAddress() != null) + throw new RuntimeException("getConnectedAddress returned address when closed"); + + ssc.close(); + } + + public static void main(String[] args) throws IOException { + ChannelFactory factory; + + // -- SocketChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return SocketChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + connectedAddressTests(); + + // -- ServerSocketChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return ServerSocketChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + + // backlog values + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), 100).close(); + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), 0).close(); + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), -1).close(); + + // -- DatagramChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return DatagramChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java --- a/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -33,14 +33,16 @@ */ import java.io.*; +import java.lang.management.*; import java.lang.reflect.*; import java.net.*; import java.security.CodeSource; import java.util.*; import java.util.jar.*; import javax.management.*; -import javax.management.modelmbean.*; import javax.management.relation.*; +import javax.management.remote.*; +import javax.management.remote.rmi.*; /* * This test finds all classes in the same code-base as the JMX @@ -68,10 +70,10 @@ */ public class NotificationInfoTest { // class or object names where the test failed - private static final Set/**/ failed = new TreeSet(); + private static final Set failed = new TreeSet(); // class or object names where there were no MBeanNotificationInfo entries - private static final Set/**/ suspicious = new TreeSet(); + private static final Set suspicious = new TreeSet(); public static void main(String[] args) throws Exception { System.out.println("Checking that all known MBeans that are " + @@ -86,8 +88,20 @@ .getCodeSource(); URL codeBase; if (cs == null) { - codeBase = new URL("file:" + System.getProperty("java.home") + - "/lib/rt.jar"); + String javaHome = System.getProperty("java.home"); + String[] candidates = {"/lib/rt.jar", "/classes/"}; + codeBase = null; + for (String candidate : candidates) { + File file = new File(javaHome + candidate); + if (file.exists()) { + codeBase = file.toURI().toURL(); + break; + } + } + if (codeBase == null) { + throw new Exception( + "Could not determine codeBase for java.home=" + javaHome); + } } else codeBase = cs.getLocation(); @@ -98,7 +112,7 @@ System.out.println("Testing standard MBeans..."); for (int i = 0; i < classes.length; i++) { String name = classes[i]; - Class c; + Class c; try { c = Class.forName(name); } catch (Throwable e) { @@ -109,18 +123,22 @@ System.out.println(name + ": not a NotificationBroadcaster"); continue; } + if (Modifier.isAbstract(c.getModifiers())) { + System.out.println(name + ": abstract class"); + continue; + } NotificationBroadcaster mbean; - Constructor constr; + Constructor constr; try { - constr = c.getConstructor(null); + constr = c.getConstructor(); } catch (Exception e) { System.out.println(name + ": no public no-arg constructor: " + e); continue; } try { - mbean = (NotificationBroadcaster) constr.newInstance(null); + mbean = (NotificationBroadcaster) constr.newInstance(); } catch (Exception e) { System.out.println(name + ": no-arg constructor failed: " + e); continue; @@ -161,22 +179,9 @@ } private static void checkPlatformMBeans() throws Exception { - Class managementFactory; - try { - managementFactory = - Class.forName("java.lang.management.ManagementFactory"); - } catch (Exception e) { - System.out.println("...no ManagementFactory, assuming pre-Tiger: " - + e); - return; - } - Method getPlatformMBeanServer = - managementFactory.getMethod("getPlatformMBeanServer", null); - MBeanServer mbs = (MBeanServer) - getPlatformMBeanServer.invoke(null, null); - Set mbeanNames = mbs.queryNames(null, null); - for (Iterator it = mbeanNames.iterator(); it.hasNext(); ) { - ObjectName name = (ObjectName) it.next(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + Set mbeanNames = mbs.queryNames(null, null); + for (ObjectName name : mbeanNames) { if (!mbs.isInstanceOf(name, NotificationBroadcaster.class.getName())) { System.out.println(name + ": not a NotificationBroadcaster"); @@ -188,31 +193,9 @@ } private static void checkRMIConnectorServer() throws Exception { - Class rmiConnectorServer; - try { - rmiConnectorServer = - Class.forName("javax.management.remote.rmi.RMIConnectorServer"); - } catch (Exception e) { - System.out.println("No RMIConnectorServer class, skipping: " + e); - return; - } - Class jmxServiceURL = - Class.forName("javax.management.remote.JMXServiceURL"); - Constructor jmxServiceURLConstructor = - jmxServiceURL.getConstructor(new Class[] {String.class}); - Object url = - jmxServiceURLConstructor.newInstance(new Object[] { - "service:jmx:rmi://" - }); - Constructor rmiConnectorServerConstructor = - rmiConnectorServer.getConstructor(new Class[] { - jmxServiceURL, Map.class - }); - Object connector = - rmiConnectorServerConstructor.newInstance(new Object[] { - url, null - }); - check((NotificationBroadcaster) connector); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + RMIConnectorServer connector = new RMIConnectorServer(url, null); + check(connector); } private static void check(String what, MBeanNotificationInfo[] mbnis) { @@ -250,30 +233,29 @@ private static String[] findStandardMBeans(URL codeBase) throws Exception { - Set names; + Set names; if (codeBase.getProtocol().equalsIgnoreCase("file") && codeBase.toString().endsWith("/")) names = findStandardMBeansFromDir(codeBase); else names = findStandardMBeansFromJar(codeBase); - Set standardMBeanNames = new TreeSet(); - for (Iterator it = names.iterator(); it.hasNext(); ) { - String name = (String) it.next(); + Set standardMBeanNames = new TreeSet(); + for (String name : names) { if (name.endsWith("MBean")) { String prefix = name.substring(0, name.length() - 5); if (names.contains(prefix)) standardMBeanNames.add(prefix); } } - return (String[]) standardMBeanNames.toArray(new String[0]); + return standardMBeanNames.toArray(new String[0]); } - private static Set findStandardMBeansFromJar(URL codeBase) + private static Set findStandardMBeansFromJar(URL codeBase) throws Exception { InputStream is = codeBase.openStream(); JarInputStream jis = new JarInputStream(is); - Set names = new TreeSet(); + Set names = new TreeSet(); JarEntry entry; while ((entry = jis.getNextJarEntry()) != null) { String name = entry.getName(); @@ -286,15 +268,15 @@ return names; } - private static Set findStandardMBeansFromDir(URL codeBase) + private static Set findStandardMBeansFromDir(URL codeBase) throws Exception { File dir = new File(new URI(codeBase.toString())); - Set names = new TreeSet(); + Set names = new TreeSet(); scanDir(dir, "", names); return names; } - private static void scanDir(File dir, String prefix, Set names) + private static void scanDir(File dir, String prefix, Set names) throws Exception { File[] files = dir.listFiles(); if (files == null) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,440 @@ +/* + * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @summary Test named MBeanServers. + * @author Daniel Fuchs + * @run clean NamedMBeanServerTest + * @run build NamedMBeanServerTest + * @run main NamedMBeanServerTest + */ + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; + +/** + * This test can probably be leveraged in the JCK to test compatibilty + * of MBeanServerFactory *Name* method implementation. + * @author dfuchs + */ +public class NamedMBeanServerTest { + + /** + * One enum value for each way of creating an MBeanServer through the + * MBeanServerFactory + */ + public static enum Creator { + newMBeanServer() { + public MBeanServer create(String domain) { + return MBeanServerFactory.newMBeanServer(domain); + } + public String test(MBeanServer server, String domain) { + System.out.println(toString()+"("+domain+")"); + return test(server, + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + domain); + } + public MBeanServer[] servers(Config config) { + return config.ndServers; + } + public String[] strings(Config config) { + return domains(config); + } + public String[] domains(Config config) { + return config.newDomains; + } + public String[] names(Config config) { + return null; + } + }, + createMBeanServer() { + public MBeanServer create(String domain) { + return MBeanServerFactory.createMBeanServer(domain); + } + public String test(MBeanServer server, String domain) { + System.out.println(toString()+"("+domain+")"); + return test(server,MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + domain); + } + public MBeanServer[] servers(Config config) { + return config.cdServers; + } + public String[] strings(Config config) { + return domains(config); + } + public String[] domains(Config config) { + return config.createDomains; + } + public String[] names(Config config) { + return null; + } + }, + newNamedMBeanServer() { + public MBeanServer create(String name) { + return MBeanServerFactory.newNamedMBeanServer(name,null); + } + public String test(MBeanServer server, String name) { + System.out.println(toString()+"("+name+",null)"); + return test(server,name,"DefaultDomain"); + } + public MBeanServer[] servers(Config config) { + return config.nnServers; + } + public String[] strings(Config config) { + return names(config); + } + public String[] domains(Config config) { + return null; + } + public String[] names(Config config) { + return config.newNames; + } + }, + createNamedMBeanServer() { + public MBeanServer create(String name) { + return MBeanServerFactory.createNamedMBeanServer(name,null); + } + public String test(MBeanServer server, String name) { + System.out.println(toString()+"("+name+",null)"); + return test(server,name,"DefaultDomain"); + } + public MBeanServer[] servers(Config config) { + return config.cnServers; + } + public String[] strings(Config config) { + return names(config); + } + public String[] domains(Config config) { + return null; + } + public String[] names(Config config) { + return config.createNames; + } + }; + + // creates an MBeanServer using the specified input string. + // either a domain, (for UNNAMED) or a mbeanServerName (for NAMED) + public abstract MBeanServer create(String string); + + // test the created server against the string used as input to create + // it. + public abstract String test(MBeanServer server, String ref); + + public abstract MBeanServer[] servers(Config config); + public abstract String[] strings(Config config); + public abstract String[] names(Config config); + public abstract String[] domains(Config config); + + public MBeanServer[] servers(Config config, String... refs) { + final MBeanServer[] servers = servers(config); + final String[] strings = strings(config); + final MBeanServer[] res = new MBeanServer[refs.length]; + for (int i=0;i found = + MBeanServerFactory.findMBeanServerByName(name); + if (!registered && found.contains(server)) + return " Server "+name+" found by name - " + + "but should not be registered"; + if (!registered && + !name.equals(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME) && + found.size()>0) + return " Server "+name+" had too many matches: " + found.size(); + if (registered && !found.contains(server)) + return " Server "+name+" not found by name - " + + "but is registered!"; + if (registered && + !name.equals(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME) && + !(found.size()==1)) + return " Server "+name+" had too many matches: " + found.size(); + return null; + } + + public static final EnumSet NAMED = + EnumSet.of(createNamedMBeanServer, newNamedMBeanServer); + public static final EnumSet UNNAMED = + EnumSet.complementOf(NAMED); + public static final EnumSet REFERENCED = + EnumSet.of(createMBeanServer, createNamedMBeanServer); + public static final EnumSet UNREFERENCED = + EnumSet.complementOf(REFERENCED); + + } + + public static class Config { + final String[] newDomains; + final String[] createDomains; + final String[] newNames; + final String[] createNames; + final MBeanServer[] ndServers; + final MBeanServer[] cdServers; + final MBeanServer[] nnServers; + final MBeanServer[] cnServers; + final Map> queries; + Config(String[][] data) { + this(data[0],data[1],data[2],data[3]); + } + Config(String[] nd, String[] cd, String[] nn, String[] cn) { + this.newDomains=nd.clone(); + this.createDomains=cd.clone(); + this.newNames=nn.clone(); + this.createNames=cn.clone(); + ndServers = new MBeanServer[nd.length]; + cdServers = new MBeanServer[cd.length]; + nnServers = new MBeanServer[nn.length]; + cnServers = new MBeanServer[cn.length]; + queries = new HashMap>(); + init(); + } + private void init() { + for (Creator c : Creator.values()) fill(c); + addQuery(null,Creator.createMBeanServer.servers(this)); + addQuery(null,Creator.createNamedMBeanServer.servers(this)); + addQuery("?*",Creator.createMBeanServer.servers(this)); + addQuery("?*",Creator.createNamedMBeanServer.servers(this)); + addQuery("*",Creator.createMBeanServer.servers(this)); + addQuery("*",Creator.createNamedMBeanServer.servers(this)); + addQuery(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + Creator.createMBeanServer.servers(this)); + } + private void addQuery(String pattern, MBeanServer... servers) { + final Set s = getQuery(pattern); + s.addAll(Arrays.asList(servers)); + } + public Set getQuery(String pattern) { + final Set s = queries.get(pattern); + if (s != null) return s; + queries.put(pattern,new HashSet()); + return queries.get(pattern); + } + public Set getPatterns() { + return queries.keySet(); + } + private void fill(Creator creator) { + fill(creator.servers(this),creator.strings(this),creator); + } + private void fill(MBeanServer[] dest, String[] src, Creator creator) { + for(int i=0;i found = + MBeanServerFactory.findMBeanServerByName(pat); + String sep=" "; + for (MBeanServer m : found) { + System.out.print(sep+MBeanServerFactory.getMBeanServerName(m)); + sep=", "; + } + System.out.println(" ]"); + final Set founds = new HashSet(); + founds.addAll(found); + if (!founds.equals(config.getQuery(pat))) { + final String msg = + "bad result for findMBeanServerByName(\""+ + pat+"\"): expected "+config.getQuery(pat).size()+", "+ + "got "+founds.size(); + throw new Exception(msg); + } + } + } + + public static void testexception(Creator c, String name, + Class error) throws Exception { + Exception failed = null; + MBeanServer server = null; + try { + server = c.create(name); + } catch (Exception x) { + failed = x; + } finally { + if (Creator.REFERENCED.contains(c) && server!=null) { + MBeanServerFactory.releaseMBeanServer(server); + } + } + if (failed == null && error != null) { + throw new Exception("Expected "+error.getName()+ + " for "+c+"("+name+")"); + } + if (error != null && !error.isInstance(failed)) + throw new Exception("Expected "+error.getName()+ + " for "+c+"("+name+"), caught "+failed); + System.out.println(""+c+"("+name+") PASSED: "+ + (failed==null?"no exception":String.valueOf(failed))); + } + + private static final Map> failures = + new LinkedHashMap>(); + private static final Map> legacy = + new LinkedHashMap>(); + private static final String[] illegalnames = { + "", "-", ":", ";", "?", "*", "wom?bat", "ran:tan.plan", + "rin;tin.tin", "tab*mow" + + }; + private static final String[] legalnames = { + "wombat", "top.tip", "ran.tan.plan", "rin.tin.tin!" + }; + private static final String[] nofailures = { + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, "default", null + }; + static { + for (String s:illegalnames) + failures.put(s, IllegalArgumentException.class); + for (String s:nofailures) + failures.put(s, null); + legacy.putAll(failures); + for (String s:legalnames) + legacy.put(s, UnsupportedOperationException.class); + + } + + public static void test2(Map> config) + throws Exception { + for (Creator c:Creator.NAMED) { + for (String s:config.keySet()) testexception(c, s, config.get(s)); + } + } + + public static class LegacyBuilder extends MBeanServerBuilder { + + @Override + public MBeanServerDelegate newMBeanServerDelegate() { + return new MBeanServerDelegate() { + @Override + public synchronized String getMBeanServerId() { + return "gloups"; + } + }; + } + + } + public static class LegacyBuilder2 extends MBeanServerBuilder { + + @Override + public MBeanServerDelegate newMBeanServerDelegate() { + return new MBeanServerDelegate() { + @Override + public synchronized String getMBeanServerId() { + return "c'est la vie..."; + } + @Override + public synchronized void setMBeanServerName(String name) { + } + + }; + } + + } + + public static void test3(Map> config, + String builderClassName) + throws Exception { + final String builder = + System.getProperty("javax.management.builder.initial"); + System.setProperty("javax.management.builder.initial", + builderClassName); + try { + test2(config); + } finally { + if (builder != null) + System.setProperty("javax.management.builder.initial", builder); + else + System.clearProperty("javax.management.builder.initial"); + } + } + + public static void main(String[] args) throws Exception { + test(test1); + test2(failures); + test3(legacy,LegacyBuilder.class.getName()); + test3(legacy,LegacyBuilder2.class.getName()); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/ObjectName/ApplyWildcardTest.java --- a/jdk/test/javax/management/ObjectName/ApplyWildcardTest.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/javax/management/ObjectName/ApplyWildcardTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -28,10 +28,13 @@ * with wildcards in the key properties value part. * @author Luis-Miguel Alventosa * @run clean ApplyWildcardTest + * @compile -XDignore.symbol.file=true ApplyWildcardTest.java * @run build ApplyWildcardTest * @run main ApplyWildcardTest */ +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Util; import javax.management.ObjectName; public class ApplyWildcardTest { @@ -74,6 +77,75 @@ { "d:k1=\"a?b\",k2=\"c*d\"", "d:k1=\"axb\",k2=\"cyzd\"" }, { "d:k1=\"a?b\",k2=\"c*d\",*", "d:k1=\"axb\",k2=\"cyzd\",k3=\"v3\"" }, { "d:*,k1=\"a?b\",k2=\"c*d\"", "d:k1=\"axb\",k2=\"cyzd\",k3=\"v3\"" }, + + // with namespaces + + { "*//:*", "d//:k=v" }, + { "//?:*", "///:k=v" }, + { "z*x//:*", "zaxcx//:k=v" }, + { "*//:*", "d/xx/q//:k=v" }, + { "z*x//:*", "z/a/x/c/x//:k=v" }, + { "*x?//:*", "dbdbdxk//:k=v" }, + { "z*x?x//:*", "zaxcx//:k=v" }, + { "*x?f//:*", "d/xxf/qxbf//:k=v" }, + { "z*x?c*x//:*", "z/a/x/c/x//:k=v" }, + + { "*//*:*", "d/c/v//x/vgh/:k=v" }, + { "z*x//z*x:*", "zaxcx//zaxcxcx:k=v" }, + { "//*//:*", "//d/xx/q//:k=v" }, + { "z*//*//:*", "z/x/x/z//z/a/x/c/x//:k=v" }, + { "*x?//blur?g*:*", "dbdbdxk//blurhgblurgh/x/:k=v" }, + { "z*x??x//??:*", "zaxcxccx///.:k=v" }, + { "*x?f//?:*", "d/xxf/qxbf///:k=v" }, + { "z*x?c*x//*//z????//g:*", "z/a/x/c/x//gloubs/././/zargh//g:k=v" }, + { "z*x?c*x//*//:*", "z/a/x/c/x//gloubs/././/:k=v"}, + { "*//*//:*", "aza//bzb//:k=v" }, + { "*//:*", "aza//:k=v" }, + + // with or without namespaces, * can also match nothing + { "x*z:*", "xz:k=v"}, + + { "*//:*", "//:k=v" }, + { "z*x//:*", "zx//:k=v" }, + { "*x?//:*", "xk//:k=v" }, + { "z*x?x//:*", "zxcx//:k=v" }, + { "*x?f//:*", "xbf//:k=v" }, + { "z*x?c*x//:*", "zx/cx//:k=v" }, + + { "*//*:*", "//:k=v" }, + { "z*x//z*x:*", "zx//zx:k=v" }, + { "//*//:*", "////:k=v" }, + { "z*//*//:*", "z////:k=v" }, + { "*x?//blur?g*:*", "xk//blurhg:k=v" }, + { "z*x??x//??:*", "zxccx///.:k=v" }, + { "*x?f//?:*", "xbf///:k=v" }, + { "z*x?c*x//*//z????//g:*", "zx/cx////zargh//g:k=v" }, + { "z*x?c*x//*//:*", "zx/cx////:k=v"}, + { "*//*//:*", "////:k=v" }, + { "*//:*", "//:k=v" }, + + // recursive namespace meta-wildcard + {"**//D:k=v", "a//D:k=v"}, + {"**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//d//D:k=v"}, + {"a//**//d//D:k=v", "a//a//b//c//d//d//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//d//c//d//e//D:k=v"}, + + // special cases for names ending with // + { "*:*", "d//:k=v" }, + { "z*x*:*", "zaxcx//:k=v" }, + { "*:*", "d/xx/q//:k=v" }, + { "z*x??:*", "z/a/x/c/x//:k=v" }, + { "*x???:*", "dbdbdxk//:k=v" }, + { "z*x?c*x*:*", "z/a/x/c/x//:k=v" }, + { "?/*/?:*", "d/xx/q//:k=v" }, + { "**//*:*", "a//b//jmx.rmi:k=v"}, + { "**//*:*", "a//b//jmx.rmi//:k=v"}, + { "*//*:*", "wombat//:type=Wombat" }, + { "**//*:*", "jmx.rmi//:k=v"}, + }; private static final String negativeTests[][] = { @@ -114,6 +186,33 @@ { "d:k1=\"a?b\",k2=\"c*d\"", "d:k1=\"ab\",k2=\"cd\"" }, { "d:k1=\"a?b\",k2=\"c*d\",*", "d:k1=\"ab\",k2=\"cd\",k3=\"v3\"" }, { "d:*,k1=\"a?b\",k2=\"c*d\"", "d:k1=\"ab\",k2=\"cd\",k3=\"v3\"" }, + + // with namespaces + + { "z*x?x*:*", "zaxcx//blougs:k=v" }, + { "*x?f??rata:*", "d/xxf/qxbf//rata:k=v" }, + { "z*x?c*x*b*:*", "z/a/x/c/x//b//:k=v" }, + + { "*:*", "d/c/v//x/vgh/:k=v" }, + { "z*x??z*x:*", "zaxcx//zaxcxcx:k=v" }, + { "?/*/?:*", "//d/xx/q//:k=v" }, + { "z*/?*/?:*", "z/x/x/z//z/a/x/c/x//:k=v" }, + { "*x?/?blur?g*:*", "dbdbdxk//blurhgblurgh/x/:k=v" }, + { "z*x??x/???:*", "zaxcxccx///.:k=v" }, + { "*x?f?/?:*", "d/xxf/qxbf///:k=v" }, + { "z*x?c*x/?*z????*g:*", "z/a/x/c/x//gloubs/././/zargh//g:k=v" }, + + // recursive namespace meta-wildcard + {"**//D:k=v", "D:k=v"}, + {"b//**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//D:k=v", "a//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//e//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//d//e//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//c//d//e//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//c//e//D:k=v"}, + { "**//*:*", "jmx.rmi:k=v"}, + }; private static int runPositiveTests() { @@ -129,6 +228,8 @@ if (result == false) { error++; System.out.println("Test failed!"); + throw new Error("test failed for "+ + "\"" + on1 + "\".apply(\"" + on2 + "\")"); } else { System.out.println("Test passed!"); } @@ -168,10 +269,85 @@ return error; } + private static int runRepositoryPositiveTests() { + int error = 0; + for (int i = 0; i < positiveTests.length; i++) { + try { + ObjectName on1 = ObjectName.getInstance(positiveTests[i][0]); + ObjectName on2 = ObjectName.getInstance(positiveTests[i][1]); + if (on1.isPropertyPattern()) { + if (!on1.getKeyPropertyListString().equals("")) continue; + } else if (!on1.getCanonicalKeyPropertyListString() + .equals(on2.getCanonicalKeyPropertyListString())) { + continue; + } + System.out.println("Repository Positive Match Test ---------------"); + final String dom1 = on1.getDomain(); + final String dom2 = on2.getDomain(); + System.out.println("Util.wildpathmatch(\"" + dom2 + "\",\"" + dom1 + "\")"); + boolean result = + Util.wildpathmatch(dom2,dom1); + System.out.println("Result = " + result); + if (result == false) { + error++; + System.out.println("Test failed!"); + } else { + System.out.println("Test passed!"); + } + } catch (Exception e) { + error++; + System.out.println("Got Unexpected Exception = " + e.toString()); + System.out.println("Test failed!"); + } + System.out.println("----------------------------------------------"); + } + return error; + } + + private static int runRepositoryNegativeTests() { + int error = 0; + for (int i = 0; i < negativeTests.length; i++) { + try { + ObjectName on1 = ObjectName.getInstance(negativeTests[i][0]); + ObjectName on2 = ObjectName.getInstance(negativeTests[i][1]); + if (on1.isPropertyPattern()) { + if (!on1.getKeyPropertyListString().equals("")) continue; + } else if (!on1.getCanonicalKeyPropertyListString() + .equals(on2.getCanonicalKeyPropertyListString())) { + continue; + } + System.out.println("Repository Negative Match Test ---------------"); + final String dom1 = on1.getDomain(); + final String dom2 = on2.getDomain(); + System.out.println("Util.wildpathmatch(\"" + dom2 + "\",\"" + dom1 + "\")"); + boolean result = + Util.wildpathmatch(dom2,dom1); + System.out.println("Result = " + result); + if (result == true) { + error++; + System.out.println("Test failed!"); + } else { + System.out.println("Test passed!"); + } + } catch (Exception e) { + error++; + System.out.println("Got Unexpected Exception = " + e.toString()); + System.out.println("Test failed!"); + } + System.out.println("----------------------------------------------"); + } + return error; + } + public static void main(String[] args) throws Exception { + int error = 0; + if (!(new ObjectName("z*x*:*").apply(new ObjectName("zaxcx//:k=v")))) + throw new Exception(); + + // Check null values // System.out.println("----------------------------------------------"); @@ -253,6 +429,10 @@ error += runPositiveTests(); error += runNegativeTests(); + System.out.println("----------------------------------------------"); + error += runRepositoryPositiveTests(); + System.out.println("----------------------------------------------"); + error += runRepositoryNegativeTests(); if (error > 0) { final String msg = "Test FAILED! Got " + error + " error(s)"; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java --- a/jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/javax/management/eventService/LeaseManagerDeadlockTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -26,6 +26,7 @@ * @bug 6717789 * @summary Check that a lock is not held when a LeaseManager expires. * @author Eamonn McManus + * @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java */ import com.sun.jmx.event.LeaseManager; diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/mxbean/JMXServiceURLTest.java --- a/jdk/test/javax/management/mxbean/JMXServiceURLTest.java Thu Sep 11 11:25:48 2008 -0700 +++ b/jdk/test/javax/management/mxbean/JMXServiceURLTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -23,16 +23,24 @@ /* * @test JMXServiceURLTest - * @bug 6607114 6670375 + * @bug 6607114 6670375 6731410 * @summary Test that JMXServiceURL works correctly in MXBeans * @author Eamonn McManus */ +import java.io.InvalidObjectException; import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.management.Attribute; import javax.management.JMX; +import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; @@ -56,6 +64,25 @@ } } + private static enum Part { + PROTOCOL("protocol", SimpleType.STRING, "rmi", 25, "", "a:b", "/", "?", "#"), + HOST("host", SimpleType.STRING, "a.b.c", 25, "a..b", ".a.b", "a.b."), + PORT("port", SimpleType.INTEGER, 25, "25", -25), + PATH("URLPath", SimpleType.STRING, "/tiddly", 25, "tiddly"); + + Part(String name, OpenType openType, Object validValue, Object... bogusValues) { + this.name = name; + this.openType = openType; + this.validValue = validValue; + this.bogusValues = bogusValues; + } + + final String name; + final OpenType openType; + final Object validValue; + final Object[] bogusValues; + } + public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("a:b=c"); @@ -91,6 +118,92 @@ Object actualValue = cd.get(itemName); assertEquals(expectedValue, actualValue); } + + // Now make sure we reject any bogus-looking CompositeData items. + // We first try every combination of omitted items (items can be + // null but cannot be omitted), then we try every combination of + // valid and bogus items. + final Part[] parts = Part.values(); + final int nParts = parts.length; + final int maxPartMask = (1 << nParts) - 1; + // Iterate over all possibilities of included and omitted, except + // 0, because a CompositeDataSupport must have at least one element, + // and maxPartMask, where all items are included and the result is valid. + for (int mask = 1; mask < maxPartMask; mask++) { + Map cdMap = new HashMap(); + List names = new ArrayList(); + List types = new ArrayList(); + for (int i = 0; i < nParts; i++) { + if ((mask & (1 << i)) != 0) { + Part part = parts[i]; + cdMap.put(part.name, part.validValue); + names.add(part.name); + types.add(openTypeForValue(part.validValue)); + } + } + String[] nameArray = names.toArray(new String[0]); + OpenType[] typeArray = types.toArray(new OpenType[0]); + CompositeType badct = new CompositeType( + "bad", "descr", nameArray, nameArray, typeArray); + CompositeData badcd = new CompositeDataSupport(badct, cdMap); + checkBad(mbs, name, badcd); + } + + int nBogus = 1; + for (Part part : parts) + nBogus *= (part.bogusValues.length + 1); + // Iterate over all combinations of bogus values. We are basically + // treating each Part as a digit while counting up from 1. A digit + // value of 0 stands for the valid value of that Part, and 1 on + // stand for the bogus values. Hence an integer where all the digits + // are 0 would represent a valid CompositeData, which is why we + // start from 1. + for (int bogusCount = 1; bogusCount < nBogus; bogusCount++) { + List names = new ArrayList(); + List types = new ArrayList(); + int x = bogusCount; + Map cdMap = new HashMap(); + for (Part part : parts) { + int digitMax = part.bogusValues.length + 1; + int digit = x % digitMax; + Object value = (digit == 0) ? + part.validValue : part.bogusValues[digit - 1]; + cdMap.put(part.name, value); + names.add(part.name); + types.add(openTypeForValue(value)); + x /= digitMax; + } + String[] nameArray = names.toArray(new String[0]); + OpenType[] typeArray = types.toArray(new OpenType[0]); + CompositeType badct = new CompositeType( + "bad", "descr", nameArray, nameArray, typeArray); + CompositeData badcd = new CompositeDataSupport(badct, cdMap); + checkBad(mbs, name, badcd); + } + } + + private static OpenType openTypeForValue(Object value) { + if (value instanceof String) + return SimpleType.STRING; + else if (value instanceof Integer) + return SimpleType.INTEGER; + else + throw new AssertionError("Value has invalid type: " + value); + } + + private static void checkBad( + MBeanServer mbs, ObjectName name, CompositeData badcd) + throws Exception { + try { + mbs.setAttribute(name, new Attribute("Url", badcd)); + throw new Exception("Expected exception for: " + badcd); + } catch (MBeanException e) { + if (!(e.getCause() instanceof InvalidObjectException)) { + throw new Exception( + "Wrapped exception should be InvalidObjectException", e); + } + System.out.println("OK: rejected " + badcd); + } } private static void assertEquals(Object expect, Object actual) diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/DomainCreationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/DomainCreationTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,329 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test DomainCreationTest.java + * @summary Test the creation and registration of JMXDomain instances. + * @author Daniel Fuchs + * @run clean DomainCreationTest Wombat WombatMBean + * @run build DomainCreationTest Wombat WombatMBean + * @run main DomainCreationTest + */ + + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.RuntimeMBeanException; +import javax.management.RuntimeOperationsException; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.MBeanServerSupport; + +/** + * Test simple creation/registration of namespace. + * + */ +public class DomainCreationTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalDomainRepository + extends MBeanServerSupport { + private final MBeanServer server; + private final String domain; + + + public class DynamicMBeanProxy implements DynamicMBean { + + private final MBeanServer server; + private final ObjectName name; + + public DynamicMBeanProxy(MBeanServer s, ObjectName n) { + this.server = s; + this.name = n; + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, + MBeanException, ReflectionException { + try { + return server.getAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + server.setAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList getAttributes(String[] attributes) { + try { + return server.getAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList setAttributes(AttributeList attributes) { + try { + return server.setAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public Object invoke(String actionName, Object[] params, + String[] signature) throws MBeanException, + ReflectionException { + try { + return server.invoke(name, actionName, params, signature); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public MBeanInfo getMBeanInfo() { + try { + return server.getMBeanInfo(name); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + } + + public LocalDomainRepository(String domain) { + this.server = MBeanServerFactory.newMBeanServer(); + this.domain = domain; + } + + @Override + protected Set getNames() { + try { + final ObjectName name = + ObjectName.getInstance(domain+":*"); + return server.queryNames(name, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + return new DynamicMBeanProxy(server, name); + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return (NotificationEmitter) mbean; + return null; + } + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + /** + * Check that we can register a JMXNamespace MBean, using its standard + * ObjectName. + * @throws java.lang.Exception + */ + public static void testGoodObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final ObjectInstance oi = + server.registerMBean(new JMXDomain( + new LocalDomainRepository("gloups")),name); + System.out.println("Succesfully registered namespace: "+name); + try { + if (! name.equals(oi.getObjectName())) + throw new RuntimeException("testGoodObjectName: TEST failed: " + + "namespace registered as: "+ + oi.getObjectName()+" expected: "+name); + } finally { + server.unregisterMBean(oi.getObjectName()); + } + System.out.println("Succesfully unregistered namespace: "+name); + System.out.println("testGoodObjectName PASSED"); + } + + /** + * Check that we cannot register a JMXNamespace MBean, if we don't use + * its standard ObjectName. + * @throws java.lang.Exception + */ + public static void testBadObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("d:k=v"); + try { + server.registerMBean(new JMXDomain( + new LocalDomainRepository("d")),name); + System.out.println("testBadObjectName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadObjectName PASSED"); + } + + /** + * Check that we cannot register a Domain MBean in a domain that already + * exists. + * + * @throws java.lang.Exception + */ + public static void testBadDomain() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glips:k=v"); + server.registerMBean(new Wombat(),name); + + final ObjectName dname = + JMXDomain.getDomainObjectName("glips"); + + try { + server.registerMBean(new JMXDomain( + new LocalDomainRepository("glips")),dname); + System.out.println("testBadDomain: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeOperationsException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected RuntimeOperationsException - got "+ + x); + } finally { + server.unregisterMBean(name); + } + if (exp == null) { + server.unregisterMBean(dname); + } + if (exp == null) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadDomain PASSED"); + } + + + public static void main(String... args) throws Exception { + testCreateWithNull(); + testGoodObjectName(); + testBadObjectName(); + testBadDomain(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test EventWithNamespaceControlTest.java + * @summary Check -Djmx.remote.use.event.service=true and + * -Djmx.remote.delegate.event.service + * @author Daniel Fuchs + * @run clean EventWithNamespaceTest EventWithNamespaceControlTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true EventWithNamespaceTest.java + EventWithNamespaceControlTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main/othervm -Djmx.remote.use.event.service=true EventWithNamespaceControlTest + * @run main/othervm EventWithNamespaceControlTest + * @run main/othervm -Djmx.remote.delegate.event.service=false EventWithNamespaceControlTest java.lang.UnsupportedOperationException + */ + +import java.util.Collections; +import java.util.Map; +import java.util.logging.Logger; +import javax.management.RuntimeOperationsException; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class EventWithNamespaceControlTest extends EventWithNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(EventWithNamespaceControlTest.class.getName()); + + /** Creates a new instance of EventWithNamespaceTest */ + public EventWithNamespaceControlTest() { + } + + + + public static void main(String[] args) { + final EventWithNamespaceControlTest test = + new EventWithNamespaceControlTest(); + if (args.length == 0) { + test.run(args); + System.out.println("Test successfully passed"); + } else { + try { + test.run(args); + throw new RuntimeException("Test should have failed."); + } catch (RuntimeOperationsException x) { + if (! args[0].equals(x.getCause().getClass().getName())) { + System.err.println("Unexpected wrapped exception: "+ + x.getCause()); + throw x; + } else { + System.out.println("Got expected exception: "+x.getCause()); + } + } + } + } + + public Map getServerMap() { + Map retValue = Collections.emptyMap(); + return retValue; + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/EventWithNamespaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/EventWithNamespaceTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,241 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test EventWithNamespaceTest.java 1.8 + * @bug 6539857 + * @summary General Namespace & Notifications test. + * @author Daniel Fuchs + * @run clean EventWithNamespaceTest Wombat WombatMBean + * JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true EventWithNamespaceTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main EventWithNamespaceTest + */ + +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class EventWithNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(EventWithNamespaceTest.class.getName()); + + /** Creates a new instance of EventWithNamespaceTest */ + public EventWithNamespaceTest() { + } + + private static Map singletonMap(String key, Object value) { + final Map map = new HashMap(); + map.put(key,value); + return map; + } + + public Map getServerMap() { + return singletonMap(JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE,"true"); + } + + public JMXServiceURL export(MBeanServer server) + throws Exception { + final JMXServiceURL in = new JMXServiceURL("rmi",null,0); + final Map env = getServerMap(); + + final JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(in,env,null); + final ObjectName csname = ObjectName. + getInstance(cs.getClass().getPackage().getName()+ + ":type="+cs.getClass().getSimpleName()); + server.registerMBean(cs,csname); + cs.start(); + return cs.getAddress(); + } + + public static class Counter { + int count; + public synchronized int count() { + count++; + notifyAll(); + return count; + } + public synchronized int peek() { + return count; + } + public synchronized int waitfor(int max, long timeout) + throws InterruptedException { + final long start = System.currentTimeMillis(); + while (count < max && timeout > 0) { + final long rest = timeout - + (System.currentTimeMillis() - start); + if (rest <= 0) break; + wait(rest); + } + return count; + } + } + + public static class CounterListener + implements NotificationListener { + final private Counter counter; + public CounterListener(Counter counter) { + this.counter = counter; + } + public void handleNotification(Notification notification, + Object handback) { + System.out.println("Received notif from " + handback + + ":\n\t" + notification); + if (!notification.getSource().equals(handback)) { + System.err.println("OhOh... Unexpected source: \n\t"+ + notification.getSource()+"\n\twas expecting:\n\t"+ + handback); + } + counter.count(); + } + } + + public void simpleTest(String[] args) { + try { + final MBeanServer server1 = + ManagementFactory.getPlatformMBeanServer(); + final JMXServiceURL url1 = export(server1); + + final MBeanServer server2 = + MBeanServerFactory.createMBeanServer("server2"); + final JMXServiceURL url2 = export(server2); + + final MBeanServer server3 = + MBeanServerFactory.createMBeanServer("server3"); + final JMXServiceURL url3 = export(server3); + + final ObjectInstance ncinst = + NamespaceController.createInstance(server1); + + final NamespaceControllerMBean nc = + JMX.newMBeanProxy(server1,ncinst.getObjectName(), + NamespaceControllerMBean.class); + + final String mount2 = nc.mount(url2,"server2",null); + final String mount3 = nc.mount(url3,"server2//server3", + null); + + final ObjectName deep = + new ObjectName("server2//server3//bush:type=Wombat,name=kanga"); + server1.createMBean(Wombat.class.getName(),deep); + + System.err.println("There's a wombat in the bush!"); + + final Counter counter = new Counter(); + + final NotificationListener listener = + new CounterListener(counter); + + final JMXConnector jc = JMXConnectorFactory.connect(url1); + final MBeanServerConnection conn1 = + jc.getMBeanServerConnection(); + final ObjectName shallow = + new ObjectName("bush:"+ + deep.getKeyPropertyListString()); + final MBeanServerConnection conn2 = + JMXNamespaces.narrowToNamespace(conn1,"server2//server3"); + + final WombatMBean proxy1 = + JMX.newMBeanProxy(conn1,deep,WombatMBean.class,true); + final WombatMBean proxy2 = + JMX.newMBeanProxy(conn2,shallow,WombatMBean.class,true); + + + System.err.println("Adding first Notification Listener"); + conn1.addNotificationListener(deep,listener,null,deep); + System.err.println("Adding second Notification Listener"); + ((NotificationEmitter)proxy2). + addNotificationListener(listener,null,shallow); + final JMXConnector c3 = JMXConnectorFactory.connect(url3, + singletonMap(JMXConnector.USE_EVENT_SERVICE,"false")); + System.err.println("Adding third Notification Listener"); + c3.getMBeanServerConnection(). + addNotificationListener(shallow,listener,null,shallow); + System.err.println("Set attribute to trigger notif"); + proxy1.setCaption("I am a new Wombat!"); + System.err.println("Get attribute"); + System.err.println("New caption: "+proxy2.getCaption()); + System.err.println("Wait for Notifs..."); + final int rcvcount = counter.waitfor(3,3000); + if (rcvcount != 3) + throw new RuntimeException("simpleTest failed: "+ + "received count is " +rcvcount); + System.err.println("simpleTest: got expected "+rcvcount+ + " notifs"); + + System.err.println("removing all listeners"); + conn1.removeNotificationListener(deep,listener,null,deep); + ((NotificationEmitter)proxy2) + .removeNotificationListener(listener,null,shallow); + c3.getMBeanServerConnection(). + removeNotificationListener(shallow,listener,null,shallow); + + System.err.println("simpleTest passed: got "+rcvcount+ + " notifs"); + + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("simpleTest failed: " + x,x); + } + } + + public void run(String[] args) { + simpleTest(args); + } + + public static void main(String[] args) { + new EventWithNamespaceTest().run(args); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/ExportNamespaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/ExportNamespaceTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test ExportNamespaceTest.java + * @summary Test that you can export a single namespace through a + * JMXConnectorServer. + * @author Daniel Fuchs + * @run clean ExportNamespaceTest Wombat WombatMBean + * @run build ExportNamespaceTest Wombat WombatMBean + * @run main ExportNamespaceTest + */ + +import javax.management.JMX; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + + +/** + * Test simple creation/registration of namespace. + * + */ +public class ExportNamespaceTest { + + public static void testExport() throws Exception { + final JMXNamespace my = + new JMXNamespace(MBeanServerFactory.newMBeanServer()); + final MBeanServer s = MBeanServerFactory.newMBeanServer(); + final ObjectName myname = JMXNamespaces.getNamespaceObjectName("my"); + final ObjectName wname = ObjectName.getInstance("backyard:type=Wombat"); + my.getSourceServer().registerMBean(new Wombat(),wname); + s.registerMBean(my,myname); + + if (!s.queryNames(new ObjectName("my//b*:*"),null).contains( + JMXNamespaces.insertPath("my", wname))) { + throw new RuntimeException("1: Wombat not found: "+wname); + } + + final MBeanServer cd = JMXNamespaces.narrowToNamespace(s, "my"); + if (!cd.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("2: Wombat not found: "+wname); + } + + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, cd); + server.start(); + + final JMXConnector jc = JMXConnectorFactory. + connect(server.getAddress(),null); + final MBeanServerConnection mbsc = jc.getMBeanServerConnection(); + + if (!mbsc.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("3: Wombat not found: "+wname); + } + System.out.println("Found a Wombat in my backyard."); + + final String deepThoughts = "I want to leave this backyard!"; + final WombatMBean w = JMX.newMBeanProxy(mbsc, wname, WombatMBean.class); + w.setCaption(deepThoughts); + if (!deepThoughts.equals(w.getCaption())) + throw new RuntimeException("4: Wombat is not thinking right: "+ + w.getCaption()); + + } + + public static void main(String... args) throws Exception { + testExport(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXDomainTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXDomainTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,512 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test JMXDomainTest.java + * @summary Basic test for JMXDomain. + * @author Daniel Fuchs + * @run clean JMXDomainTest Wombat WombatMBean + * @run build JMXDomainTest Wombat WombatMBean + * @run main JMXDomainTest + */ + + +import java.util.Collections; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.Set; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +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.ReflectionException; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.MBeanServerSupport; + +/** + * Test simple creation/registration of namespace. + * + */ +public class JMXDomainTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalDomainRepository + extends MBeanServerSupport { + private final MBeanServer server; + private final String domain; + + public class DynamicMBeanProxy implements DynamicMBean { + + private final MBeanServer server; + private final ObjectName name; + + public DynamicMBeanProxy(MBeanServer s, ObjectName n) { + this.server = s; + this.name = n; + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, + MBeanException, ReflectionException { + try { + return server.getAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + server.setAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList getAttributes(String[] attributes) { + try { + return server.getAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList setAttributes(AttributeList attributes) { + try { + return server.setAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public Object invoke(String actionName, Object[] params, + String[] signature) throws MBeanException, + ReflectionException { + try { + return server.invoke(name, actionName, params, signature); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public MBeanInfo getMBeanInfo() { + try { + return server.getMBeanInfo(name); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + } + + public LocalDomainRepository(String domain) { + this.server = MBeanServerFactory.newMBeanServer(); + this.domain = domain; + } + + @Override + protected Set getNames() { + try { + final ObjectName name = + ObjectName.getInstance(domain+":*"); + return server.queryNames(name, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (server.isRegistered(name)) + return new DynamicMBeanProxy(server, name); + throw new InstanceNotFoundException(name); + } + + + @Override + public NotificationEmitter + getNotificationEmitterFor(final ObjectName name) + throws InstanceNotFoundException { + if (server.isInstanceOf(name, NotificationEmitter.class.getName())) { + return new NotificationEmitter() { + + public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { + try { + server.removeNotificationListener(name, listener, filter, handback); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { + try { + server.addNotificationListener(name, listener, filter, handback); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { + try { + server.removeNotificationListener(name, listener); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public MBeanNotificationInfo[] getNotificationInfo() { + try { + return server.getMBeanInfo(name).getNotifications(); + } catch (Exception x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + }; + } + return null; + } + + @Override + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, + MBeanRegistrationException, NotCompliantMBeanException { + return server.registerMBean(object, name); + } + + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, + MBeanRegistrationException { + server.unregisterMBean(name); + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, ObjectName loaderName, Object[] params, + String[] signature, boolean useCLR) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + if (useCLR && loaderName == null) { + return server.createMBean(className, name, params, signature); + } + return server.createMBean(className, name, loaderName, + params, signature); + } + + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + public static void testRegisterSimple() throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + MBeanServerFactory.newMBeanServer()); + testRegister("testRegisterSimple: ",name,jmxDomain); + } + + public static void testRegisterPseudoVirtual() + throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + new LocalDomainRepository("gloups")); + testRegister("testRegisterPseudoVirtual: ",name,jmxDomain); + } + + public static void testRegister(final String test, + final ObjectName name, + final JMXDomain jmxDomain) throws Exception { + System.out.println(test+" START"); + MBeanServer server = newMBeanServer(); + final ObjectInstance oi = + server.registerMBean(jmxDomain,name); + System.out.println(test+"Succesfully registered namespace: "+name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered!"); + if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(name)) + fail(test+name+" not in queryNames"); + + final Thing thing = new Thing(); + final ObjectName thingName = new ObjectName("gloups:type=Thing"); + server.registerMBean(thing,thingName); + if (!server.isRegistered(thingName)) + fail(test+thingName+" is not registered!"); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(thingName)) + fail(test+thingName+" not in queryNames"); + + server.unregisterMBean(name); + if (server.isRegistered(thingName)) + fail(test+thingName+" is still registered!"); + if (server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(thingName)) + fail(test+thingName+" still in queryNames"); + + server.registerMBean(jmxDomain, name); + if (!server.isRegistered(thingName)) + fail(test+thingName+" is not registered again!"); + + System.out.println(test+" PASSED"); + } + + private static MBeanServerNotification pop( + BlockingQueue queue, + String type, + ObjectName mbean, + String test) + throws InterruptedException { + final Notification n = queue.poll(1, TimeUnit.SECONDS); + if (!(n instanceof MBeanServerNotification)) + fail(test+"expected MBeanServerNotification, got "+n); + final MBeanServerNotification msn = (MBeanServerNotification)n; + if (!type.equals(msn.getType())) + fail(test+"expected "+type+", got "+msn.getType()); + if (!mbean.apply(msn.getMBeanName())) + fail(test+"expected "+mbean+", got "+msn.getMBeanName()); + System.out.println(test+" got: "+msn); + return msn; + } + private static MBeanServerNotification popADD( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION, + mbean, test); + } + + private static MBeanServerNotification popREM( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + mbean, test); + } + + + public static void testRegisterNotifSimple() throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + MBeanServerFactory.newMBeanServer()); + testRegisterNotif("testRegisterNotifSimple: ",name,jmxDomain); + } + + public static void testRegisterNotifPseudoVirtual() + throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + new LocalDomainRepository("gloups")); + testRegisterNotif("testRegisterNotifPseudoVirtual: ",name,jmxDomain); + } + + public static void testRegisterNotif(final String test, + final ObjectName name, + final JMXDomain jmxDomain) throws Exception { + System.out.println(test+" START"); + MBeanServer server = newMBeanServer(); + final ObjectInstance oi = + server.registerMBean(jmxDomain,name); + System.out.println(test+"Succesfully registered namespace: "+name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered!"); + + final BlockingQueue queue = + new ArrayBlockingQueue(10); + + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification,5,TimeUnit.SECONDS)) + throw new RuntimeException("timeout exceeded"); + } catch (Exception x) { + fail(test+"failed to handle notif", x); + } + } + }; + + server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + final Thing thing = new Thing(); + final ObjectName thingName = new ObjectName("gloups:type=Thing"); + + server.registerMBean(thing,thingName); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + popADD(queue, thingName, test); + server.unregisterMBean(thingName); + if (jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + popREM(queue, thingName, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.unregisterMBean(name); + popREM(queue, name, test); + + jmxDomain.getSourceServer().registerMBean(thing,thingName); + if (server.isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + jmxDomain.getSourceServer().unregisterMBean(thingName); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.registerMBean(jmxDomain, name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered again!"); + popADD(queue, name, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.registerMBean(thing,thingName); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + popADD(queue, thingName, test); + server.unregisterMBean(thingName); + if (jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + popREM(queue, thingName, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + System.out.println(test+" PASSED"); + } + + + + private static void fail(String msg) { + raise(new RuntimeException(msg)); + } + + private static void fail(String msg, Throwable cause) { + raise(new RuntimeException(msg,cause)); + } + + private static void raise(RuntimeException x) { + lastException = x; + exceptionCount++; + throw x; + } + + private static volatile Exception lastException = null; + private static volatile int exceptionCount = 0; + + public static void main(String... args) throws Exception { + testCreateWithNull(); + + testRegisterSimple(); + testRegisterNotifSimple(); + + testRegisterPseudoVirtual(); + testRegisterNotifPseudoVirtual(); + + if (lastException != null) + throw lastException; + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,272 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test JMXNamespaceSecurityTest.java + * @summary General JMXNamespaceSecurityTest test. + * @author Daniel Fuchs + * @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean + * LazyDomainTest + * @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean + * LazyDomainTest + * @run main/othervm JMXNamespaceSecurityTest namespace.policy + */ +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXConnectorServer; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class JMXNamespaceSecurityTest extends JMXNamespaceViewTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespaceSecurityTest.class.getName()); + + public static class NamedMBeanServerCreator + extends JMXNamespaceViewTest.MBeanServerConfigCreator { + public MBeanServer createMBeanServerFor(NamespaceConfig config) { + return MBeanServerFactory. + createNamedMBeanServer(config.name,config.name); + } + } + /** + * Creates a config for a hierarchy of namespaces, mixing local namespaces + * and remote namespaces using the given protocol. + * @param protocol The protocol that should be used for remote namespaces. + * @return A namespace config hierarchy. + * @throws java.lang.Exception + */ + public static NamespaceConfig[] makeConfig(String protocol) + throws Exception { + final NamespaceConfig[] config = { + // Top level namespace "top1" (local) + config("top1",wombats("wchief","w1","w2","w3"), + // top1//local1 + config("local1",wombats("wchief","ww1","ww2")), + // top1//local2 + config("local2",wombats("wchief","ww4","ww5","ww6"), + // top1//local2//local3 + config("local3",wombats("wchief","www1","www2")), + // top1//local2//rmi1 + config("rmi1",url(protocol),wombats("wchief","www3","www4","www5"))), + // top1//rmi2 + config("rmi2",url(protocol),wombats("wchief","ww7","ww8","ww9"), + // top1//rmi2//local4 + config("local4",wombats("wchief","www6","www7")), + // top1//rmi2//rmi3 + config("rmi3",url(protocol),wombats("wchief","www3","www4","www5"), + // top1//rmi2//rmi3//local5 + config("local5",wombats("wchief","wwww1"))))), + // Top level namespace "top2" (local) + config("top2",wombats("wchief","w21","w22","w23"), + // top2//local21 + config("local21",wombats("wchief","ww21","ww22")), + // top2//rmi22 + config("rmi22",url(protocol),wombats("wchief","ww27","ww28","ww29"), + // top2//rmi22//local24 + config("local24",wombats("wchief","www26","www27")), + // top2//rmi22//rmi23 + config("rmi23",url(protocol),wombats("wchief","www23","www24","www25"), + // top2//rmi22//rmi23//local25 + config("local25",wombats("wchief","wwww21"))))), + // Top level namespace "top3" (remote) + config("top3",url(protocol),wombats("wchief","w31","w32","w33"), + // top3//local31 + config("local31",wombats("wchief","ww31","ww32")), + // top3//rmi32 + config("rmi32",url(protocol),wombats("wchief","ww37","ww38","ww39"), + // top3//rmi32//local34 + config("local34",wombats("wchief","www36","www37")), + // top3//rmi32//rmi33 + config("rmi33",url(protocol),wombats("wchief","www33","www34","www35"), + // top3//rmi32//local35 + config("local35",wombats("wchief","wwww31"))))), + }; + return config; + } + + public static void test(MBeanServer server, NamespaceConfig[] namespaces) + throws Exception { + System.out.println("Launching test..."); + List cslist = load(server, + new NamedMBeanServerCreator(), namespaces); + Map inputMap = + new HashMap(); + + for (NamespaceConfig cfg : namespaces) { + fillMap(inputMap,"",cfg); + } + final MBeanServer platform = ManagementFactory.getPlatformMBeanServer(); + //if (System.getProperty("jmx.wait")!=null) { + /* + // if we wanted to lazy load the platform MBeanServer: + final LazyDomainTest.MBeanServerLoader loader = + new LazyDomainTest.MBeanServerLoader() { + public MBeanServer loadMBeanServer() { + return ManagementFactory.getPlatformMBeanServer(); + } + }; + final LazyDomainTest.MBeanServerProxy proxy = + new LazyDomainTest.MBeanServerProxy(loader); + final LazyDomainTest.LazyDomain domain = + new LazyDomainTest.LazyDomain(proxy); + server.registerMBean(domain, + JMXDomain.getDomainObjectName("java.lang")); + */ + // Mount java.lang MBeans into our private server so that + // visualvm can connect. + server.registerMBean( + new JMXDomain(platform), + JMXDomain.getDomainObjectName("java.lang")); + //} + if (System.getProperty("jmx.wait")!=null) { + platform.registerMBean(new JMXNamespace(server), + JMXNamespaces.getNamespaceObjectName("test")); + } + + System.setSecurityManager(new SecurityManager()); + + // Some sanity checks... The policy file should allow access + // to java.lang MBeans. + final ObjectName platnames = new ObjectName("java.lang:*"); + for (ObjectName o : platform.queryNames(platnames,null)) { + server.getMBeanInfo(o); + } + final Set lang = + new HashSet(server.queryNames(platnames, null)); + lang.remove(JMXDomain.getDomainObjectName("java.lang")); + if (!lang.equals(platform. + queryNames(platnames, null))) + throw new Exception("Wrong list of platform names: "+lang); + System.out.println("Got all java.lang MBeans: "+lang); + + // The policy file should allow to see all namespaces. + // check this... + final List patterns = new ArrayList(); + final Set paths = new TreeSet(); + final Set uuids = new HashSet(); + patterns.add(new ObjectName("*//:*")); + while (patterns.size()>0) { + System.out.println("server.queryNames("+patterns.get(0)+",null)"); + Set names = server.queryNames(patterns.remove(0),null); + System.out.println("found: "+names); + + for (ObjectName no : names) { + final String uuid = (String) server.getAttribute(no, "UUID"); + if (uuids.contains(uuid)) { + System.out.print("namespace "+no+", uuid="+uuid+ + " already parsed. Skipping"); + continue; + } + uuids.add(uuid); + patterns.add(new ObjectName(no.getDomain()+"*//:*")); + System.out.println("added pattern: "+ + new ObjectName(no.getDomain()+"*//:*")); + if (no.getDomain().endsWith(ClientContext.NAMESPACE+ + JMXNamespaces.NAMESPACE_SEPARATOR)) continue; + paths.add(no.getDomain().substring(0, + no.getDomain().length()- + JMXNamespaces.NAMESPACE_SEPARATOR.length())); + } + } + final TreeSet expected = new TreeSet(inputMap.keySet()); + if (!expected.equals(paths)) { + throw new Exception("wrong set of namespaces, expected "+ + expected+", got "+paths); + } + + System.out.println("Got all namespaces: "+paths); + + // Check that we can see all wombats. + // + ObjectName wchief = + new ObjectName("top1//rmi2//wombat:name=wchief,type=Wombat"); + String caption = (String) server.getAttribute(wchief,"Caption"); + System.out.println("wchief says "+caption); + Object mood = server.getAttribute(wchief,"Mood"); + System.out.println("wchief's mood on a scale of 100 is "+mood); + + ObjectName wchief2 = + new ObjectName("top1//wombat:name=wchief,type=Wombat"); + String caption2 = (String) server.getAttribute(wchief2,"Caption"); + System.out.println("wchief2 says "+caption2); + try { + Object mood2 = server.getAttribute(wchief2,"Mood"); + System.out.println("wchief2's mood on a scale of 100 is "+mood2); + throw new Exception("Expected security exception for "+ + "getAttribute("+wchief2+", \"Mood\""); + } catch (SecurityException x) { + System.out.println("wchief2's mood is unavailable: "+x); + } + try { + exportAndWaitIfNeeded(server); + } finally { + closeAll(cslist); + } + + } + /** Creates a new instance of JMXNamespaceTest */ + public JMXNamespaceSecurityTest() { + } + + public static void main(String[] args) throws Exception { + String osName = System.getProperty("os.name"); + System.out.println("os.name = " + osName); + if (!osName.equals("SunOS")) { + System.out.println("This test runs on Solaris only."); + System.out.println("Bye! Bye!"); + return; + } + final String policy = System.getProperty("test.src") + + File.separator + args[0]; + System.out.println("PolicyFile = " + policy); + System.setProperty("java.security.policy", policy); + if (!new File(System.getProperty("java.security.policy")).canRead()) + throw new IOException("no such file: "+ + System.getProperty("java.security.policy")); + test(MBeanServerFactory.createNamedMBeanServer("root","root"), + makeConfig("rmi")); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXNamespaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXNamespaceTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,714 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test JMXNamespaceTest.java + * @summary General JMXNamespace test. + * @author Daniel Fuchs + * @run clean JMXNamespaceTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true JMXNamespaceTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main/othervm JMXNamespaceTest + */ +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaceMBean; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.namespace.MBeanServerConnectionWrapper; +import javax.management.namespace.MBeanServerSupport; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class JMXNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespaceTest.class.getName()); + + /** Creates a new instance of JMXNamespaceTest */ + public JMXNamespaceTest() { + } + + public static class WombatRepository extends MBeanServerSupport { + final Wombat wombat; + final StandardMBean mbean; + final ObjectName wombatName; + + public WombatRepository(ObjectName wombatName) { + try { + wombat = new Wombat(); + mbean = wombat; + this.wombatName = wombatName; + wombat.preRegister(null,wombatName); + } catch (Exception x) { + throw new IllegalArgumentException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (wombatName.equals(name)) return mbean; + else throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + final Set res = Collections.singleton(wombatName); + return res; + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mb = getDynamicMBeanFor(name); + if (mb instanceof NotificationEmitter) + return (NotificationEmitter)mb; + return null; + } + } + + public static class SimpleTest { + public final String descr; + private final Class testClass; + private final Method method; + public SimpleTest(String descr) { + this.descr = descr; + this.testClass = JMXNamespaceTest.class; + try { + method = testClass. + getDeclaredMethod(descr,SimpleTestConf.class, + Object[].class); + } catch (NoSuchMethodException x) { + throw new IllegalArgumentException(descr+": test not found", + x); + } + } + + public void run(SimpleTestConf conf, Object... args) + throws Exception { + try { + method.invoke(null,conf,args); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception)cause; + if (cause instanceof Error) throw (Error)cause; + throw x; + } + } + } + + private static class SimpleTestConf { + public final Wombat wombat; + public final StandardMBean mbean; + public final String dirname; + public final ObjectName handlerName; + public final ObjectName wombatNickName; + public final ObjectName wombatName; + public final JMXNamespace wombatNamespace; + public final MBeanServer server; + public final WombatMBean proxy; + public SimpleTestConf(String[] args) throws Exception { + wombat = new Wombat(); + mbean = wombat; + dirname = "wombat"; + handlerName = + new ObjectName(dirname+"//:type=JMXNamespace"); + + wombatNickName = + new ObjectName("burrow:type=Wombat"); + + wombatName = + new ObjectName(dirname+"//"+wombatNickName); + + wombatNamespace = + new JMXNamespace( + new WombatRepository(wombatNickName)); + + server = ManagementFactory.getPlatformMBeanServer(); + System.out.println(handlerName+" registered="+ + server.isRegistered(handlerName)); + server.registerMBean(wombatNamespace,handlerName); + + try { + proxy = JMX.newMBeanProxy(server,wombatName, + WombatMBean.class); + } catch (Exception x) { + server.unregisterMBean(handlerName); + throw x; + } + } + + public void close() { + try { + server.unregisterMBean(handlerName); + } catch (Exception x) { + System.out.println("Failed to close: " + x); + x.printStackTrace(); + } + } + + public void test(SimpleTest test,Object... args) + throws Exception { + try { + test.run(this,args); + passed++; + } catch (Exception x) { + failed++; + System.err.println(test.descr+" failed: " + x); + x.printStackTrace(); + } + } + + public volatile int failed = 0; + public volatile int passed = 0; + } + + static void checkValue(String name,Object expected, Object returned) + throws InvalidAttributeValueException { + if (Collections.singletonList(expected). + equals(Collections.singletonList(returned))) return; + + throw new InvalidAttributeValueException("Bad value for "+ + name+": ["+returned+"] - was expecting ["+expected+"]"); + } + + // --------------------------------------------------------------- + // SIMPLE TESTS BEGIN HERE + // --------------------------------------------------------------- + + static void getCaptionTest(SimpleTestConf env, Object... args) + throws Exception { + System.out.println(env.proxy.getCaption()); + } + + static void setCaptionTest(SimpleTestConf env, Object... args) + throws Exception { + env.proxy.setCaption((String)args[0]); + final String result = env.proxy.getCaption(); + System.out.println(result); + checkValue("Caption",args[0],result); + } + + static void queryNamesTest1(SimpleTestConf env, Object... args) + throws Exception { + final ObjectName pat = + new ObjectName(env.handlerName.getDomain()+"*:*"); + final Set res = + env.server.queryNames(pat,null); + System.out.println("queryNamesTest1: "+res); + checkValue("names",Collections.singleton(env.wombatName),res); + } + + static void queryNamesTest2(SimpleTestConf env, Object... args) + throws Exception { + final ObjectName pat = + new ObjectName("*:"+ + env.wombatName.getKeyPropertyListString()); + final Set res = + env.server.queryNames(pat,null); + System.out.println("queryNamesTest2: "+res); + checkValue("names",Collections.emptySet(),res); + } + + static void getDomainsTest(SimpleTestConf env, Object... args) + throws Exception { + final List domains = + Arrays.asList(env.server.getDomains()); + System.out.println("getDomainsTest: "+domains); + if (domains.contains(env.wombatName.getDomain())) + throw new InvalidAttributeValueException("domain: "+ + env.wombatName.getDomain()); + if (!domains.contains(env.handlerName.getDomain())) + throw new InvalidAttributeValueException("domain not found: "+ + env.handlerName.getDomain()); + } + + // --------------------------------------------------------------- + // SIMPLE TESTS END HERE + // --------------------------------------------------------------- + + private static void simpleTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + try { + conf.test(new SimpleTest("getCaptionTest")); + conf.test(new SimpleTest("setCaptionTest"), + "I am a new Wombat!"); + conf.test(new SimpleTest("queryNamesTest1")); + conf.test(new SimpleTest("queryNamesTest2")); + conf.test(new SimpleTest("getDomainsTest")); + } finally { + conf.close(); + } + } catch (Exception x) { + System.err.println("simpleTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.out.println("simpleTest: "+conf.passed+ + " PASSED, " + conf.failed + " FAILED."); + if (conf.failed>0) { + System.err.println("simpleTest FAILED ["+conf.failed+"]"); + throw new RuntimeException("simpleTest FAILED ["+conf.failed+"]"); + } else { + System.err.println("simpleTest PASSED ["+conf.passed+"]"); + } + } + + public static void recursiveTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + try { + final JMXServiceURL url = + new JMXServiceURL("rmi","localHost",0); + final Map empty = Collections.emptyMap(); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + empty,conf.server); + server.start(); + final JMXServiceURL address = server.getAddress(); + final JMXConnector client = + JMXConnectorFactory.connect(address, + empty); + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + }; + final String[] signature2 = { + JMXServiceURL.class.getName(), + Map.class.getName(), + String.class.getName(), + }; + final Object[] params = { + address, + null, + }; + final MBeanServerConnection c = + client.getMBeanServerConnection(); + final ObjectName dirName1 = + new ObjectName("kanga//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName1, params,signature); + c.invoke(dirName1, "connect", null, null); + try { + final MemoryMXBean memory = + JMX.newMXBeanProxy(c, + new ObjectName("kanga//"+ + ManagementFactory.MEMORY_MXBEAN_NAME), + MemoryMXBean.class); + System.out.println("HeapMemory #1: "+ + memory.getHeapMemoryUsage().toString()); + final MemoryMXBean memory2 = + JMX.newMXBeanProxy(c, + new ObjectName("kanga//kanga//"+ + ManagementFactory.MEMORY_MXBEAN_NAME), + MemoryMXBean.class); + System.out.println("HeapMemory #2: "+ + memory2.getHeapMemoryUsage().toString()); + final Object[] params2 = { + address, + null, + "kanga//kanga" + // "kanga//kanga//roo//kanga", <= cycle + }; + final ObjectName dirName2 = + new ObjectName("kanga//roo//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName2, params2, signature2); + System.out.println(dirName2 + " created!"); + JMX.newMBeanProxy(c,dirName2, + JMXRemoteNamespaceMBean.class).connect(); + try { + final ObjectName wombatName1 = + new ObjectName("kanga//roo//"+conf.wombatName); + final ObjectName wombatName2 = + new ObjectName("kanga//roo//"+wombatName1); + final WombatMBean wombat1 = + JMX.newMBeanProxy(c,wombatName1,WombatMBean.class); + final WombatMBean wombat2 = + JMX.newMBeanProxy(c,wombatName2,WombatMBean.class); + final String newCaption="I am still the same old wombat"; + wombat1.setCaption(newCaption); + final String caps = conf.proxy.getCaption(); + System.out.println("Caption: "+caps); + checkValue("Caption",newCaption,caps); + final String caps1 = wombat1.getCaption(); + System.out.println("Caption #1: "+caps1); + checkValue("Caption #1",newCaption,caps1); + final String caps2 = wombat2.getCaption(); + System.out.println("Caption #2: "+caps2); + checkValue("Caption #2",newCaption,caps2); + final ObjectInstance instance = + NamespaceController.createInstance(conf.server); + final NamespaceControllerMBean controller = + JMX.newMBeanProxy(conf.server,instance.getObjectName(), + NamespaceControllerMBean.class); + final String[] dirs = controller.findNamespaces(); + System.out.println("directories: " + + Arrays.asList(dirs)); + final int depth = 4; + final String[] dirs2 = controller.findNamespaces(null,null,depth); + System.out.println("directories[depth="+depth+"]: " + + Arrays.asList(dirs2)); + for (String dir : dirs2) { + if (dir.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) + dir = dir.substring(0,dir.length()- + JMXNamespaces.NAMESPACE_SEPARATOR.length()); + if (dir.split(JMXNamespaces.NAMESPACE_SEPARATOR).length + > (depth+1)) { + throw new RuntimeException(dir+": depth exceeds "+depth); + } + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dir); + final JMXNamespaceMBean handler = + JMX.newMBeanProxy(conf.server,handlerName, + JMXNamespaceMBean.class); + try { + System.err.println("Directory "+dir+" domains: "+ + Arrays.asList(handler.getDomains())); + System.err.println("Directory "+dir+" default domain: "+ + handler.getDefaultDomain()); + System.err.println("Directory "+dir+" MBean count: "+ + handler.getMBeanCount()); + } catch(Exception x) { + System.err.println("get info failed for " + + dir +", "+handlerName+": "+x); + x.getCause().printStackTrace(); + throw x; + } + } + + } finally { + c.unregisterMBean(dirName2); + } + } finally { + c.unregisterMBean(dirName1); + client.close(); + server.stop(); + } + } finally { + conf.close(); + } + System.err.println("recursiveTest PASSED"); + } catch (Exception x) { + System.err.println("recursiveTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + } + + /** + * Test cycle detection. + * mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo + * touch kanga/roo/wombat + **/ + public static void probeKangaRooTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + try { + final JMXServiceURL url = + new JMXServiceURL("rmi","localHost",0); + final Map empty = Collections.emptyMap(); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + empty,conf.server); + server.start(); + final JMXServiceURL address = server.getAddress(); + final JMXConnector client = + JMXConnectorFactory.connect(address, + empty); + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + }; + + final Object[] params = { + address, + null, + }; + final MBeanServerConnection c = + client.getMBeanServerConnection(); + + // ln -s . kanga + final ObjectName dirName1 = + new ObjectName("kanga//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName1, params,signature); + c.invoke(dirName1, "connect", null, null); + try { + // ln -s kanga//kanga//roo//kanga roo + final JMXNamespace local = new JMXNamespace( + new MBeanServerConnectionWrapper(null, + JMXNamespaceTest.class.getClassLoader()){ + + @Override + protected MBeanServerConnection getMBeanServerConnection() { + return JMXNamespaces.narrowToNamespace(c, + "kanga//kanga//roo//kanga" + ); + } + + }); + final ObjectName dirName2 = + new ObjectName("roo//:type=JMXNamespace"); + conf.server.registerMBean(local,dirName2); + System.out.println(dirName2 + " created!"); + try { + // touch kanga/roo/wombat + final ObjectName wombatName1 = + new ObjectName("kanga//roo//"+conf.wombatName); + final WombatMBean wombat1 = + JMX.newMBeanProxy(c,wombatName1,WombatMBean.class); + final String newCaption="I am still the same old wombat"; + Exception x = null; + try { + wombat1.setCaption(newCaption); + } catch (RuntimeOperationsException r) { + x=r.getTargetException(); + System.out.println("Got expected exception: " + x); + // r.printStackTrace(); + } + if (x == null) + throw new RuntimeException("cycle not detected!"); + } finally { + c.unregisterMBean(dirName2); + } + } finally { + c.unregisterMBean(dirName1); + client.close(); + server.stop(); + } + } finally { + conf.close(); + } + System.err.println("probeKangaRooTest PASSED"); + } catch (Exception x) { + System.err.println("probeKangaRooTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + } + /** + * Test cycle detection 2. + * mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga + * touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ; + * touch kanga/roo/wombat + * + **/ + public static void probeKangaRooCycleTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + Exception failed = null; + try { + final JMXServiceURL url = + new JMXServiceURL("rmi","localHost",0); + final Map empty = Collections.emptyMap(); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + empty,conf.server); + server.start(); + final JMXServiceURL address = server.getAddress(); + final JMXConnector client = + JMXConnectorFactory.connect(address, + empty); + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + }; + final String[] signature2 = { + JMXServiceURL.class.getName(), + Map.class.getName(), + String.class.getName() + }; + final Object[] params = { + address, + Collections.emptyMap(), + }; + final Object[] params2 = { + address, + null, + "kanga", + }; + final MBeanServerConnection c = + client.getMBeanServerConnection(); + + // ln -s . roo + final ObjectName dirName1 = + new ObjectName("roo//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName1, params,signature); + c.invoke(dirName1, "connect",null,null); + try { + final Map emptyMap = + Collections.emptyMap(); + final JMXNamespace local = new JMXNamespace( + new MBeanServerConnectionWrapper( + JMXNamespaces.narrowToNamespace(c, + "roo//roo//"), + JMXNamespaceTest.class.getClassLoader())) { + }; + // ln -s roo/roo kanga + final ObjectName dirName2 = + new ObjectName("kanga//:type=JMXNamespace"); + conf.server.registerMBean(local,dirName2); + System.out.println(dirName2 + " created!"); + try { + // touch kanga/roo/wombat + final ObjectName wombatName1 = + new ObjectName("kanga//roo//"+conf.wombatName); + final WombatMBean wombat1 = + JMX.newMBeanProxy(c,wombatName1,WombatMBean.class); + final String newCaption="I am still the same old wombat"; + wombat1.setCaption(newCaption); + // rm roo + c.unregisterMBean(dirName1); + // ln -s kanga roo + System.err.println("**** Creating " + dirName1 + + " ****"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName1, params2,signature2); + System.err.println("**** Created " + dirName1 + + " ****"); + Exception x = null; + try { + // touch kanga/roo/wombat + wombat1.setCaption(newCaption+" I hope"); + } catch (RuntimeOperationsException r) { + x=(Exception)r.getCause(); + System.out.println("Got expected exception: " + x); + //r.printStackTrace(); + } + if (x == null) + throw new RuntimeException("should have failed!"); + x = null; + try { + // ls kanga/roo/wombat + System.err.println("**** Connecting " + dirName1 + + " ****"); + JMX.newMBeanProxy(c,dirName1, + JMXRemoteNamespaceMBean.class).connect(); + System.err.println("**** Connected " + dirName1 + + " ****"); + } catch (IOException r) { + x=r; + System.out.println("Got expected exception: " + x); + //r.printStackTrace(); + } + System.err.println("**** Expected Exception Not Raised ****"); + if (x == null) { + System.out.println(dirName1+" contains: "+ + c.queryNames(new ObjectName( + dirName1.getDomain()+"*:*"),null)); + throw new RuntimeException("cycle not detected!"); + } + } catch (Exception t) { + if (failed == null) failed = t; + } finally { + c.unregisterMBean(dirName2); + } + } finally { + try { + c.unregisterMBean(dirName1); + } catch (Exception t) { + if (failed == null) failed = t; + System.err.println("Failed to unregister "+dirName1+ + ": "+t); + } + try { + client.close(); + } catch (Exception t) { + if (failed == null) failed = t; + System.err.println("Failed to close client: "+t); + } + try { + server.stop(); + } catch (Exception t) { + if (failed == null) failed = t; + System.err.println("Failed to stop server: "+t); + } + } + } finally { + try { + conf.close(); + } catch (Exception t) { + if (failed == null) failed = t; + System.err.println("Failed to stop server: "+t); + } + } + if (failed != null) throw failed; + System.err.println("probeKangaRooCycleTest PASSED"); + } catch (Exception x) { + System.err.println("probeKangaRooCycleTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + } + public static void main(String[] args) { + simpleTest(args); + recursiveTest(args); + probeKangaRooTest(args); + probeKangaRooCycleTest(args); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXNamespaceViewTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,549 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test JMXNamespaceViewTest.java + * @summary Test the JMXNamespaceView class. + * @author Daniel Fuchs + * @run clean JMXNamespaceViewTest Wombat WombatMBean + * @run build JMXNamespaceViewTest Wombat WombatMBean + * @run main JMXNamespaceViewTest + */ + + +import java.lang.management.ManagementFactory; +import java.net.ServerSocket; +import java.rmi.registry.LocateRegistry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.management.JMException; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaceView; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * A simple test to test the JMXNamespaceViewTest... + * @author dfuchs + */ +public class JMXNamespaceViewTest { + + // TODO: Remove this when contexts are added. + public static class ClientContext { + public final static String NAMESPACE = "jmx.context"; + } + + /** + * Describe the configuration of a namespace + */ + public static class NamespaceConfig { + /** name of the namespace - no // allowed **/ + public String name; + /** + * JMXServiceURL through which the namespace is exported, if it + * is a remote namespace. {@code null} if the namespace is local. + * This is an inpur URL - eg: new JMXServiceURL("rmi",null,0).toString() + * is acceptable here. + */ + public String jmxurl; + /** + * Values of the name= key for each WombatMBean contained in the + * namespace. + */ + public String[] wombats; + /** list of child namespace **/ + public NamespaceConfig[] children; + } + + /** + * Creates a NamespaceConfig record for a local namespace. + * @param name name of the namespace + * @param wombats names of WombatMBean it should contain. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String[] wombats) { + return config(name,null,wombats); + } + + /** + * Creates a NamespaceConfig record for a remote namespace. + * @param name name of the namespace + * @param jmxurl input JMXServiceURL for creating the JMXConnectorServer + * @param wombats names of WombatMBean it should contain. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String jmxurl, + String[] wombats) { + return config(name,jmxurl,wombats,(NamespaceConfig[])null); + } + + /** + * Creates a NamespaceConfig record for a local namespace. + * @param name name of the namespace + * @param wombats names of WombatMBean it should contain. + * @param children list of sub namespaces. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String[] wombats, + NamespaceConfig... children) { + return config(name,null,wombats,children); + } + + /** + * Creates a NamespaceConfig record for a remote namespace. + * @param name name of the namespace + * @param jmxurl input JMXServiceURL for creating the JMXConnectorServer + * @param wombats names of WombatMBean it should contain. + * @param children list of sub namespaces. + * @return a NamespaceConfig. + */ + static NamespaceConfig config(String name, String jmxurl, String[] wombats, + NamespaceConfig... children) { + final NamespaceConfig cfg = new NamespaceConfig(); + cfg.name=name; cfg.jmxurl=jmxurl; cfg.wombats=wombats; + cfg.children=children; + return cfg; + } + + /** + * Returns the given names. This is a utility method to ease code + * reading. + * @param names names of Wombat MBeans. + * @return the given names. + */ + static String[] wombats(String... names) { + return names; + } + + /** + * Creates a JMXServiceURL string for the given protocol. + * This is also a utility method to ease code reading. + * @param protocol The protocol name (e.g. "rmi") + * @return A JMXServiceURL string. + * @throws Exception if creation of the JMXServiceURL fails. + */ + static String url(String protocol) throws Exception { + return new JMXServiceURL(protocol,null,0).toString(); + } + + /** + * Creates a config for a hierarchy of namespaces, mixing local namespaces + * and remote namespaces using the given protocol. + * @param protocol The protocol that should be used for remote namespaces. + * @return A namespace config hierarchy. + * @throws java.lang.Exception + */ + public static NamespaceConfig[] makeConfig(String protocol) + throws Exception { + final NamespaceConfig[] config = { + // Top level namespace "top1" (local) + config("top1",wombats("wchief","w1","w2","w3"), + // top1//local1 + config("local1",wombats("wchief","ww1","ww2")), + // top1//local2 + config("local2",wombats("wchief","ww4","ww5","ww6"), + // top1//local2//local3 + config("local3",wombats("wchief","www1","www2")), + // top1//local2//rmi1 + config("rmi1",url(protocol),wombats("wchief","www3","www4","www5"))), + // top1//rmi2 + config("rmi2",url(protocol),wombats("wchief","ww7","ww8","ww9"), + // top1//rmi2//local4 + config("local4",wombats("wchief","www6","www7")), + // top1//rmi2//rmi3 + config("rmi3",url(protocol),wombats("wchief","www3","www4","www5"), + // top1//rmi2//rmi3//local5 + config("local5",wombats("wchief","wwww1"))))), + // Top level namespace "top2" (local) + config("top2",wombats("wchief","w21","w22","w23"), + // top2//local21 + config("local21",wombats("wchief","ww21","ww22")), + // top2//rmi22 + config("rmi22",url(protocol),wombats("wchief","ww27","ww28","ww29"), + // top2//rmi22//local24 + config("local24",wombats("wchief","www26","www27")), + // top2//rmi22//rmi23 + config("rmi23",url(protocol),wombats("wchief","www23","www24","www25"), + // top2//rmi22//rmi23//local25 + config("local25",wombats("wchief","wwww21"))))), + // Top level namespace "top3" (remote) + config("top3",url(protocol),wombats("wchief","w31","w32","w33"), + // top3//local31 + config("local31",wombats("wchief","ww31","ww32")), + // top3//rmi32 + config("rmi32",url(protocol),wombats("wchief","ww37","ww38","ww39"), + // top3//rmi32//local34 + config("local34",wombats("wchief","www36","www37")), + // top3//rmi32//rmi33 + config("rmi33",url(protocol),wombats("wchief","www33","www34","www35"), + // top3//rmi32//local35 + config("local35",wombats("wchief","wwww31"))))), + }; + return config; + } + + /** + * Close all connector servers in the list. + * @param cslist List of connector servers to close. + */ + public static void closeAll(List cslist) { + for (JMXConnectorServer cs : cslist) { + try { + cs.stop(); + } catch (Exception xx) { + System.err.println("Failed to stop connector: " + xx); + } + } + } + + public static class MBeanServerConfigCreator { + public MBeanServer createMBeanServerFor(NamespaceConfig config) { + return MBeanServerFactory.newMBeanServer(); + } + } + + /** + * Load the given namespace configuration inside the given MBeanServer. + * Return a list of connector servers created in the process. + * @param server The MBeanServer in which the namespaces must + * be created. + * @param namespaces The list of namespaces to create. + * @return a list of started connector servers. + * @throws java.lang.Exception failed to create the specified namespaces. + */ + public static List load(MBeanServer server, + MBeanServerConfigCreator factory, + NamespaceConfig... namespaces) throws Exception { + final List cslist = + new ArrayList(); + try { + final ObjectName creator = + new ObjectName("jmx.creator:type=JMXNamespaceCreator"); + if (System.getProperty("jmx.wait")!=null + && !server.isRegistered(creator)) { + server.registerMBean(new JMXNamespaceCreator(),creator); + } + for (NamespaceConfig cfg : namespaces) { + final MBeanServer srv = factory.createMBeanServerFor(cfg); + if (System.getProperty("jmx.wait")!=null + && !srv.isRegistered(creator)) { + srv.registerMBean(new JMXNamespaceCreator(),creator); + } + if (cfg.wombats != null) { + for (String w : cfg.wombats) { + final ObjectName n = + new ObjectName("wombat:type=Wombat,name=" + w); + final WombatMBean ww = new Wombat(); + srv.registerMBean(ww, n); + } + } + if (cfg.children != null) { + cslist.addAll(load(srv, factory, cfg.children)); + } + JMXNamespace nm; + if (cfg.jmxurl == null) { + nm = new JMXNamespace(srv); + } else { + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL(cfg.jmxurl), + null, srv); + srv.registerMBean(cs, + new ObjectName("jmx.remote:type=JMXConnectorServer")); + cs.start(); + cslist.add(cs); + nm = JMXRemoteNamespace. + newJMXRemoteNamespace(cs.getAddress(), + null); + } + server.registerMBean(nm, + JMXNamespaces.getNamespaceObjectName(cfg.name)); + if (nm instanceof JMXRemoteNamespace) { + server.invoke( + JMXNamespaces.getNamespaceObjectName(cfg.name), + "connect", null, null); + } + } + } catch (Exception x) { + closeAll(cslist); + throw x; + } + return cslist; + } + + /** + * Add an entry {@code } in the map for the given + * namespace and its subnamespaces. + * @param map A {@code Map}. + * @param parent The path of the parent workspace. + * @param cfg The NamespaceConfig hierarchy to index in the map. + */ + public static void fillMap(Map map, String parent, + NamespaceConfig cfg) { + + final String where; + if (parent == null || parent.equals("")) + where=cfg.name; + else + where=parent+JMXNamespaces.NAMESPACE_SEPARATOR+cfg.name; + map.put(where,cfg); + if (cfg.children==null) return; + for(NamespaceConfig child:cfg.children) { + fillMap(map,where,child); + } + } + + /** + * Compare a list of namespace names obtained from JMXNamespaceView.list() + * with the expected clildren list of the corresponding NamespaceConfig. + * @param list A list of namespace names + * @param children A list of NamespaceConfig correspondng to expected + * namespace. + * @param fail If true and the comparison yields false, throws an + * exception instead of simply returning false. + * @return true if OK, false if NOK. + */ + private static boolean compare(String[] list, NamespaceConfig[] children, + boolean fail) { + final List found = new ArrayList(Arrays.asList(list)); + if (found.contains(ClientContext.NAMESPACE)) + found.remove(ClientContext.NAMESPACE); + + if (children == null && found.size()==0) return true; + if (children == null && fail == false) return false; + if (children == null) throw new RuntimeException( + "No child expected. Found "+Arrays.toString(list)); + final Set names = new HashSet(); + for (NamespaceConfig cfg : children) { + names.add(cfg.name); + if (found.contains(cfg.name)) continue; + if (!fail) return false; + throw new RuntimeException(cfg.name+" not found in "+ + found); + } + found.removeAll(names); + if (found.size()==0) return true; + if (fail==false) return false; + throw new RuntimeException("found additional namespaces: "+ + found); + } + + /** + * Compares the result of queryNames(null,null) with a set of expected + * wombats. + * @param where The path of the namespace that was queried. + * @param list The set of ObjectNames found. + * @param wombats The expected list of wombats. + * @param fail If true and the comparison yields false, throws an + * exception instead of simply returning false. + * @return true if OK, false if NOK. + * @throws java.lang.Exception something went wrong. + */ + private static boolean compare(String where, + Setlist, String[] wombats, + boolean fail) throws Exception { + final Set found = new HashSet(); + final Set expected = new HashSet(); + for (ObjectName n : list) { + if ("Wombat".equals(n.getKeyProperty("type"))) + found.add(n); + } + for(String w : wombats) { + final ObjectName n = + new ObjectName("wombat:type=Wombat,name=" + w); + expected.add(n); + if (found.contains(n)) continue; + if (fail == false) return false; + throw new RuntimeException(where+ + ": Wombat "+w+" not found in "+found); + } + found.removeAll(expected); + if (found.size()==0) { + System.out.println(where+": found all expected: "+expected); + return true; + } + if (fail==false) return false; + throw new RuntimeException(where+": found additional MBeans: "+ + found); + } + + /** + * A generic test to test JMXNamespaceView over a namespace configuration. + * @param server The MBeanServer in which to load the namespace + * config. + * @param namespaces The namespace config to run the test over... + * @throws java.lang.Exception + */ + public static void doTest(MBeanServer server, NamespaceConfig... namespaces) + throws Exception { + List cslist = load(server, + new MBeanServerConfigCreator(), namespaces); + Map inputMap = + new HashMap(); + + for (NamespaceConfig cfg : namespaces) { + fillMap(inputMap,"",cfg); + } + try { + final JMXNamespaceView root = new JMXNamespaceView(server); + List vlist = new ArrayList(); + vlist.add(root); + + while (!vlist.isEmpty()) { + JMXNamespaceView v = vlist.remove(0); + final String where = v.isRoot()?"root":v.where(); + System.out.println(where+": "+ + v.getMBeanServerConnection().queryNames(null,null)); + for (String ns : v.list()) { + final JMXNamespaceView down = v.down(ns); + vlist.add(down); + if (!down.where().equals(v.isRoot()?ns:where+ + JMXNamespaces.NAMESPACE_SEPARATOR+ns)) { + throw new RuntimeException("path of "+down.where()+ + " should be "+(v.isRoot()?ns:where+ + JMXNamespaces.NAMESPACE_SEPARATOR+ns)); + } + if (down.up().equals(v)) continue; + throw new RuntimeException("parent of "+down.where()+ + " should be "+where); + } + final NamespaceConfig[] children; + final NamespaceConfig cfg; + if (v.isRoot()) { + children=namespaces; + cfg = null; + } else { + cfg = inputMap.get(where); + children = cfg==null?null:cfg.children; + } + compare(v.list(),children,true); + if (!v.isRoot()) { + if (where.endsWith(ClientContext.NAMESPACE)) { + System.out.println(where+": skipping queryNames analysis"); + continue; + } + //System.out.println(where+": cfg is: "+cfg); + compare(where,v.getMBeanServerConnection(). + queryNames(null, null),cfg.wombats,true); + } + } + + exportAndWaitIfNeeded(server); + } finally { + closeAll(cslist); + } + } + + public static interface JMXNamespaceCreatorMBean { + public ObjectInstance createLocalNamespace(String namespace) + throws JMException ; + public void removeLocalNamespace(String namespace) + throws JMException; + } + + public static class JMXNamespaceCreator + implements MBeanRegistration, + JMXNamespaceCreatorMBean { + + private volatile MBeanServer mbeanServer; + + public ObjectInstance createLocalNamespace(String namespace) + throws JMException { + return mbeanServer.registerMBean( + new JMXNamespace(MBeanServerFactory.newMBeanServer()), + JMXNamespaces.getNamespaceObjectName(namespace)); + } + + public void removeLocalNamespace(String namespace) + throws JMException { + mbeanServer.unregisterMBean( + JMXNamespaces.getNamespaceObjectName(namespace)); + } + + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + mbeanServer = server; + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + } + + public static void exportAndWaitIfNeeded(MBeanServer server) + throws Exception { + if (System.getProperty("jmx.wait")!=null) { + final int port = getPortFor("rmi"); + LocateRegistry.createRegistry(port); + final JMXServiceURL url = + new JMXServiceURL("rmi",null,port, + "/jndi/rmi://localhost:"+port+"/jmxrmi"); + final JMXConnectorServer cs = + JMXConnectorServerFactory. + newJMXConnectorServer(url, null, server); + cs.start(); + try { + System.out.println("RMI Server waiting at: "+cs.getAddress()); + System.in.read(); + } finally { + cs.stop(); + } + } + } + + public static int getPortFor(String protocol) throws Exception { + final int aport = + Integer.valueOf(System.getProperty("jmx."+protocol+".port","0")); + if (aport > 0) return aport; + final ServerSocket s = new ServerSocket(0); + try { + final int port = s.getLocalPort(); + return port; + } finally { + s.close(); + } + } + + public static void main(String[] args) throws Exception { + doTest(ManagementFactory.getPlatformMBeanServer(),makeConfig("rmi")); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXNamespacesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXNamespacesTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,647 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test JMXNamespacesTest.java + * @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest + * @author Daniel Fuchs + * @run clean JMXNamespacesTest + * @compile -XDignore.symbol.file=true JMXNamespacesTest.java + * @run main JMXNamespacesTest + */ + +import com.sun.jmx.namespace.ObjectNameRouter; +import java.io.Serializable; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; + +/** + * Class JMXNamespacesTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class JMXNamespacesTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespacesTest.class.getName()); + + /** Creates a new instance of JMXNamespacesTest */ + public JMXNamespacesTest() { + } + + public static class CustomObject implements Serializable { + ObjectName toto; + String titi; + CustomObject(String toto, String titi) { + try { + this.toto = new ObjectName(toto); + } catch (MalformedObjectNameException m) { + throw new IllegalArgumentException(m); + } + this.titi = titi; + } + private Object[] data() { + return new Object[] {toto, titi}; + } + @Override + public boolean equals(Object other) { + if (! (other instanceof CustomObject)) return false; + return Arrays.deepEquals(data(),((CustomObject)other).data()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(data()); + } + } + + public static CustomObject obj(String toto, String titi) { + return new CustomObject(toto,titi); + } + + private static String failure; + + public static void testDeepRewrite() throws Exception { + failure = null; + String s1 = "x//y//d:k=v"; + String s2 = "v//w//x//y//d:k=v"; + String p1 = "v//w"; + String p3 = "a//b"; + + System.out.println("inserting "+p1); + final CustomObject foo1 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s1,s1),"",p1); + assertEquals(foo1.toto.toString(),p1+"//"+s1); + assertEquals(foo1.titi,s1); + + System.out.println("removing "+p1); + final CustomObject foo2 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,""); + assertEquals(foo2.toto.toString(),s1); + assertEquals(foo2.titi,s2); + + System.out.println("removing "+p1); + final CustomObject foo3 = + JMXNamespaces.deepReplaceHeadNamespace(obj(p1+"//"+s2,s2),p1,""); + assertEquals(foo3.toto.toString(),s2); + assertEquals(foo3.titi,s2); + + System.out.println("replacing "+p1+" with "+p3); + final CustomObject foo4 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,p3); + assertEquals(foo4.toto.toString(),p3+"//"+s1); + assertEquals(foo4.titi,s2); + + System.out.println("replacing "+p1+" with "+p1); + final CustomObject foo5 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,p1); + assertEquals(foo5.toto.toString(),s2); + assertEquals(foo5.titi,s2); + + System.out.println("removing x//y in "+s2); + try { + final CustomObject foo7 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),"x//y",""); + failed("Remove x//y in "+s2+" should have failed!"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception: "+x); + } + + System.out.println("replacing x//y with "+p3+" in "+s2); + try { + final CustomObject foo7 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),"x//y",p3); + failed("Replace x//y in "+s2+" should have failed!"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception: "+x); + } + + if (failure != null) throw new Exception(failure); + } + + private static String[][] wildcards = { + { "", "*:*" }, + { "//", "//*:*" }, + { "foo", "foo//*:*" }, + { "//foo", "//foo//*:*" }, + { "////foo", "//foo//*:*" }, + { "foo//", "foo//*:*" }, + { "foo////", "foo//*:*" }, + { "//foo//", "//foo//*:*" }, + { "////foo//", "//foo//*:*" }, + { "////foo////", "//foo//*:*" }, + { "foo//bar", "foo//bar//*:*" }, + { "//foo//bar", "//foo//bar//*:*" }, + { "////foo//bar", "//foo//bar//*:*" }, + { "foo//bar//", "foo//bar//*:*" }, + { "foo//bar////", "foo//bar//*:*" }, + { "//foo//bar//", "//foo//bar//*:*" }, + { "////foo//bar//", "//foo//bar//*:*" }, + { "////foo//bar////", "//foo//bar//*:*" }, + { "foo////bar", "foo//bar//*:*" }, + { "//foo////bar", "//foo//bar//*:*" }, + { "////foo////bar", "//foo//bar//*:*" }, + { "foo////bar//", "foo//bar//*:*" }, + { "foo////bar////", "foo//bar//*:*" }, + { "//foo////bar//", "//foo//bar//*:*" }, + { "////foo////bar//", "//foo//bar//*:*" }, + { "////foo////bar////", "//foo//bar//*:*" }, + { "fo/o", "fo/o//*:*" }, + { "//f/oo", "//f/oo//*:*" }, + { "////f/o/o", "//f/o/o//*:*" }, + { "fo/o//", "fo/o//*:*" }, + { "f/oo////", "f/oo//*:*" }, + { "//fo/o//", "//fo/o//*:*" }, + { "////f/oo//", "//f/oo//*:*" }, + { "////f/o/o////", "//f/o/o//*:*" }, + { "foo//b/a/r", "foo//b/a/r//*:*" }, + { "//fo/o//bar", "//fo/o//bar//*:*" }, + { "////foo//b/ar", "//foo//b/ar//*:*" }, + { "foo//ba/r//", "foo//ba/r//*:*" }, + { "f/oo//bar////", "f/oo//bar//*:*" }, + { "//f/o/o//bar//", "//f/o/o//bar//*:*" }, + { "////foo//b/a/r//", "//foo//b/a/r//*:*" }, + { "////f/o/o//b/a/r////", "//f/o/o//b/a/r//*:*" }, + { "foo////ba/r", "foo//ba/r//*:*" }, + { "//foo////b/ar", "//foo//b/ar//*:*" }, + { "////f/oo////bar", "//f/oo//bar//*:*" }, + { "fo/o////bar//", "fo/o//bar//*:*" }, + { "foo////ba/r////", "foo//ba/r//*:*" }, + { "//fo/o////ba/r//", "//fo/o//ba/r//*:*" }, + { "////f/oo////b/ar//", "//f/oo//b/ar//*:*" }, + { "////f/o/o////b/a/r////", "//f/o/o//b/a/r//*:*" }, + }; + private final static String[] badguys = { + null, + "/", "/*:*", + "///", "///*:*" , + "/foo", "/foo//*:*", + "//foo/", "//foo///*:*" , + "/////foo", "///foo//*:*", + "/foo//", "/foo//*:*", + "foo/////", "foo///*:*", + "///foo//", "///foo//*:*", + "////foo///", "//foo///*:*" , + "/////foo/////", "///foo///*:*", + "/foo//bar", "/foo//bar//*:*", + "//foo///bar", "//foo///bar//*:*", + "/////foo////bar/", "///foo//bar///*:*", + "foo///bar//", "foo//bar///*:*", + "foo//bar/////", "foo///bar//*:*", + "///foo//bar//", "//foo///bar//*:*" , + }; + public static void testWildcard() throws Exception { + int i = 0; + for (String[] pair : wildcards) { + i++; + final String msg = "testWildcard[good,"+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg, new ObjectName(pair[1]), + JMXNamespaces.getWildcardFor(pair[0])); + } + i=0; + for (String bad : badguys) { + i++; + try { + JMXNamespaces.getWildcardFor(bad); + failed("testWildcard[bad,"+i+"] "+bad+" incorrectly accepted. " + + "IllegalArgumentException was expected"); + } catch (IllegalArgumentException x) { + // OK + } + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] goodinsert = { + {"","d:k=v","d:k=v"}, + {"","//d:k=v","//d:k=v"}, + {"//","d:k=v","//d:k=v"}, + {"//","//d:k=v","//d:k=v"}, + {"//","a//d:k=v","//a//d:k=v"}, + {"//","//a//d:k=v","//a//d:k=v"}, + {"//","////a////d:k=v","//a//d:k=v"}, + {"//b","////a////d:k=v","//b//a//d:k=v"}, + {"b","////a////d:k=v","b//a//d:k=v"}, + {"b","d:k=v","b//d:k=v"}, + {"b//","d:k=v","b//d:k=v"}, + {"//b//","d:k=v","//b//d:k=v"}, + {"//b","////a////d:k=v","//b//a//d:k=v"}, + {"b//c","////a////d:k=v","b//c//a//d:k=v"}, + {"b//c","d:k=v","b//c//d:k=v"}, + {"b//c//","d:k=v","b//c//d:k=v"}, + {"//b//c//","d:k=v","//b//c//d:k=v"}, + {"","/d:k=v","/d:k=v"}, + {"","///d:k=v","///d:k=v"}, + {"//","/d:k=v","///d:k=v"}, + {"//","///d:k=v","///d:k=v"}, + {"//","a///d:k=v","//a///d:k=v"}, + {"//","//a///d:k=v","//a///d:k=v"}, + {"//","////a////d/:k=v","//a//d/:k=v"}, + {"//b","////a/////d:k=v","//b//a///d:k=v"}, + {"b","////a////d/:k=v","b//a//d/:k=v"}, + {"b","/d:k=v","b///d:k=v"}, + {"b//","/d:k=v","b///d:k=v"}, + {"//b//","/d:k=v","//b///d:k=v"}, + {"//b","////a/////d:k=v","//b//a///d:k=v"}, + {"b//c","////a/////d:k=v","b//c//a///d:k=v"}, + {"b//c","/d:k=v","b//c///d:k=v"}, + {"b//c//","/d:k=v","b//c///d:k=v"}, + {"//b//c//","d/:k=v","//b//c//d/:k=v"}, + }; + + private static String[][] badinsert = { + {"/","d:k=v"}, + {"/","//d:k=v"}, + {"///","d:k=v"}, + {"///","//d:k=v"}, + {"///","/a//d:k=v"}, + {"///","///a//d:k=v"}, + {"///","/////a////d:k=v"}, + {"//b","/////a////d:k=v"}, + {"b/","////a////d:k=v"}, + {"b/","d:k=v"}, + {"b///","d:k=v"}, + {"//b///","d:k=v"}, + {"//b/","////a////d:k=v"}, + {"b///c","////a////d:k=v"}, + {"b//c/","d:k=v"}, + {"b///c//","d:k=v"}, + {"//b///c//","d:k=v"}, + + }; + + public static void testInsertPath() throws Exception { + int i = 0; + for (String[] pair : goodinsert) { + i++; + final String msg = "testInsertPath[good,"+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg,new ObjectName(pair[2]), + JMXNamespaces.insertPath(pair[0], + new ObjectName(pair[1]))); + } + i=0; + for (String[] bad : badinsert) { + i++; + try { + JMXNamespaces.insertPath(bad[0], + new ObjectName(bad[1])); + failed("testInsertPath[bad,"+i+"] "+ + Arrays.asList(bad)+" incorrectly accepted. " + + "IllegalArgumentException was expected"); + } catch (IllegalArgumentException x) { + // OK + } + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] testpath = { + {"/a/a/:k=v",""}, + {"/:k=v",""}, + {"bli:k=v",""}, + {"///a/a/:k=v",""}, + {"///:k=v",""}, + {"//bli:k=v",""}, + {"/////a/a/:k=v",""}, + {"/////:k=v",""}, + {"////bli:k=v",""}, + {"y///a/a/:k=v","y"}, + {"y///:k=v","y"}, + {"y//bli:k=v","y"}, + {"y/////a/a/:k=v","y"}, + {"y/////:k=v","y"}, + {"y////bli:k=v","y"}, + {"//y///a/a/:k=v","y"}, + {"//y///:k=v","y"}, + {"//y//bli:k=v","y"}, + {"//y/////a/a/:k=v","y"}, + {"//y/////:k=v","y"}, + {"//y////bli:k=v","y"}, + {"////y///a/a/:k=v","y"}, + {"////y///:k=v","y"}, + {"////y//bli:k=v","y"}, + {"////y/////a/a/:k=v","y"}, + {"////y/////:k=v","y"}, + {"////y////bli:k=v","y"}, + + {"z//y///a/a/:k=v","z//y"}, + {"z//y///:k=v","z//y"}, + {"z//y//bli:k=v","z//y"}, + {"z//y/////a/a/:k=v","z//y"}, + {"z//y/////:k=v","z//y"}, + {"z//y////bli:k=v","z//y"}, + {"//z//y///a/a/:k=v","z//y"}, + {"//z//y///:k=v","z//y"}, + {"//z//y//bli:k=v","z//y"}, + {"//z//y/////a/a/:k=v","z//y"}, + {"//z//y/////:k=v","z//y"}, + {"//z//y////bli:k=v","z//y"}, + {"z////y///a/a/:k=v","z//y"}, + {"z////y///:k=v","z//y"}, + {"z////y//bli:k=v","z//y"}, + {"z////y/////a/a/:k=v","z//y"}, + {"z////y/////:k=v","z//y"}, + {"z////y////bli:k=v","z//y"}, + {"//z////y///a/a/:k=v","z//y"}, + {"//z////y///:k=v","z//y"}, + {"//z////y//bli:k=v","z//y"}, + {"//z////y/////a/a/:k=v","z//y"}, + {"//z////y/////:k=v","z//y"}, + {"//z////y////bli:k=v","z//y"}, + {"////z////y///a/a/:k=v","z//y"}, + {"////z////y///:k=v","z//y"}, + {"////z////y//bli:k=v","z//y"}, + {"////z////y/////a/a/:k=v","z//y"}, + {"////z////y/////:k=v","z//y"}, + {"////z////y////bli:k=v","z//y"}, + + }; + + public static void testGetNormalizedPath() throws Exception { + int i = 0; + for (String[] pair : testpath) { + i++; + final String msg = "testGetNormalizedPath["+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + JMXNamespaces.getContainingNamespace(new ObjectName(pair[0]))); + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] testdomain = { + {"/a/a/","/a/a/"}, + {"/","/"}, + {"bli","bli"}, + {"///a/a/","///a/a/"}, + {"///","///"}, + {"//bli","//bli"}, + {"/////a/a/","///a/a/"}, + {"/////","///"}, + {"////bli","//bli"}, + {"y///a/a/","y///a/a/"}, + {"y///","y///"}, + {"y//bli","y//bli"}, + {"y/////a/a/","y///a/a/"}, + {"y/////","y///"}, + {"y////bli","y//bli"}, + {"//y///a/a/","//y///a/a/"}, + {"//y///","//y///"}, + {"//y//bli","//y//bli"}, + {"//y/////a/a/","//y///a/a/"}, + {"//y/////","//y///"}, + {"//y////bli","//y//bli"}, + {"////y///a/a/","//y///a/a/"}, + {"////y///","//y///"}, + {"////y//bli","//y//bli"}, + {"////y/////a/a/","//y///a/a/"}, + {"////y/////","//y///"}, + {"////y////bli","//y//bli"}, + + {"z//y///a/a/","z//y///a/a/"}, + {"z//y///","z//y///"}, + {"z//y//bli","z//y//bli"}, + {"z//y/////a/a/","z//y///a/a/"}, + {"z//y/////","z//y///"}, + {"z//y////bli","z//y//bli"}, + {"//z//y///a/a/","//z//y///a/a/"}, + {"//z//y///","//z//y///"}, + {"//z//y//bli","//z//y//bli"}, + {"//z//y/////a/a/","//z//y///a/a/"}, + {"//z//y/////","//z//y///"}, + {"//z//y////bli","//z//y//bli"}, + {"z////y///a/a/","z//y///a/a/"}, + {"z////y///","z//y///"}, + {"z////y//bli","z//y//bli"}, + {"z////y/////a/a/","z//y///a/a/"}, + {"z////y/////","z//y///"}, + {"z////y////bli","z//y//bli"}, + {"//z////y///a/a/","//z//y///a/a/"}, + {"//z////y///","//z//y///"}, + {"//z////y//bli","//z//y//bli"}, + {"//z////y/////a/a/","//z//y///a/a/"}, + {"//z////y/////","//z//y///"}, + {"//z////y////bli","//z//y//bli"}, + {"////z////y///a/a/","//z//y///a/a/"}, + {"////z////y///","//z//y///"}, + {"////z////y//bli","//z//y//bli"}, + {"////z////y/////a/a/","//z//y///a/a/"}, + {"////z////y/////","//z//y///"}, + {"////z////y////bli","//z//y//bli"}, + + {"bli//","bli//"}, + {"//bli//","//bli//"}, + {"////bli//","//bli//"}, + {"y////","y//"}, + {"y//bli//","y//bli//"}, + {"y////","y//"}, + {"y////bli//","y//bli//"}, + {"//y////","//y//"}, + {"//y//bli//","//y//bli//"}, + {"//y//////","//y//"}, + {"//y////bli//","//y//bli//"}, + {"////y////","//y//"}, + {"////y//bli////","//y//bli//"}, + {"////y//////","//y//"}, + {"////y////bli////","//y//bli//"}, + {"z//y////","z//y//"}, + {"z//y//bli//","z//y//bli//"}, + {"z//y//////","z//y//"}, + {"z//y////bli//","z//y//bli//"}, + {"//z//y////","//z//y//"}, + {"//z//y//bli//","//z//y//bli//"}, + {"//z//y//////","//z//y//"}, + {"//z//y////bli//","//z//y//bli//"}, + {"z////y////","z//y//"}, + {"z////y//bli//","z//y//bli//"}, + {"z////y//////","z//y//"}, + {"z////y////bli//","z//y//bli//"}, + {"//z////y////","//z//y//"}, + {"//z////y//bli//","//z//y//bli//"}, + {"//z////y//////","//z//y//"}, + {"//z////y////bli//","//z//y//bli//"}, + {"////z////y////","//z//y//"}, + {"////z////y//bli//","//z//y//bli//"}, + {"////z////y//////","//z//y//"}, + {"////z////y////bli//","//z//y//bli//"}, + + }; + private static String[][] testnolead = { + {"/a/a/","/a/a/"}, + {"/","/"}, + {"bli","bli"}, + {"///a/a/","/a/a/"}, + {"///","/"}, + {"//bli","bli"}, + {"/////a/a/","/a/a/"}, + {"/////","/"}, + {"////bli","bli"}, + {"y///a/a/","y///a/a/"}, + {"y///","y///"}, + {"y//bli","y//bli"}, + {"y/////a/a/","y///a/a/"}, + {"y/////","y///"}, + {"y////bli","y//bli"}, + {"//y///a/a/","y///a/a/"}, + {"//y///","y///"}, + {"//y//bli","y//bli"}, + {"//y/////a/a/","y///a/a/"}, + {"//y/////","y///"}, + {"//y////bli","y//bli"}, + {"////y///a/a/","y///a/a/"}, + {"////y///","y///"}, + {"////y//bli","y//bli"}, + {"////y/////a/a/","y///a/a/"}, + {"////y/////","y///"}, + {"////y////bli","y//bli"}, + + {"z//y///a/a/","z//y///a/a/"}, + {"z//y///","z//y///"}, + {"z//y//bli","z//y//bli"}, + {"z//y/////a/a/","z//y///a/a/"}, + {"z//y/////","z//y///"}, + {"z//y////bli","z//y//bli"}, + {"//z//y///a/a/","z//y///a/a/"}, + {"//z//y///","z//y///"}, + {"//z//y//bli","z//y//bli"}, + {"//z//y/////a/a/","z//y///a/a/"}, + {"//z//y/////","z//y///"}, + {"//z//y////bli","z//y//bli"}, + {"z////y///a/a/","z//y///a/a/"}, + {"z////y///","z//y///"}, + {"z////y//bli","z//y//bli"}, + {"z////y/////a/a/","z//y///a/a/"}, + {"z////y/////","z//y///"}, + {"z////y////bli","z//y//bli"}, + {"//z////y///a/a/","z//y///a/a/"}, + {"//z////y///","z//y///"}, + {"//z////y//bli","z//y//bli"}, + {"//z////y/////a/a/","z//y///a/a/"}, + {"//z////y/////","z//y///"}, + {"//z////y////bli","z//y//bli"}, + {"////z////y///a/a/","z//y///a/a/"}, + {"////z////y///","z//y///"}, + {"////z////y//bli","z//y//bli"}, + {"////z////y/////a/a/","z//y///a/a/"}, + {"////z////y/////","z//y///"}, + {"////z////y////bli","z//y//bli"}, + + {"bli//","bli//"}, + {"//bli//","bli//"}, + {"////bli//","bli//"}, + {"y////","y//"}, + {"y//bli//","y//bli//"}, + {"y////","y//"}, + {"y////bli//","y//bli//"}, + {"//y////","y//"}, + {"//y//bli//","y//bli//"}, + {"//y//////","y//"}, + {"//y////bli//","y//bli//"}, + {"////y////","y//"}, + {"////y//bli////","y//bli//"}, + {"////y//////","y//"}, + {"////y////bli////","y//bli//"}, + {"z//y////","z//y//"}, + {"z//y//bli//","z//y//bli//"}, + {"z//y//////","z//y//"}, + {"z//y////bli//","z//y//bli//"}, + {"//z//y////","z//y//"}, + {"//z//y//bli//","z//y//bli//"}, + {"//z//y//////","z//y//"}, + {"//z//y////bli//","z//y//bli//"}, + {"z////y////","z//y//"}, + {"z////y//bli//","z//y//bli//"}, + {"z////y//////","z//y//"}, + {"z////y////bli//","z//y//bli//"}, + {"//z////y////","z//y//"}, + {"//z////y//bli//","z//y//bli//"}, + {"//z////y//////","z//y//"}, + {"//z////y////bli//","z//y//bli//"}, + {"////z////y////","z//y//"}, + {"////z////y//bli//","z//y//bli//"}, + {"////z////y//////","z//y//"}, + {"////z////y////bli//","z//y//bli//"}, + + }; + + public static void testNormalizeDomain() throws Exception { + int i = 0; + for (String[] pair : testdomain) { + i++; + final String msg = "testNormalizeDomain["+i+", false] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + ObjectNameRouter.normalizeDomain(pair[0],false)); + } + if (failure != null) throw new Exception(failure); + i = 0; + for (String[] pair : testnolead) { + i++; + final String msg = "testNormalizeDomain["+i+", true] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + ObjectNameRouter.normalizeDomain(pair[0],true)); + } + if (failure != null) throw new Exception(failure); + } + + public static void main(String[] args) throws Exception { + testDeepRewrite(); + testNormalizeDomain(); + testInsertPath(); + testWildcard(); + testGetNormalizedPath(); + } + + private static void assertEquals(Object x, Object y) { + assertEquals("",x,y); + } + + private static void assertEquals(String msg, Object x, Object y) { + if (msg == null) msg=""; + if (!equal(x, y)) + failed(msg+"expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXRemoteNamespaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXRemoteNamespaceTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,189 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test JMXRemoteNamespaceTest.java + * @summary Basic tests on a JMXRemoteNamespace. + * @author Daniel Fuchs + * @run clean JMXRemoteNamespaceTest Wombat WombatMBean + * @run build JMXRemoteNamespaceTest Wombat WombatMBean + * @run main JMXRemoteNamespaceTest + */ + +import javax.management.JMX; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationListener; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.io.IOException; +import javax.management.AttributeChangeNotification; + +/** + * Test simple creation/registration of namespace. + * + */ +public class JMXRemoteNamespaceTest { + + static class MyConnect implements NotificationListener { + private final JMXRemoteNamespace my; + private final List list; + private volatile int connectCount=0; + private int closeCount=0; + private final ObjectName myname; + public MyConnect(JMXRemoteNamespace my, ObjectName myname) { + this.my=my; + this.myname = myname; + list = Collections.synchronizedList(new ArrayList()); + my.addNotificationListener(this, null, null); + } + + public synchronized void connect() throws IOException { + my.connect(); + if (!my.isConnected()) + throw new IOException(myname+" should be connected"); + connectCount++; + } + + public void close() throws IOException { + my.close(); + if (my.isConnected()) + throw new IOException(myname+" shouldn't be connected"); + closeCount++; + } + + public synchronized int getConnectCount() { + return connectCount; + } + public synchronized int getClosedCount() { + return closeCount; + } + + public synchronized void handleNotification(Notification notification, + Object handback) { + list.add(notification); + } + + public synchronized void checkNotifs(int externalConnect, + int externalClosed) throws Exception { + System.err.println("Connected: "+connectCount+" time"+ + ((connectCount>1)?"s":"")); + System.err.println("Closed: "+closeCount+" time"+ + ((closeCount>1)?"s":"")); + System.err.println("Received:"); + int cl=0; + int co=0; + for (Notification n : list) { + System.err.println("\t"+n); + if (!(n instanceof AttributeChangeNotification)) + throw new Exception("Unexpected notif: "+n.getClass()); + final AttributeChangeNotification acn = + (AttributeChangeNotification)n; + if (((Boolean)acn.getNewValue()).booleanValue()) + co++; + else cl++; + if ((((Boolean)acn.getNewValue()).booleanValue()) + == (((Boolean)acn.getOldValue()).booleanValue())) { + throw new Exception("Bad values: old=new"); + } + } + if (! (list.size()==(closeCount+connectCount+ + externalClosed+externalConnect))) { + throw new Exception("Bad notif count - got "+list.size()); + } + if (cl!=(closeCount+externalClosed)) { + throw new Exception("Bad count of close notif: expected " + +(closeCount+externalClosed)+", got"+cl); + } + if (co!=(connectCount+externalConnect)) { + throw new Exception("Bad count of connect notif: expected " + +(connectCount+externalConnect)+", got"+co); + } + } + } + + public static void testConnectClose() throws Exception { + final MBeanServer myServer = MBeanServerFactory.newMBeanServer(); + final JMXConnectorServer myRMI = + JMXConnectorServerFactory.newJMXConnectorServer( + new JMXServiceURL("rmi",null,0), null, myServer); + myRMI.start(); + try { + final JMXRemoteNamespace my = + JMXRemoteNamespace.newJMXRemoteNamespace( + myRMI.getAddress(),null); + final MBeanServer s = MBeanServerFactory.newMBeanServer(); + final ObjectName myname = JMXNamespaces.getNamespaceObjectName("my"); + final ObjectName wname = ObjectName.getInstance("backyard:type=Wombat"); + myServer.registerMBean(new Wombat(),wname); + final MyConnect myc = new MyConnect(my,myname); + myc.connect(); + myc.close(); + myc.connect(); + s.registerMBean(my,myname); + myc.close(); + myc.connect(); + if (!s.queryNames(new ObjectName("my//b*:*"),null).contains( + JMXNamespaces.insertPath("my", wname))) { + throw new RuntimeException("1: Wombat not found: "+wname); + } + myc.close(); + myc.connect(); + final MBeanServer cd = JMXNamespaces.narrowToNamespace(s, "my"); + if (!cd.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("2: Wombat not found: "+wname); + } + myc.close(); + myc.connect(); + System.out.println("Found a Wombat in my backyard."); + + final String deepThoughts = "I want to leave this backyard!"; + final WombatMBean w = JMX.newMBeanProxy(cd, wname, WombatMBean.class); + w.setCaption(deepThoughts); + if (!deepThoughts.equals(w.getCaption())) + throw new RuntimeException("4: Wombat is not thinking right: "+ + w.getCaption()); + s.unregisterMBean(myname); + if (my.isConnected()) + throw new Exception(myname+" shouldn't be connected"); + myc.connect(); + myc.close(); + myc.checkNotifs(0,1); + } finally { + myRMI.stop(); + } + + } + + public static void main(String... args) throws Exception { + testConnectClose(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,222 @@ +/* + * 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. + */ + + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServerConnection; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.event.EventClient; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXServiceURL; + +// These options originally in the draft of javax/management/namespaces +// but we decided to retire them - since they could be implemented +// by subclasses. The JMXRemoteTargetNamespace is such a subclass. +// +public class JMXRemoteTargetNamespace extends JMXRemoteNamespace { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXRemoteTargetNamespace.class.getName()); + public static final String CREATE_EVENT_CLIENT = + "jmx.test.create.event.client"; + + private final String sourceNamespace; + private final boolean createEventClient; + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap) { + this(sourceURL,optionsMap,null); + } + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap, String sourceNamespace) { + this(sourceURL,optionsMap,sourceNamespace,false); + } + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap, String sourceNamespace, + boolean createEventClient) { + super(sourceURL,optionsMap); + this.sourceNamespace = sourceNamespace; + this.createEventClient = createEventClient(optionsMap); + } + + private boolean createEventClient(Map options) { + if (options == null) return false; + final Object createValue = options.get(CREATE_EVENT_CLIENT); + if (createValue == null) return false; + if (createValue instanceof Boolean) + return ((Boolean)createValue).booleanValue(); + if (createValue instanceof String) + return Boolean.valueOf((String)createValue); + throw new IllegalArgumentException("Bad type for value of property " + + CREATE_EVENT_CLIENT+": "+createValue.getClass().getName()); + } + + @Override + protected JMXConnector newJMXConnector(JMXServiceURL url, + Map env) throws IOException { + JMXConnector sup = super.newJMXConnector(url, env); + if (sourceNamespace == null || "".equals(sourceNamespace)) + return sup; + if (createEventClient) + sup = EventClient.withEventClient(sup); + return JMXNamespaces.narrowToNamespace(sup, sourceNamespace); + } + + + /** + * Creates a target name space to mirror a remote source name space in + * the target server. + * @param targetServer A connection to the target MBean server in which + * the new name space should be created. + * @param targetPath the name space to create in the target server. Note + * that if the target name space is a path - that is if + * {@code targetPath} contains '//', then the parent name space + * must be pre-existing in the target server. Attempting to create + * {code targetPath="a//b//c"} in {@code targetServer} + * will fail if name space {@code "a//b"} doesn't already exists + * in {@code targetServer}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the + * {@link JMXRemoteNamespaceMBean} which handles the + * new name space. + * + **/ + public static ObjectInstance createNamespace( + MBeanServerConnection targetServer, + String targetPath, + JMXServiceURL sourceURL, + Map options) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + final ObjectName name = + JMXNamespaces.getNamespaceObjectName(targetPath); + return createInstance(targetServer, name, sourceURL, options, null); + } + + /** + * Creates a target name space to mirror a remote source name space in + * the target server. + * @param targetServer A connection to the target MBean server in which + * the new name space should be created. + * @param targetPath the name space to create in the target server. Note + * that if the target name space is a path - that is if + * {@code targetPath} contains '//', then the parent name space + * must be pre-existing in the target server. Attempting to create + * {code targetPath="a//b//c"} in {@code targetServer} + * will fail if name space {@code "a//b"} doesn't already exists + * in {@code targetServer}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param sourcePath the source namespace path insode the source server. + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the + * {@link JMXRemoteNamespaceMBean} which handles the + * new name space. + * + **/ + public static ObjectInstance createNamespace( + MBeanServerConnection targetServer, + String targetPath, + JMXServiceURL sourceURL, + Map options, + String sourcePath) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + final ObjectName name = + JMXNamespaces.getNamespaceObjectName(targetPath); + return createInstance(targetServer, name, sourceURL, options, sourcePath); + } + + /** + * Creates and registers a {@link JMXRemoteNamespaceMBean} in a target + * server, to mirror a remote source name space. + * + * @param server A connection to the target MBean server in which + * the new name space should be created. + * @param handlerName the name of the JMXRemoteNamespace to create. + * This must be a compliant name space handler name as returned + * by {@link + * JMXNamespaces#getNamespaceObjectName JMXNamespaces.getNamespaceObjectName}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param sourcePath the path inside the source server + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the new + * {@link JMXRemoteNamespaceMBean} created. + * @see #createNamespace createNamespace + */ + static ObjectInstance createInstance(MBeanServerConnection server, + ObjectName handlerName, + JMXServiceURL sourceURL, Map options, + String sourcePath) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + try { + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + String.class.getName() + }; + final Object[] params = { + sourceURL,options,sourcePath + }; + final ObjectInstance instance = + server.createMBean(JMXRemoteTargetNamespace.class.getName(), + handlerName,params,signature); + return instance; + } catch (NotCompliantMBeanException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } catch (ReflectionException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/LazyDomainTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/LazyDomainTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,789 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test LazyDomainTest.java + * @summary Basic test for Lazy Domains. + * @author Daniel Fuchs + * @run clean LazyDomainTest Wombat WombatMBean + * @run build LazyDomainTest Wombat WombatMBean + * @run main LazyDomainTest + */ + + +import java.lang.management.ClassLoadingMXBean; +import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.Set; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.remote.MBeanServerForwarder; + +/** + * Test simple creation/registration of namespace. + * + */ +public class LazyDomainTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static interface MBeanServerLoader { + public MBeanServer loadMBeanServer(); + } + + + public static class MBeanServerProxy implements InvocationHandler { + + private final static Map localMap; + static { + localMap = new HashMap(); + for (Method m : MBeanServerForwarder.class.getDeclaredMethods()) { + try { + final Method loc = MBeanServerProxy.class. + getMethod(m.getName(), m.getParameterTypes()); + localMap.put(m, loc); + } catch (Exception x) { + // not defined... + } + } + try { + localMap.put(MBeanServer.class. + getMethod("getMBeanCount", (Class[]) null), + MBeanServerProxy.class. + getMethod("getMBeanCount", (Class[]) null)); + } catch (NoSuchMethodException x) { + // OK. + } + } + + private final MBeanServerLoader loader; + private MBeanServer server; + private final Set domains; + + public MBeanServerProxy(MBeanServerLoader loader) { + if (loader == null) + throw new IllegalArgumentException("null loader"); + this.loader = loader; + this.server = null; + domains = new HashSet(); + } + + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + if (method.getDeclaringClass().equals(Object.class)) { + return invokeMethod(this,method,args); + } + final Method local = localMap.get(method); + if (local != null) { + return invokeMethod(this,local,args); + } + if (method.getDeclaringClass().equals(MBeanServer.class)) { + return invokeMethod(getMBeanServer(),method,args); + } + throw new NoSuchMethodException(method.getName()); + } + + private Object invokeMethod(Object on, Method method, Object[] args) + throws Throwable { + try { + return method.invoke(on, args); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + public synchronized MBeanServer getMBeanServer() { + if (server == null) setMBeanServer(loader.loadMBeanServer()); + return server; + } + + public synchronized void setMBeanServer(MBeanServer mbs) { + this.server = mbs; + if (mbs != null) { + for (LazyDomain dom : domains) dom.loaded(); + domains.clear(); + } + } + + public synchronized boolean isLoaded() { + return server != null; + } + + public synchronized void add(LazyDomain dom) { + if (isLoaded()) dom.loaded(); + else domains.add(dom); + } + + public synchronized boolean remove(LazyDomain dom) { + return domains.remove(dom); + } + + public Integer getMBeanCount() { + if (isLoaded()) return server.getMBeanCount(); + else return Integer.valueOf(0); + } + } + + public static class LazyDomain extends JMXDomain { + public static MBeanServer makeProxyFor(MBeanServerProxy proxy) { + return (MBeanServer) + Proxy.newProxyInstance(LazyDomain.class.getClassLoader(), + new Class[] {MBeanServer.class, MBeanServerForwarder.class}, + proxy); + } + + private final MBeanServerProxy proxy; + private volatile NotificationListener listener; + private volatile NotificationFilter filter; + + public LazyDomain(MBeanServerProxy proxy) { + super(makeProxyFor(proxy)); + this.proxy = proxy; + } + + @Override + public Integer getMBeanCount() { + if (proxy.isLoaded()) + return super.getMBeanCount(); + return 0; + } + + + @Override + public synchronized void addMBeanServerNotificationListener( + NotificationListener listener, + NotificationFilter filter) { + if (proxy.isLoaded()) { + super.addMBeanServerNotificationListener(listener, filter); + } else { + this.listener = listener; + this.filter = filter; + proxy.add(this); + } + } + + @Override + public synchronized void removeMBeanServerNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + if (this.listener != listener) + throw new ListenerNotFoundException(); + this.listener = null; + this.filter = null; + if (proxy.isLoaded()) + super.removeMBeanServerNotificationListener(listener); + proxy.remove(this); + } + + public synchronized void loaded() { + if (listener != null) + addMBeanServerNotificationListener(listener, filter); + } + + } + + /** + * This is a use case for e.g GlassFish: the LazyStarterDomain MBean + * is a place holder that will unregister itself and autoload a set + * of MBeans in place of its own domain when that domain is + * accessed. + * This is an abstract class, where the only abstract method + * is loadMBeans(MBeanServer). + * Subclasses should implement that method to register whatever MBeans + * in the domain previously held by that LazyStarterDomain object. + * In other words: the LazyStarterDomain MBean is 'replaced' by the + * MBeans loaded by loadMBeans(); + */ + public static abstract class LazyStarterDomain extends LazyDomain { + + /** + * This is a loader that will unregister the JMXDomain that + * created it, and register a bunch of MBeans in its place + * by calling LazyStarterDomain.loadMBeans + * + * That one gave me "la migraine". + */ + private static class HalfGrainLoader implements MBeanServerLoader { + private volatile LazyStarterDomain domain; + public MBeanServer loadMBeanServer() { + if (domain == null) + throw new IllegalStateException( + "JMXDomain MBean not registered!"); + final MBeanServer server = domain.getMBeanServer(); + final ObjectName domainName = domain.getObjectName(); + try { + server.unregisterMBean(domainName); + } catch (Exception x) { + throw new IllegalStateException("Can't unregister " + + "JMXDomain: "+x,x); + } + domain.loadMBeans(server,domainName.getDomain()); + return server; + } + public void setDomain(LazyStarterDomain domain) { + this.domain = domain; + } + } + + /** + * This is an MBeanServerProxy which create a loader for the + * LazyStarterDomain MBean. + */ + private static class DomainStarter extends MBeanServerProxy { + + public DomainStarter() { + this(new HalfGrainLoader()); + } + + private final HalfGrainLoader loader; + private DomainStarter(HalfGrainLoader loader) { + super(loader); + this.loader = loader; + } + + public void setDomain(LazyStarterDomain domain) { + loader.setDomain(domain); + } + } + + /** + * A new LazyStarterDomain. When the domain monitored by this + * MBean is accessed, this MBean will unregister itself and call + * the abstract loadMBeans(MBeanServer) method. + * Subclasses need only to implement loadMBeans(). + */ + public LazyStarterDomain() { + this(new DomainStarter()); + } + + private LazyStarterDomain(DomainStarter starter) { + super(starter); + starter.setDomain(this); + } + + // Contrarily to its LazyDomain superclass, this LazyDomain + // doesn't wrapp another MBeanServer: it simply registers a bunch + // of MBeans in its own MBeanServer. + // Thus, there's no notifications to forward. + // + @Override + public void addMBeanServerNotificationListener( + NotificationListener listener, NotificationFilter filter) { + // nothing to do. + } + + // Contrarily to its LazyDomain superclass, this LazyDomain + // doesn't wrapp another MBeanServer: it simply registers a bunch + // of MBeans in its own MBeanServer. + // Thus, there's no notifications to forward. + // + @Override + public void removeMBeanServerNotificationListener( + NotificationListener listener) throws ListenerNotFoundException { + // nothing to do + } + + // If this domain is registered, it contains no MBean. + // If it is not registered, then it no longer contain any MBean. + // The MBeanCount is thus always 0. + @Override + public Integer getMBeanCount() { + return 0; + } + + /** + * Called when the domain is first accessed. + * {@code server} is the server in which this MBean was registered. + * A subclass must override this method in order to register + * the MBeans that should be contained in domain. + * + * @param server the server in which to load the MBeans. + * @param domain the domain in which the MBeans should be registered. + */ + protected abstract void loadMBeans(MBeanServer server, String domain); + + + } + + private static MBeanServerNotification pop( + BlockingQueue queue, + String type, + ObjectName mbean, + String test) + throws InterruptedException { + final Notification n = queue.poll(1, TimeUnit.SECONDS); + if (!(n instanceof MBeanServerNotification)) + fail(test+"expected MBeanServerNotification, got "+n); + final MBeanServerNotification msn = (MBeanServerNotification)n; + if (!type.equals(msn.getType())) + fail(test+"expected "+type+", got "+msn.getType()); + if (!mbean.apply(msn.getMBeanName())) + fail(test+"expected "+mbean+", got "+msn.getMBeanName()); + System.out.println(test+" got: "+msn); + return msn; + } + private static MBeanServerNotification popADD( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION, + mbean, test); + } + + private static MBeanServerNotification popREM( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + mbean, test); + } + + + private static void fail(String msg) { + raise(new RuntimeException(msg)); + } + + private static void fail(String msg, Throwable cause) { + raise(new RuntimeException(msg,cause)); + } + + private static void raise(RuntimeException x) { + lastException = x; + exceptionCount++; + throw x; + } + + private static volatile Exception lastException = null; + private static volatile int exceptionCount = 0; + + // ZZZ need to add a test case with several LazyDomains, and + // need to test that nothing is loaded until the lazy domains + // are accessed... + // + + private static void registerWombats(MBeanServer server, String domain, + int count) { + try { + for (int i=0;i queue = + new ArrayBlockingQueue(100); + + // A listener that puts notifs in the queue. + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification, 5, TimeUnit.SECONDS)) { + throw new RuntimeException("timeout exceeded"); + } + } catch (Exception x) { + fail(test + "failed to handle notif", x); + } + } + }; + + // Create a LazyDomain for each of the platform domain. + // All platform domain share the same MBeanServer proxy, which means + // that loading one domain will also load all the others. + // + Map domainsMap = new HashMap(); + for (String dom : platformDomains) { + domainsMap.put(dom, new LazyDomain(platform)); + } + domainsMap.put("custom.awomb", new LazyDomain(customa)); + domainsMap.put("custom.bwomb", new LazyDomain(customb)); + + for (Map.Entry e : domainsMap.entrySet()) { + server.registerMBean(e.getValue(), + JMXDomain.getDomainObjectName(e.getKey())); + } + + // check that lazy MBeans are not there... + checkSize(test,server,domainsMap.size()+1); + + System.out.println(test+" registering listener with delegate."); + server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + // check that lazy MBeans are not there... + checkSize(test,server,domainsMap.size()+1); + + // force loading of custom.awomb. + final ObjectName awombat = new ObjectName( + "custom.awomb:type=Wombat,name=wombat#"+customCount/2); + if (!server.isRegistered(awombat)) + fail(test+"Expected "+awombat+" to be reggistered!"); + + final int oldCount = domainsMap.size()+1+customCount; + checkSize(test,server,oldCount); + + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + + System.out.println(test+"creating a proxy for ClassLoadingMXBean."); + final ClassLoadingMXBean cl = + JMX.newMXBeanProxy(server, + new ObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME), + ClassLoadingMXBean.class); + + checkSize(test,server,oldCount); + + System.out.println(test+"Loaded classes: "+cl.getLoadedClassCount()); + + final int newCount = server.getMBeanCount(); + if (newCount < oldCount+6) + fail(test+"Expected at least "+(oldCount+6)+ + " MBeans. Found "+newCount); + + final ObjectName jwombat = new ObjectName("java.lang:type=Wombat"); + server.createMBean("Wombat", jwombat); + System.out.println(test+"Created "+jwombat); + checkSize(test,server,newCount+1); + + popADD(queue, jwombat, test); + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + + int platcount = 0; + for (String dom : platformDomains) { + final Set found = + server.queryNames(new ObjectName(dom+":*"),null); + final int jcount = found.size(); + System.out.println(test+"Found "+jcount+" MBeans in "+dom+ + ": "+found); + checkSize(test,server,newCount+1); + platcount += (jcount-1); + } + checkSize(test,server,oldCount+platcount); + + final ObjectName owombat = new ObjectName("custom:type=Wombat"); + server.createMBean("Wombat", owombat); + System.out.println(test+"Created "+owombat); + checkSize(test,server,newCount+2); + popADD(queue, owombat, test); + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + final Set jwombatView = (Set) + server.invoke(jwombat, "listMatching", new Object[] {null}, + new String[] {ObjectName.class.getName()}); + System.out.println(test+jwombat+" sees: "+jwombatView); + checkSize(test, server, newCount+2); + if (jwombatView.size() != (platcount+1)) + fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" + + " have seen "+(platcount+1)); + + final Set platformMBeans = + ManagementFactory.getPlatformMBeanServer(). + queryNames(null, null); + if (!platformMBeans.equals(jwombatView)) + fail(test+jwombat+" should have seen "+platformMBeans); + + // check that awombat triggers loading of bwombats + final Set awombatView = (Set) + server.invoke(awombat, "listMatching", new Object[] {null}, + new String[] {ObjectName.class.getName()}); + System.out.println(test+awombat+" sees: "+awombatView); + final int totalCount = newCount+2+customCount; + checkSize(test, server, totalCount); + if (awombatView.size() != totalCount) + fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" + + " have seen "+totalCount); + + final Set allMBeans = server. + queryNames(null, null); + if (!allMBeans.equals(awombatView)) + fail(test+awombat+" should have seen "+allMBeans); + + System.out.println(test + " PASSED"); + + } + + + public static void lazyStarterTest() throws Exception { + final String test = "lazyStarterTest: "; + System.out.println("" + + "\nThis test checks that it is possible to perform lazy loading" + + "\nof MBeans in a given domain by using a transient JMXDomain" + + "\nsubclass for that domain. "); + + System.out.println(test + " START"); + + // The "global" MBeanServer... + final MBeanServer platform = + ManagementFactory.getPlatformMBeanServer(); + + // A notification queue. + final BlockingQueue queue = + new ArrayBlockingQueue(100); + + // A listener that puts notifs in the queue. + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification, 5, TimeUnit.SECONDS)) { + throw new RuntimeException("timeout exceeded"); + } + } catch (Exception x) { + fail(test + "failed to handle notif", x); + } + } + }; + + System.out.println(test+" registering listener with delegate."); + platform.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + final String ld1 = "lazy1"; + final String ld2 = "lazy2"; + final int wCount = 5; + final LazyStarterDomain lazy1 = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld1, wCount); + } + }; + final LazyStarterDomain lazy2 = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld2, wCount); + } + }; + final ObjectName lo1 = JMXDomain.getDomainObjectName(ld1); + final ObjectName lo2 = JMXDomain.getDomainObjectName(ld2); + + final int initial = platform.getMBeanCount(); + + platform.registerMBean(lazy1, lo1); + System.out.println(test+"registered "+lo1); + checkSize(test, platform, initial+1); + popADD(queue, lo1, test); + + platform.registerMBean(lazy2, lo2); + System.out.println(test+"registered "+lo2); + checkSize(test, platform, initial+2); + popADD(queue, lo2, test); + + + final ObjectName awombat = new ObjectName( + ld1+":type=Wombat,name=wombat#"+wCount/2); + if (!platform.isRegistered(awombat)) + fail(test+"Expected "+awombat+" to be reggistered!"); + checkSize(test,platform,initial+wCount+1); + popREM(queue, lo1, test); + final ObjectName pat1 = + new ObjectName(ld1+":type=Wombat,name=wombat#*"); + for (int i=0;i all = platform.queryNames(null, null); + popREM(queue, lo2, test); + System.out.println(test+"Now found: "+all); + checkSize(test,platform,initial+wCount+wCount); + final ObjectName pat2 = + new ObjectName(ld2+":type=Wombat,name=wombat#*"); + for (int i=0;i testConcurrent = + new HashMap(); + for (int i=0;i<(100/wCount);i++) { + final String ld = "concurrent.lazy"+i; + final LazyStarterDomain lazy = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld, wCount-1); + } + }; + testConcurrent.put(ld, lazy); + final ObjectName lo = JMXDomain.getDomainObjectName(ld); + platform.registerMBean(lazy, lo); + popADD(queue, lo, test); + } + + System.out.println(test+"Big autoload: "+ + platform.queryNames(null,null)); + System.out.println(test+"Big after load: "+ + platform.queryNames(null,null)); + if (!platform.queryNames(JMXDomain.getDomainObjectName("*"), null). + isEmpty()) { + fail(test+" some domains are still here: "+ + platform.queryNames( + JMXDomain.getDomainObjectName("*"), null)); + } + queue.clear(); + System.out.println(test+"PASSED: The DomainDispatcher appears to be " + + "resilient to concurrent modifications."); + } + + public static void main(String... args) throws Exception { + + lazyTest(); + lazyStarterTest(); + + if (lastException != null) + throw lastException; + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/MXBeanRefTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/MXBeanRefTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,181 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test MXBeanRefTest.java + * @bug 5072476 + * @summary Test that MXBean proxy references work correctly in the presence + * of namespaces. + * @author Eamonn Mcmanus + */ + +/** + * The idea is that we will create a hierarchy like this: + * a// + * X + * b// + * Y + * Z + * and we will use MXBean references so we have links like this: + * a// + * X----+ + * b// | + * / + * Y + * \ + * / + * Z + * In other words, X.getY() will return a proxy for Y, which the MXBean + * framework will map to b//Y. A proxy for a//X should then map this + * into a proxy for a//b//Y. That's easy. But then if we call getZ() + * on this proxy, the MXBean framework will return just Z, and the proxy + * must map that into a proxy for a//b//Z. + */ + +import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.openmbean.OpenDataException; + +public class MXBeanRefTest { + + public static interface ZMXBean { + public void success(); + } + public static class ZImpl implements ZMXBean { + public void success() {} + } + + public static interface YMXBean { + public ZMXBean getZ(); + public void setZ(ZMXBean z); + } + public static class YImpl implements YMXBean { + private ZMXBean z; + + public YImpl(ZMXBean z) { + this.z = z; + } + + public ZMXBean getZ() { + return z; + } + + public void setZ(ZMXBean z) { + this.z = z; + } + } + + public static interface XMXBean { + public YMXBean getY(); + } + public static class XImpl implements XMXBean { + private final YMXBean yProxy; + + public XImpl(YMXBean yProxy) { + this.yProxy = yProxy; + } + + public YMXBean getY() { + return yProxy; + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + // Set up namespace hierarchy a//b// + MBeanServer ambs = MBeanServerFactory.newMBeanServer(); + MBeanServer bmbs = MBeanServerFactory.newMBeanServer(); + JMXNamespace bHandler = new JMXNamespace(bmbs); + ObjectName bHandlerName = JMXNamespaces.getNamespaceObjectName("b"); + System.out.println(bHandlerName); + ambs.registerMBean(bHandler, bHandlerName); + JMXNamespace aHandler = new JMXNamespace(ambs); + ObjectName aHandlerName = JMXNamespaces.getNamespaceObjectName("a"); + mbs.registerMBean(aHandler, aHandlerName); + + ZMXBean z = new ZImpl(); + ObjectName zName = new ObjectName("foo:type=Z"); + bmbs.registerMBean(z, zName); + + YMXBean y = new YImpl(z); + ObjectName yName = new ObjectName("foo:type=Y"); + bmbs.registerMBean(y, yName); + + ObjectName yNameInA = new ObjectName("b//" + yName); + System.out.println("MBeanInfo for Y as seen from a//:"); + System.out.println(ambs.getMBeanInfo(yNameInA)); + YMXBean yProxyInA = JMX.newMXBeanProxy(ambs, yNameInA, YMXBean.class); + XMXBean x = new XImpl(yProxyInA); + ObjectName xName = new ObjectName("foo:type=X"); + ambs.registerMBean(x, xName); + + ObjectName xNameFromTop = new ObjectName("a//" + xName); + XMXBean xProxy = JMX.newMXBeanProxy(mbs, xNameFromTop, XMXBean.class); + System.out.println("Name of X Proxy: " + proxyName(xProxy)); + YMXBean yProxy = xProxy.getY(); + System.out.println("Name of Y Proxy: " + proxyName(yProxy)); + ZMXBean zProxy = yProxy.getZ(); + System.out.println("Name of Z Proxy: " + proxyName(zProxy)); + + System.out.println("Operation through Z proxy..."); + zProxy.success(); + + System.out.println("Changing Y's ref to Z..."); + yProxy.setZ(zProxy); + zProxy = yProxy.getZ(); + System.out.println("Name of Z Proxy now: " + proxyName(zProxy)); + System.out.println("Operation through Z proxy again..."); + zProxy.success(); + + System.out.println("Changing Y's ref to a bogus one..."); + ZMXBean zProxyBad = JMX.newMXBeanProxy(mbs, zName, ZMXBean.class); + try { + yProxy.setZ(zProxyBad); + } catch (UndeclaredThrowableException e) { + Throwable cause = e.getCause(); + if (cause instanceof OpenDataException) { + System.out.println("...correctly got UndeclaredThrowableException"); + System.out.println("...wrapping: " + cause); + } else + throw new Exception("FAILED: wrong exception: " + cause); + } + + System.out.println("Test passed"); + } + + private static ObjectName proxyName(Object proxy) { + InvocationHandler ih = Proxy.getInvocationHandler(proxy); + MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler) ih; + return mbsih.getObjectName(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NamespaceController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NamespaceController.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,405 @@ +/* + * 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. + */ + +import com.sun.jmx.namespace.ObjectNameRouter; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.remote.JMXServiceURL; + +/** + * The {@code NamespaceController} MBean makes it possible to easily + * create mount points ({@linkplain JMXNamespace JMXNamespaces}) in an + * {@code MBeanServer}. + * There is at most one instance of NamespaceController in an + * MBeanServer - which can be created using the {@link #createInstance + * createInstance} method. The {@code NamespaceController} MBean will + * make it possible to remotely create name spaces by mounting remote + * MBeanServers into the MBeanServer in which it was registered. + */ +// This API was originally in the draft of javax/management/namespaces +// but we decided to retire it. Rather than removing all the associated +// tests I have moved the API to the test hierarchy - so it is now used as +// an additional (though somewhat complex) test case... +// +public class NamespaceController implements NamespaceControllerMBean, + NotificationEmitter, MBeanRegistration { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NamespaceController.class.getName()); + + private static long seqNumber=0; + + private final NotificationBroadcasterSupport broadcaster = + new NotificationBroadcasterSupport(); + + private volatile MBeanServer mbeanServer = null; + + private volatile ObjectName objectName = null; + + //was: NamespaceController.class.getPackage().getName() + public static final String NAMESPACE_CONTROLLER_DOMAIN = "jmx.ns"; + + /** + * Creates a new NamespaceController. + * Using {@link #createInstance} should be preferred. + **/ + public NamespaceController() { + this(null); + } + + public NamespaceController(MBeanServer mbeanServer) { + this.mbeanServer = mbeanServer; + } + + /* + * MBeanNotification support + * You shouldn't update these methods + */ + public final void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) { + broadcaster.addNotificationListener(listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + }; + } + + public final void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + public final void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener, filter, handback); + } + + public static synchronized long getNextSeqNumber() { + return seqNumber++; + } + + protected final void sendNotification(Notification n) { + if (n.getSequenceNumber()<=0) + n.setSequenceNumber(getNextSeqNumber()); + if (n.getSource()==null) + n.setSource(objectName); + broadcaster.sendNotification(n); + } + + /** + * The ObjectName with which this MBean was registered. + *

    Unless changed by subclasses, this is + * {@code + * "javax.management.namespace:type="+this.getClass().getSimpleName()}. + * @return this MBean's ObjectName, or null if this MBean was never + * registered. + **/ + public final ObjectName getObjectName() { + return objectName; + } + + /** + * The MBeanServer served by this NamespaceController. + * @return the MBeanServer served by this NamespaceController. + **/ + public final MBeanServer getMBeanServer() { + return mbeanServer; + } + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. Subclasses which override {@code preRegister} + * must call {@code super.preRegister(name,server)}; + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. + * The name must be either {@code null} - or equal to that + * described by {@link #getObjectName}. + * @return The name under which the MBean is to be registered. + * This will be the name described by {@link #getObjectName}. + * @throws MalformedObjectNameException if the supplied name does not + * meet expected requirements. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws MalformedObjectNameException { + objectName = name; + final ObjectName single = + ObjectName.getInstance(NAMESPACE_CONTROLLER_DOMAIN+ + ":type="+this.getClass().getSimpleName()); + if (name!=null && !single.equals(name)) + throw new MalformedObjectNameException(name.toString()); + if (mbeanServer == null) mbeanServer = server; + return single; + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * @param registrationDone Indicates whether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + public void postRegister(Boolean registrationDone) { + //TODO postRegister implementation; + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public void preDeregister() throws Exception { + //TODO preDeregister implementation; + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + */ + public void postDeregister() { + //TODO postDeregister implementation; + } + + public String mount(JMXServiceURL url, + String targetPath, + Map optionsMap) + throws IOException { + return mount(url, targetPath, "", optionsMap); + } + + // see NamespaceControllerMBean + public String mount(JMXServiceURL url, + String targetPath, + String sourcePath, + Map optionsMap) + throws IOException { + + // TODO: handle description. + final String dirName = + JMXNamespaces.normalizeNamespaceName(targetPath); + + try { + final ObjectInstance moi = + JMXRemoteTargetNamespace.createNamespace(mbeanServer, + dirName,url,optionsMap, + JMXNamespaces.normalizeNamespaceName(sourcePath) + ); + final ObjectName nsMBean = moi.getObjectName(); + try { + mbeanServer.invoke(nsMBean, "connect", null,null); + } catch (Throwable t) { + mbeanServer.unregisterMBean(nsMBean); + throw t; + } + return getMountPointID(nsMBean); + } catch (InstanceAlreadyExistsException x) { + throw new IllegalArgumentException(targetPath,x); + } catch (IOException x) { + throw x; + } catch (Throwable x) { + if (x instanceof Error) throw (Error)x; + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw ((IOException)cause); + if (cause == null) cause = x; + + final IOException io = + new IOException("connect failed: "+cause); + io.initCause(cause); + throw io; + } + } + + private String getMountPointID(ObjectName dirName) { + return dirName.toString(); + } + + private ObjectName getHandlerName(String mountPointID) { + try { + final ObjectName tryit = ObjectName.getInstance(mountPointID); + final ObjectName formatted = + JMXNamespaces.getNamespaceObjectName(tryit.getDomain()); + if (!formatted.equals(tryit)) + throw new IllegalArgumentException(mountPointID+ + ": invalid mountPointID"); + return formatted; + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(mountPointID,x); + } + } + + public boolean unmount(String mountPointID) + throws IOException { + final ObjectName dirName = getHandlerName(mountPointID); + if (!mbeanServer.isRegistered(dirName)) + throw new IllegalArgumentException(mountPointID+ + ": no such name space"); + final JMXRemoteNamespaceMBean mbean = + JMX.newMBeanProxy(mbeanServer,dirName, + JMXRemoteNamespaceMBean.class); + try { + mbean.close(); + } catch (IOException io) { + LOG.fine("Failed to close properly - ignoring exception: "+io); + LOG.log(Level.FINEST, + "Failed to close properly - ignoring exception",io); + } finally { + try { + mbeanServer.unregisterMBean(dirName); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(mountPointID+ + ": no such name space", x); + } catch (MBeanRegistrationException x) { + final IOException io = + new IOException(mountPointID +": failed to unmount"); + io.initCause(x); + throw io; + } + } + return true; + } + + public boolean ismounted(String targetPath) { + return mbeanServer.isRegistered(JMXNamespaces.getNamespaceObjectName(targetPath)); + } + + public ObjectName getHandlerNameFor(String targetPath) { + return JMXNamespaces.getNamespaceObjectName(targetPath); + } + + public String[] findNamespaces() { + return findNamespaces(null,null,0); + } + + + private ObjectName getDirPattern(String from) { + try { + if (from == null) + return ObjectName.getInstance(ALL_NAMESPACES); + final String namespace = + ObjectNameRouter.normalizeNamespacePath(from,false,true,false); + if (namespace.equals("")) + return ObjectName.getInstance(ALL_NAMESPACES); + if (JMXNamespaces.getNamespaceObjectName(namespace).isDomainPattern()) + throw new IllegalArgumentException(from); + return ObjectName.getInstance(namespace+NAMESPACE_SEPARATOR+ALL_NAMESPACES); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(from,x); + } + } + + public String[] findNamespaces(String from, String regex, int depth) { + if (depth < 0) return new String[0]; + final Set res = new TreeSet(); + final ObjectName all = getDirPattern(from); + Set names = mbeanServer.queryNames(all,null); + for (ObjectName dirName : names) { + final String dir = dirName.getDomain(); + if (regex == null || dir.matches(regex)) + res.add(dir); + if (depth > 0) + res.addAll(Arrays.asList(findNamespaces(dir,regex,depth-1))); + } + return res.toArray(new String[res.size()]); + } + + /** + * Creates a {@link NamespaceController} MBean in the provided + * {@link MBeanServerConnection}. + *

    The name of the MBean is that returned by {@link #preRegister} + * as described by {@link #getObjectName}. + * @throws IOException if an {@code IOException} is raised when invoking + * the provided connection. + * @throws InstanceAlreadyExistsException if an MBean was already + * registered with the NamespaceController's name. + * @throws MBeanRegistrationException if thrown by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + * @throws MBeanException if thrown by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + * @return the {@link ObjectInstance}, as returned by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + **/ + public static ObjectInstance createInstance(MBeanServerConnection server) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + try { + final ObjectInstance instance = + server.createMBean(NamespaceController.class.getName(), null); + return instance; + } catch (NotCompliantMBeanException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } catch (ReflectionException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } + } + + private final static String ALL_NAMESPACES= + "*"+NAMESPACE_SEPARATOR+":"+ + JMXNamespace.TYPE_ASSIGNMENT; + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NamespaceControllerMBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NamespaceControllerMBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,143 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.util.Map; + +import javax.management.ObjectName; +import javax.management.remote.JMXServiceURL; + +/** + * The {@link NamespaceController} MBean makes it possible to easily + * create mount points ({@link JMXNamespace JMXNamespaces}) in an + * {@code MBeanServer}. + */ +// This API was originally in the draft of javax/management/namespaces +// but we decided to retire it. Rather than removing all the associated +// tests I have moved the API to the test hierarchy - so it is now used as +// an additional (though somewhat complex) test case... +// +public interface NamespaceControllerMBean { + /** + * Mount MBeans from the source path of the source URL into the specified + * target path of the target. + * @param url URL of the mounted source. + * @param targetPath Target path in which MBeans will be mounted. + * @param optionsMap connection map and options. See {@link + * javax.management.namespace.JMXRemoteNamespace.Options + * JMXRemoteNamespace.Options} + * @throws IOException Connection with the source failed + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @return A mount point id. + */ + public String mount(JMXServiceURL url, + String targetPath, + Map optionsMap) + throws IOException, IllegalArgumentException; + + /** + * Mount MBeans from the source path of the source URL into the specified + * target path of the target. + * @param url URL of the mounted source. + * @param targetPath Target path in which MBeans will be mounted. + * @param sourcePath source namespace path. + * @param optionsMap connection map and options. See {@link + * javax.management.namespace.JMXRemoteNamespace.Options + * JMXRemoteNamespace.Options} + * @throws IOException Connection with the source failed + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @return A mount point id. + */ + public String mount(JMXServiceURL url, + String targetPath, + String sourcePath, + Map optionsMap) + throws IOException, IllegalArgumentException; + + /** + * Unmount a previously mounted mount point. + * @param mountPointId A mount point id, as previously returned + * by mount. + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @throws IOException thrown if the mount point {@link JMXNamespace} + * couldn't be unregistered. + */ + public boolean unmount(String mountPointId) + throws IOException, IllegalArgumentException; + + /** + * Tells whether there already exists a {@link JMXNamespace} for + * the given targetPath. + * @param targetPath a target name space path. + * @return true if a {@link JMXNamespace} is registered for that + * name space path. + **/ + public boolean ismounted(String targetPath); + + /** + * Returns the handler name for the provided target name space + * path. Can throw IllegalArgumentException if the provided + * targetPath contains invalid characters (like e.g. ':'). + * @param targetPath A target name space path. + * @return the handler name for the provided target name space + * path. + **/ + public ObjectName getHandlerNameFor(String targetPath); + + /** + * Return a sorted array of locally mounted name spaces. + * This is equivalent to calling {@link + * #findNamespaces(java.lang.String,java.lang.String,int) + * findNamespaces(null,null,0)}; + * @return a sorted array of locally mounted name spaces. + **/ + public String[] findNamespaces(); + + /** + * Return a sorted array of mounted name spaces, starting at + * from (if non null), and recursively searching up to + * provided depth. + * @param from A name spaces from which to start the search. If null, + * will start searching from the MBeanServer root. + * If not null, all returned names will start with from//. + * @param regex A regular expression that the returned names must match. + * If null - no matching is performed and all found names are + * returned. If not null, then all returned names satisfy + * {@link String#matches name.matches(regex)}; + * @param depth the maximum number of levels that the search algorithm + * will cross. 0 includes only top level name spaces, 1 top level + * and first level children etc... depth is evaluated + * with regard to where the search starts - if a non null + * from parameter is provided - then {@code depth=0} + * corresponds to all name spaces found right below + * from//. + * @return A sorted array of name spaces matching the provided criteria. + * All returned names end with "//". + **/ + public String[] findNamespaces(String from, String regex, int depth); +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NamespaceCreationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NamespaceCreationTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,262 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test NamespaceCreationTest.java + * @summary General JMXNamespace test. + * @author Daniel Fuchs + * @run clean NamespaceCreationTest Wombat WombatMBean + * @run build NamespaceCreationTest Wombat WombatMBean + * @run main NamespaceCreationTest + */ + + +import java.util.Collections; +import java.util.Map; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.RuntimeMBeanException; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; + +/** + * Test simple creation/registration of namespace. + * + */ +public class NamespaceCreationTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalNamespace extends JMXNamespace { + + public LocalNamespace() { + super(MBeanServerFactory.newMBeanServer()); + } + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + /** + * Check that we can register a JMXNamespace MBean, using its standard + * ObjectName. + * @throws java.lang.Exception + */ + public static void testGoodObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + final ObjectName name = + JMXNamespaces.getNamespaceObjectName("gloups"); + final ObjectInstance oi = + server.registerMBean(new LocalNamespace(),name); + System.out.println("Succesfully registered namespace: "+name); + try { + if (! name.equals(oi.getObjectName())) + throw new RuntimeException("testGoodObjectName: TEST failed: " + + "namespace registered as: "+ + oi.getObjectName()+" expected: "+name); + } finally { + server.unregisterMBean(oi.getObjectName()); + } + System.out.println("Succesfully unregistered namespace: "+name); + System.out.println("testGoodObjectName PASSED"); + } + + /** + * Check that we cannot register a JMXNamespace MBean, if we don't use + * its standard ObjectName. + * @throws java.lang.Exception + */ + public static void testBadObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("d:k=v"); + try { + server.registerMBean(new LocalNamespace(),name); + System.out.println("testBadObjectName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadObjectName PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean in a namespace that does + * not exists. + * + * @throws java.lang.Exception + */ + public static void testBadNamespace() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glips//d:k=v"); + + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadNamespace: " + + "Error: MBean registered, no exception thrown."); + } catch(MBeanRegistrationException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected MBeanRegistrationException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadNamespace PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean with a domain name + * that ends with //. This is reserved for namespaces. + * + * @throws java.lang.Exception + */ + public static void testBadDomain() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glups//:k=v"); + + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadDomain: Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadDomain PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean as if it were a + * JMXNamespace. Only JMXNamespace MBeans can have JMX Namespace names. + * @throws java.lang.Exception + */ + public static void testBadClassName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = + JMXNamespaces.getNamespaceObjectName("glops"); + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadClassName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadClassName PASSED"); + } + + public static void main(String... args) throws Exception { + testCreateWithNull(); + testGoodObjectName(); + testBadObjectName(); + testBadNamespace(); + testBadDomain(); + testBadClassName(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NamespaceNotificationsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,388 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test NamespaceNotificationsTest.java 1.12 + * @summary General Namespace & Notifications test. + * @author Daniel Fuchs + * @run clean NamespaceNotificationsTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true NamespaceNotificationsTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main NamespaceNotificationsTest + */ +import com.sun.jmx.remote.util.EventClientConnection; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.loading.MLet; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAddressable; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class NamespaceNotificationsTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NamespaceNotificationsTest.class.getName()); + + /** Creates a new instance of NamespaceNotificationsTest */ + public NamespaceNotificationsTest() { + } + + + public static JMXServiceURL export(MBeanServer server) + throws Exception { + final JMXServiceURL in = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(in,null,null); + final ObjectName csname = ObjectName. + getInstance(cs.getClass().getPackage().getName()+ + ":type="+cs.getClass().getSimpleName()); + server.registerMBean(cs,csname); + cs.start(); + return cs.getAddress(); + } + + public static class Counter { + int count; + public synchronized int count() { + count++; + notifyAll(); + return count; + } + public synchronized int peek() { + return count; + } + public synchronized int waitfor(int max, long timeout) + throws InterruptedException { + final long start = System.currentTimeMillis(); + while (count < max && timeout > 0) { + final long rest = timeout - + (System.currentTimeMillis() - start); + if (rest <= 0) break; + wait(rest); + } + return count; + } + } + + public static class CounterListener + implements NotificationListener { + final private Counter counter; + public CounterListener(Counter counter) { + this.counter = counter; + } + public void handleNotification(Notification notification, + Object handback) { + System.out.println("Received notif from " + handback + + ":\n\t" + notification); + if (!notification.getSource().equals(handback)) { + System.err.println("OhOh... Unexpected source: \n\t"+ + notification.getSource()+"\n\twas expecting:\n\t"+ + handback); + } + counter.count(); + } + } + + public static void simpleTest(String[] args) { + try { + final MBeanServer server1 = + ManagementFactory.getPlatformMBeanServer(); + final JMXServiceURL url1 = export(server1); + + final MBeanServer server2 = + MBeanServerFactory.createMBeanServer("server2"); + final JMXServiceURL url2 = export(server2); + + final MBeanServer server3 = + MBeanServerFactory.createMBeanServer("server3"); + final JMXServiceURL url3 = export(server3); + + final ObjectInstance ncinst = + NamespaceController.createInstance(server1); + + final NamespaceControllerMBean nc = + JMX.newMBeanProxy(server1,ncinst.getObjectName(), + NamespaceControllerMBean.class); + + final Map options = new HashMap(); + options.put(JMXRemoteTargetNamespace.CREATE_EVENT_CLIENT,"true"); + + final String mount1 = + nc.mount(url1,"server1",options); + final String mount2 = nc.mount(url2,"server1//server2", + options); + final String mount3 = nc.mount(url3, + "server1//server2//server3", + options); + final String mount13 = nc.mount( + url1, + "server3", + "server2//server3", + options); + final String mount21 = nc.mount(url1,"server2//server1", + options); + final String mount31 = nc.mount( + url1, + "server3//server1", + "server1", + options); + final String mount32 = nc.mount( + url1, + "server3//server2", + "server2", + options); + + + final ObjectName deep = + new ObjectName("server1//server2//server3//bush:type=Wombat,name=kanga"); + server1.createMBean(Wombat.class.getName(),deep); + + System.err.println("There's a wombat in the bush!"); + + final Counter counter = new Counter(); + + final NotificationListener listener = + new CounterListener(counter); + + final JMXConnector jc = JMXConnectorFactory.connect(url1); + final MBeanServerConnection aconn = + EventClientConnection.getEventConnectionFor( + jc.getMBeanServerConnection(),null); + aconn.addNotificationListener(deep,listener,null,deep); + + + final JMXServiceURL urlx = new JMXServiceURL(url1.toString()); + System.out.println("conn: "+urlx); + final JMXConnector jc2 = JMXNamespaces.narrowToNamespace( + JMXConnectorFactory.connect(urlx),"server1//server1"); + final JMXConnector jc3 = JMXNamespaces.narrowToNamespace(jc2,"server3"); + jc3.connect(); + System.out.println("JC#3: " + + ((jc3 instanceof JMXAddressable)? + ((JMXAddressable)jc3).getAddress(): + jc3.toString())); + final MBeanServerConnection bconn = + jc3.getMBeanServerConnection(); + final ObjectName shallow = + new ObjectName("bush:"+ + deep.getKeyPropertyListString()); + final WombatMBean proxy = + JMX.newMBeanProxy(EventClientConnection.getEventConnectionFor( + bconn,null),shallow,WombatMBean.class,true); + + ((NotificationEmitter)proxy). + addNotificationListener(listener,null,shallow); + proxy.setCaption("I am a new Wombat!"); + System.err.println("New caption: "+proxy.getCaption()); + final int rcvcount = counter.waitfor(2,3000); + if (rcvcount != 2) + throw new RuntimeException("simpleTest failed: "+ + "received count is " +rcvcount); + + System.err.println("simpleTest passed: got "+rcvcount+ + " notifs"); + + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("simpleTest failed: " + x,x); + } + } + + public static class LocalNamespace extends + JMXNamespace { + LocalNamespace() { + super(MBeanServerFactory.newMBeanServer()); + } + + } + + public static class ContextObject { + public final K name; + public final V object; + public ContextObject(K name, V object) { + this.name = name; + this.object = object; + } + private Object[] data() { + return new Object[] {name,object}; + } + + @Override + public boolean equals(Object x) { + if (x instanceof ContextObject) + return Arrays.deepEquals(data(),((ContextObject)x).data()); + return false; + } + @Override + public int hashCode() { + return Arrays.deepHashCode(data()); + } + } + + private static ContextObject context(K k, V v) { + return new ContextObject(k,v); + } + + private static ObjectName name(String name) { + try { + return new ObjectName(name); + } catch(MalformedObjectNameException x) { + throw new IllegalArgumentException(name,x); + } + } + + public static void simpleTest2() { + try { + System.out.println("\nsimpleTest2: STARTING\n"); + final LocalNamespace foo = new LocalNamespace(); + final LocalNamespace joe = new LocalNamespace(); + final LocalNamespace bar = new LocalNamespace(); + final MBeanServer server = MBeanServerFactory.newMBeanServer(); + + server.registerMBean(foo,JMXNamespaces.getNamespaceObjectName("foo")); + server.registerMBean(joe,JMXNamespaces.getNamespaceObjectName("foo//joe")); + server.registerMBean(bar,JMXNamespaces.getNamespaceObjectName("foo//bar")); + final BlockingQueue> queue = + new ArrayBlockingQueue>(20); + + 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 name in the handback. + // + final String namespace = (String) handback; + System.out.println("Received " + mbsn.getType() + + " for MBean " + mbsn.getMBeanName() + + " from name space " + namespace); + try { + queue.offer(context(namespace,mbsn),500,TimeUnit.MILLISECONDS); + } catch (Exception x) { + System.err.println("Failed to enqueue received notif: "+mbsn); + x.printStackTrace(); + } + } + }; + + server.addNotificationListener(JMXNamespaces.insertPath("foo//joe", + MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe"); + server.addNotificationListener(JMXNamespaces.insertPath("foo//bar", + MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar"); + server.createMBean(MLet.class.getName(), + name("foo//joe//domain:type=MLet")); + checkQueue(queue,"foo//joe", + MBeanServerNotification.REGISTRATION_NOTIFICATION); + server.createMBean(MLet.class.getName(), + name("foo//bar//domain:type=MLet")); + checkQueue(queue,"foo//bar", + MBeanServerNotification.REGISTRATION_NOTIFICATION); + server.unregisterMBean( + name("foo//joe//domain:type=MLet")); + checkQueue(queue,"foo//joe", + MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + server.unregisterMBean( + name("foo//bar//domain:type=MLet")); + checkQueue(queue,"foo//bar", + MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + } catch (RuntimeException x) { + System.err.println("FAILED: "+x); + throw x; + } catch(Exception x) { + System.err.println("FAILED: "+x); + throw new RuntimeException("Unexpected exception: "+x,x); + } + } + + + private static void checkQueue( + BlockingQueue> q, + String path, String type) { + try { + final ContextObject ctxt = + q.poll(500,TimeUnit.MILLISECONDS); + if (ctxt == null) + throw new RuntimeException("Timeout expired: expected notif from "+ + path +", type="+type); + if (!ctxt.name.equals(path)) + throw new RuntimeException("expected notif from "+ + path +", got "+ctxt.name); + if (!ctxt.object.getType().equals(type)) + throw new RuntimeException(ctxt.name+": expected type="+ + type +", got "+ctxt.object.getType()); + if (!ctxt.object.getType().equals(type)) + throw new RuntimeException(ctxt.name+": expected type="+ + type +", got "+ctxt.object.getType()); + if (!ctxt.object.getMBeanName().equals(name("domain:type=MLet"))) + throw new RuntimeException(ctxt.name+": expected MBean=domain:type=MLet"+ + ", got "+ctxt.object.getMBeanName()); + } catch(InterruptedException x) { + throw new RuntimeException("unexpected interruption: "+x,x); + } + } + + public static void main(String[] args) { + simpleTest(args); + simpleTest2(); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NullDomainObjectNameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NullDomainObjectNameTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,284 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test NullDomainObjectNameTest.java + * @summary Test that null domains are correctly handled in namespaces. + * @author Daniel Fuchs + * @run clean NullDomainObjectNameTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true NullDomainObjectNameTest.java + * @run build NullDomainObjectNameTest Wombat WombatMBean + * @run main NullDomainObjectNameTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * Class NullDomainObjectNameTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class NullDomainObjectNameTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NullDomainObjectNameTest.class.getName()); + + /** Creates a new instance of NullDomainObjectNameTest */ + public NullDomainObjectNameTest() { + } + + public static class MyWombat + extends Wombat { + public MyWombat() throws NotCompliantMBeanException { + super(); + } + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + + if (name == null) + name = new ObjectName(":type=Wombat"); + + return super.preRegister(server, name); + } + + } + + static String failure=null; + + public static void testRegister() throws Exception { + final MBeanServer top = ManagementFactory.getPlatformMBeanServer(); + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer srv = + JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub); + srv.start(); + + try { + + // Create a namespace rmi// that points to 'sub' and flows through + // a JMXRemoteNamespace connected to 'srv' + // The namespace rmi// will accept createMBean, but not registerMBean. + // + final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace. + newJMXRemoteNamespace(srv.getAddress(), + null); + top.registerMBean(rmiHandler,JMXNamespaces.getNamespaceObjectName("rmi")); + top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"), + "connect", null, null); + + // Create a namespace direct// that points to 'sub' and flows + // through a direct reference to 'sub'. + // The namespace direct// will accept createMBean, and registerMBean. + // + final JMXNamespace directHandler = new JMXNamespace(sub); + top.registerMBean(directHandler, + JMXNamespaces.getNamespaceObjectName("direct")); + + // Now cd to each of the created namespace. + // + MBeanServer cdrmi = JMXNamespaces.narrowToNamespace(top,"rmi"); + MBeanServer cddirect = JMXNamespaces.narrowToNamespace(top,"direct"); + boolean ok = false; + + // Check that calling createMBean with a null domain works + // for namespace rmi// + // + try { + final ObjectInstance moi1 = + cdrmi.createMBean(MyWombat.class.getName(), + new ObjectName(":type=Wombat")); + System.out.println(moi1.getObjectName().toString()+ + ": created through rmi//"); + assertEquals(moi1.getObjectName().getDomain(), + cddirect.getDefaultDomain()); + cddirect.unregisterMBean(moi1.getObjectName()); + } catch (MBeanRegistrationException x) { + System.out.println("Received unexpected exception: " + x); + failed("Received unexpected exception: " + x); + } + + // Check that calling refgisterMBean with a null domain works + // for namespace direct// + // + try { + final ObjectInstance moi2 = + cddirect.registerMBean(new MyWombat(), + new ObjectName(":type=Wombat")); + System.out.println(moi2.getObjectName().toString()+ + ": created through direct//"); + assertEquals(moi2.getObjectName().getDomain(), + cdrmi.getDefaultDomain()); + cdrmi.unregisterMBean(moi2.getObjectName()); + } catch (MBeanRegistrationException x) { + System.out.println("Received unexpected exception: " + x); + failed("Received unexpected exception: " + x); + } + + // Now artificially pretend that 'sub' is contained in a faked// + // namespace. + // + RoutingServerProxy proxy = + new RoutingServerProxy(sub, "", "faked", false); + + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(), + new ObjectName(":type=Wombat")); + System.out.println(moi3.getObjectName().toString()+ + ": created through faked//"); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // null should work with "faked//" + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(),null); + assertEquals(moi3.getObjectName().getDomain(), + "faked//"+sub.getDefaultDomain()); + + System.out.println(moi3.getObjectName().toString() + + ": created through faked//"); + + // Now check that null is correctly handled (accepted or rejected) + // in queries for each of the above configs. + // + ObjectName wombat = moi3.getObjectName().withDomain( + moi3.getObjectName().getDomain().substring("faked//".length())); + ObjectInstance moi = new ObjectInstance(wombat,moi3.getClassName()); + + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with rmi//"); + assertEquals(cdrmi.queryNames( + new ObjectName(":*"),null).contains(wombat),true); + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with direct//"); + assertEquals(cddirect.queryNames( + new ObjectName(":*"),null).contains(wombat),true); + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with rmi//"); + assertEquals(cdrmi.queryMBeans( + new ObjectName(":*"),null).contains(moi),true); + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with direct//"); + assertEquals(cddirect.queryMBeans( + new ObjectName(":*"),null).contains(moi),true); + + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with faked//"); + assertEquals(proxy.queryNames( + new ObjectName(":*"),null). + contains(moi3.getObjectName()),true); + failed("queryNames(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with faked//"); + assertEquals(proxy.queryMBeans( + new ObjectName(":*"),null).contains(moi3),true); + failed("queryMBeans(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + + System.out.println("Checking queryNames(faked//*:*,null)"); + assertEquals(proxy.queryNames(new ObjectName("faked//*:*"),null). + contains(moi3.getObjectName()),true); + + System.out.println("Checking queryMBeans(faked//*:*,null)"); + assertEquals(proxy.queryMBeans(new ObjectName("faked//*:*"),null). + contains(moi3),true); + + proxy.unregisterMBean(moi3.getObjectName()); + + // ADD NEW TESTS HERE ^^^ + + } finally { + srv.stop(); + } + + if (failure != null) + throw new Exception(failure); + + + } + private static void assertEquals(Object x, Object y) { + if (!equal(x, y)) + failed("expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + + public static void main(String[] args) throws Exception { + testRegister(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/NullObjectNameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/NullObjectNameTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,251 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test NullObjectNameTest.java + * @summary Test that null ObjectName are correctly handled in namespaces. + * @author Daniel Fuchs + * @run clean NullObjectNameTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true NullObjectNameTest.java + * @run build NullObjectNameTest Wombat WombatMBean + * @run main NullObjectNameTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * Class NullObjectNameTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class NullObjectNameTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NullObjectNameTest.class.getName()); + + /** Creates a new instance of NullObjectNameTest */ + public NullObjectNameTest() { + } + + public static class MyWombat + extends Wombat { + public MyWombat() throws NotCompliantMBeanException { + super(); + } + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + + if (name == null) + name = new ObjectName(":type=Wombat"); + + return super.preRegister(server, name); + } + + } + + static String failure=null; + + public static void testRegister() throws Exception { + final MBeanServer top = ManagementFactory.getPlatformMBeanServer(); + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer srv = + JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub); + srv.start(); + + try { + + // Create a namespace rmi// that points to 'sub' and flows through + // a JMXRemoteNamespace connected to 'srv' + // The namespace rmi// will accept createMBean, but not registerMBean. + // + final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace. + newJMXRemoteNamespace(srv.getAddress(),null); + top.registerMBean(rmiHandler,JMXNamespaces.getNamespaceObjectName("rmi")); + top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"), + "connect", null, null); + + // Create a namespace direct// that points to 'sub' and flows + // through a direct reference to 'sub'. + // The namespace direct// will accept createMBean, and registerMBean. + // + final JMXNamespace directHandler = new JMXNamespace(sub); + top.registerMBean(directHandler, + JMXNamespaces.getNamespaceObjectName("direct")); + + // Now cd to each of the created namespace. + // + MBeanServer cdrmi = JMXNamespaces.narrowToNamespace(top,"rmi"); + MBeanServer cddirect = JMXNamespaces.narrowToNamespace(top,"direct"); + boolean ok = false; + + // Check that calling createMBean with a null ObjectName fails + // gracefully for namespace rmi// (we can't add rmi// to a null + // ObjectName. + // + // TODO: do this test for all createMBean flavors! + try { + final ObjectInstance moi1 = + cdrmi.createMBean(MyWombat.class.getName(),null); + System.out.println(moi1.getObjectName().toString()+ + ": created through rmi//"); + cddirect.unregisterMBean(moi1.getObjectName()); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // Check that calling refgisterMBean with a null ObjectName fails + // gracefully for namespace direct// (we can't add direct// to a null + // ObjectName. + // + try { + final ObjectInstance moi2 = + cddirect.registerMBean(new MyWombat(), (ObjectName)null); + System.out.println(moi2.getObjectName().toString()+ + ": created through direct//"); + cdrmi.unregisterMBean(moi2.getObjectName()); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // Now artificially pretend that 'sub' is contained in a faked// + // namespace. + // We should be able to use 'null' in registerMBean/createMBean in + // this case. + // + RoutingServerProxy proxy = + new RoutingServerProxy(sub,"","faked",false); + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(),null); + System.out.println(moi3.getObjectName().toString()+ + ": created through faked//"); + + // Now check that null is correctly handled (accepted or rejected) + // in queries for each of the above configs. + // + ObjectName wombat = moi3.getObjectName().withDomain( + moi3.getObjectName().getDomain().substring("faked//".length())); + ObjectInstance moi = new ObjectInstance(wombat,moi3.getClassName()); + + System.out.println("Checking queryNames(null,null) with rmi//"); + assertEquals(cdrmi.queryNames(null,null).contains(wombat),true); + System.out.println("Checking queryNames(null,null) with direct//"); + assertEquals(cddirect.queryNames(null,null).contains(wombat),true); + System.out.println("Checking queryMBeans(null,null) with rmi//"); + assertEquals(cdrmi.queryMBeans(null,null).contains(moi),true); + System.out.println("Checking queryMBeans(null,null) with direct//"); + assertEquals(cddirect.queryMBeans(null,null).contains(moi),true); + + try { + System.out.println("Checking queryNames(null,null) with faked//"); + assertEquals(proxy.queryNames(null,null). + contains(moi3.getObjectName()),true); + failed("queryNames(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + try { + System.out.println("Checking queryMBeans(null,null) with faked//"); + assertEquals(proxy.queryMBeans(null,null).contains(moi3),true); + failed("queryMBeans(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + System.out.println("Checking queryNames(faked//*:*,null)"); + assertEquals(proxy.queryNames(new ObjectName("faked//*:*"),null). + contains(moi3.getObjectName()),true); + + System.out.println("Checking queryMBeans(faked//*:*,null)"); + assertEquals(proxy.queryMBeans(new ObjectName("faked//*:*"),null). + contains(moi3),true); + + proxy.unregisterMBean(moi3.getObjectName()); + + // ADD NEW TESTS HERE ^^^ + + } finally { + srv.stop(); + } + + if (failure != null) + throw new Exception(failure); + + + } + private static void assertEquals(Object x, Object y) { + if (!equal(x, y)) + failed("expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + + public static void main(String[] args) throws Exception { + testRegister(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/QueryNamesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/QueryNamesTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,408 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test QueryNamesTest.java 1.4 + * @summary Test how queryNames works with Namespaces. + * @author Daniel Fuchs + * @run clean QueryNamesTest Wombat WombatMBean + * @run build QueryNamesTest Wombat WombatMBean + * @run main QueryNamesTest + */ + + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.logging.Logger; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; + +/** + * Class QueryNamesTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class QueryNamesTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(QueryNamesTest.class.getName()); + + public static class LocalNamespace + extends JMXNamespace { + + private static MBeanServer check(MBeanServer server) { + if (server == null) + throw new IllegalArgumentException("MBeanServer can't be null"); + return server; + } + + public LocalNamespace() { + this(MBeanServerFactory.createMBeanServer()); + } + + public LocalNamespace(MBeanServer server) { + super(check(server)); + } + + + public static String add(MBeanServerConnection server, + String nspath) + throws IOException, JMException { + server.createMBean(LocalNamespace.class.getName(), + JMXNamespaces.getNamespaceObjectName(nspath)); + return nspath; + } + } + + /** Creates a new instance of QueryNamesTest */ + public QueryNamesTest() { + } + + private static String[] namespaces = { + "greg", "greg//chichille", "greg//chichille//petard", + "greg//alambic", "greg//alambic//canette", + "greg//chichille/virgule", "greg//chichille/funeste", + "greg//chichille/virgule//bidouble", + "greg//chichille/virgule//bi/double", + "fran", "fran//gast", "fran//gast//gaf", + "fran//longtar", "fran//longtar//parcmetre" + }; + + private static void createNamespaces(MBeanServer server) throws Exception { + final LinkedList all = new LinkedList(); + try { + for (String ns : namespaces) + all.addFirst(LocalNamespace.add(server,ns)); + } catch (Exception e) { + removeNamespaces(server,all.toArray(new String[all.size()])); + throw e; + } + } + + // Dummy test that checks that all JMXNamespaces are registered, + // but are not returned by queryNames("*:*"); + // + private static void checkRegistration(MBeanServer server) + throws Exception { + final Set handlerNames = new HashSet(namespaces.length); + for (String ns : namespaces) + handlerNames.add(JMXNamespaces.getNamespaceObjectName(ns)); + for (ObjectName nh : handlerNames) // check handler registration + if (!server.isRegistered(nh)) + throw new InstanceNotFoundException("handler "+nh+ + " is not registered"); + + // global: queryNames("*:*") from top level + final Set all1 = server.queryNames(null,null); + final Set all2 = server.queryNames(ObjectName.WILDCARD,null); + if (!all1.equals(all2)) + throw new Exception("queryNames(*:*) != queryNames(null)"); + final Set common = new HashSet(all1); + common.retainAll(handlerNames); + + final Set ref = new HashSet(); + for (String ns : namespaces) { + if (!ns.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + ref.add(JMXNamespaces.getNamespaceObjectName(ns)); + } + if (!common.equals(ref)) { + throw new Exception("some handler names were not returned by " + + "wildcard query - only returned: "+common+ + ", expected: "+ref); + } + + // for each namespace: queryNames("//*:*"); + for (String ns : namespaces) { + final ObjectName pattern = new ObjectName(ns+ + JMXNamespaces.NAMESPACE_SEPARATOR+"*:*"); + final Set all4 = + server.queryNames(pattern,null); + final Set common4 = new HashSet(all4); + common4.retainAll(handlerNames); + + final Set ref4 = new HashSet(); + for (String ns2 : namespaces) { + if (! ns2.startsWith(ns+JMXNamespaces.NAMESPACE_SEPARATOR)) + continue; + if (!ns2.substring(ns.length()+ + JMXNamespaces.NAMESPACE_SEPARATOR.length()). + contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + ref4.add(JMXNamespaces.getNamespaceObjectName(ns2)); + } + if (!common4.equals(ref4)) { + throw new Exception("some handler names were not returned by " + + "wildcard query on "+pattern+" - only returned: "+common4+ + ", expected: "+ref4); + } + } + } + + // Make a Map + private static Map> makeNsTree(String[] nslist) { + final Map> nsTree = + new LinkedHashMap>(nslist.length); + for (String ns : nslist) { + if (nsTree.get(ns) == null) + nsTree.put(ns,new LinkedHashSet()); + final String[] elts = ns.split(JMXNamespaces.NAMESPACE_SEPARATOR); + int last = ns.lastIndexOf(JMXNamespaces.NAMESPACE_SEPARATOR); + if (last<0) continue; + while (last > 0 && ns.charAt(last-1) == '/') last--; + final String parent = ns.substring(0,last); + if (nsTree.get(parent) == null) + nsTree.put(parent,new LinkedHashSet()); + nsTree.get(parent).add(ns); + } + return nsTree; + } + + private static class Rigolo { + final static String[] ones = { "a", "e", "i", "o", "u", "y", "ai", "oo", + "ae", "ey", "ay", "oy", "au", "ou", "eu", "oi", "ei", "ea"}; + final static String[] twos = { "b", "bz", "c", "cz", "ch", + "ct", "ck", "cs", "d", "ds", "f", "g", "gh", "h", "j", "k", "l", "m", + "n", "p", "ps", "q", "r", "s", "sh", "t", "v", "w", "x", + "z"}; + final static String[] threes = {"rr","tt","pp","ss","dd","ff","ll", "mm", "nn", + "zz", "cc", "bb"}; + final static String[] fours = {"x", "s", "ght", "cks", "rt", "rts", "ghts", "bs", + "ts", "gg" }; + final static String[] fives = { "br", "bl", "cr", "cn", "cth", "dr", + "fr", "fl", "cl", "chr", "gr", "gl", "kr", "kh", "pr", "pl", "ph", + "rh", "sr", "tr", "vr"}; + + private Random rg = new Random(); + + private String next(String[] table) { + return table[rg.nextInt(table.length)]; + } + + public String nextName(int max) { + final Random rg = new Random(); + final int nl = 3 + rg.nextInt(max); + boolean begin = rg.nextBoolean(); + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < nl ; j++) { + if (begin) { + sb.append(next(ones)); + } else if (j > 0 && j < nl-1 && rg.nextInt(4)==0) { + sb.append(next(threes)); + } else if (j < nl-1 && rg.nextInt(3)==0) { + sb.append(next(fives)); + } else { + sb.append(next(twos)); + } + begin = !begin; + } + if (!begin && rg.nextInt(2)==0) + sb.append(next(fours)); + return sb.toString(); + } + + private ObjectName getWombatName(String ns, String domain, String name) + throws MalformedObjectNameException { + String d = domain; + if (ns != null && !ns.equals("")) + d = ns + JMXNamespaces.NAMESPACE_SEPARATOR + domain; + return new ObjectName(d+":type=Wombat,name="+name); + } + + public Set nextWombats(String ns) + throws MalformedObjectNameException { + final int dcount = 1 + rg.nextInt(5); + final Set wombats = new HashSet(); + for (int i = 0; i < dcount ; i++) { + final String d = nextName(7); + final int ncount = 5 + rg.nextInt(20); + for (int j = 0 ; j> nsTree = makeNsTree(namespaces); + final Random rg = new Random(); + final Rigolo rigolo = new Rigolo(); + for (String ns : namespaces) { + final ObjectName name = JMXNamespaces.getNamespaceObjectName(ns); + final String[] doms = + (String[])server.getAttribute(name,"Domains"); + final Set subs = new HashSet(); + for (String d : doms) { + if (d.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { + subs.add(ns+JMXNamespaces.NAMESPACE_SEPARATOR+d.substring(0, + d.length()-JMXNamespaces.NAMESPACE_SEPARATOR.length())); + } + } + + final Set expectNs = new HashSet(nsTree.get(ns)); + + if (! subs.containsAll(expectNs)) + throw new Exception("getDomains didn't return all namespaces: "+ + "returned="+subs+", expected="+expectNs); + if (! expectNs.containsAll(subs)) + throw new Exception("getDomains returned additional namespaces: "+ + "returned="+subs+", expected="+expectNs); + + final Set nsNames = server.queryNames( + new ObjectName(ns+ + JMXNamespaces.NAMESPACE_SEPARATOR+"*"+ + JMXNamespaces.NAMESPACE_SEPARATOR+":*"),null); + + final Set expect = + new HashSet(expectNs.size()); + for (String sub : expectNs) { + expect.add(JMXNamespaces.getNamespaceObjectName(sub)); + } + + if (! nsNames.containsAll(expect)) + throw new Exception("queryNames didn't return all namespaces: "+ + "returned="+nsNames+", expected="+expect); + if (! expect.containsAll(nsNames)) + throw new Exception("getDomains returned additional namespaces: "+ + "returned="+nsNames+", expected="+expect); + + } + } + + private static void addWombats(MBeanServer server, Set names) + throws Exception { + for (ObjectName on : names) { + if (! server.isRegistered(on)) { + server.createMBean(Wombat.class.getName(),on); + System.out.println("A new wombat is born: "+on); + } + } + } + + private static void addWombats(MBeanServer server, + Map> wombats) + throws Exception { + for (String ns : wombats.keySet()) { + addWombats(server,wombats.get(ns)); + } + } + + private static Map> nameWombats() + throws Exception { + final Rigolo rigolo = new Rigolo(); + final Map> wombats = + new HashMap>(namespaces.length); + + for (String ns : namespaces) { + wombats.put(ns,rigolo.nextWombats(ns)); + } + wombats.put("",rigolo.nextWombats("")); + return wombats; + } + + private static boolean removeWombats(MBeanServer server, + Map> wombats) { + boolean res = true; + for (String ns : wombats.keySet()) { + res = res && removeWombats(server,wombats.get(ns)); + } + return res; + } + + private static boolean removeWombats(MBeanServer server, + Set wombats) { + boolean res = true; + for (ObjectName on : wombats) { + try { + if (server.isRegistered(on)) + server.unregisterMBean(on); + } catch (Exception x) { + res = false; + System.out.println("Failed to remove "+on+": "+x); + } + } + return res; + } + + public static void main(String[] args) + throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Map> wombats = nameWombats(); + createNamespaces(server); + try { + addWombats(server,wombats); + System.out.println("MBeans: " +server.getMBeanCount()); + System.out.println("Visible: " +server.queryNames(null,null).size()); + System.out.println("Domains: " +Arrays.asList(server.getDomains())); + checkRegistration(server); + checkNsQuery(server); + } finally { + boolean res = true; + res = res && removeWombats(server, wombats); + if (!res) + throw new RuntimeException("failed to cleanup some namespaces"); + } + + } + + private static boolean removeNamespaces(MBeanServer server) { + final List l = Arrays.asList(namespaces); + Collections.reverse(l); + return removeNamespaces(server, l.toArray(new String[namespaces.length])); + } + + private static boolean removeNamespaces(MBeanServer server, String[] t) { + boolean success = true; + for (String ns : t) { + try { + server.unregisterMBean(JMXNamespaces.getNamespaceObjectName(ns)); + } catch (Exception x) { + System.out.println("failed to remove namespace: "+ ns); + success = false; + } + } + return success; + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/RemoveNotificationListenerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/RemoveNotificationListenerTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,376 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * + * @test RemoveNotificationListenerTest.java 1.8 + * @summary General RemoveNotificationListenerTest test. + * @author Daniel Fuchs + * @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace + * @compile -XDignore.symbol.file=true JMXRemoteTargetNamespace.java + * @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace + * @run main/othervm RemoveNotificationListenerTest + */ + +import com.sun.jmx.remote.util.EventClientConnection; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.security.Principal; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAuthenticator; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXConnectorServerMBean; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +/** + * Class RemoveNotificationListenerTest + */ +public class RemoveNotificationListenerTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(RemoveNotificationListenerTest.class.getName()); + + /** Creates a new instance of RemoveNotificationListenerTest */ + public RemoveNotificationListenerTest() { + } + + public static class SubjectAuthenticator implements JMXAuthenticator { + final Set authorized; + public SubjectAuthenticator(Subject[] authorized) { + this.authorized = new HashSet(Arrays.asList(authorized)); + } + + public Subject authenticate(Object credentials) { + if (authorized.contains(credentials)) + return (Subject)credentials; + else + throw new SecurityException("Subject not authorized: "+credentials); + } + + } + + public static interface LongtarMBean { + public void sendNotification(Object userData) + throws IOException, JMException; + } + public static class Longtar extends NotificationBroadcasterSupport + implements LongtarMBean { + public Longtar() { + super(new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] {"papillon"}, + "pv","M'enfin???") + }); + } + + public void sendNotification(Object userData) + throws IOException, JMException { + final Notification n = + new Notification("papillon",this,nextseq(),"M'enfin???"); + n.setUserData(userData); + System.out.println("Sending notification: "+userData); + sendNotification(n); + } + + private static synchronized long nextseq() {return ++seqnb;} + private static volatile long seqnb=0; + } + + private static final String NS = JMXNamespaces.NAMESPACE_SEPARATOR; + private static final String CS = "jmx.rmi:type=JMXConnectorServer"; + private static final String BD = "longtar:type=Longtar"; + + private static void createNamespace(MBeanServerConnection server, + String namespace, Subject creator, boolean forwarding) + throws Exception { + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final Map smap = new HashMap(); + smap.put(JMXConnectorServer.AUTHENTICATOR, + new SubjectAuthenticator(new Subject[] {creator})); + final JMXConnectorServer rmi = + JMXConnectorServerFactory.newJMXConnectorServer(url,smap,null); + final ObjectName name = new ObjectName(CS); + sub.registerMBean(rmi,name); + rmi.start(); + final Map cmap = new HashMap(); + cmap.put(JMXConnector.CREDENTIALS,creator); + final Map options = new HashMap(cmap); + options.put(JMXRemoteTargetNamespace.CREATE_EVENT_CLIENT,"true"); + JMXRemoteTargetNamespace.createNamespace(server, + namespace, + rmi.getAddress(), + options + ); + server.invoke(JMXNamespaces.getNamespaceObjectName(namespace), + "connect", null,null); + } + private static void closeNamespace(MBeanServerConnection server, + String namespace) { + try { + final ObjectName hname = + JMXNamespaces.getNamespaceObjectName(namespace); + if (!server.isRegistered(hname)) + return; + final ObjectName sname = + new ObjectName(namespace+NS+CS); + if (!server.isRegistered(sname)) + return; + final JMXConnectorServerMBean cs = + JMX.newMBeanProxy(server,sname, + JMXConnectorServerMBean.class,true); + try { + cs.stop(); + } finally { + server.unregisterMBean(hname); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private static Subject newSubject(String[] principals) { + final Set ps = new HashSet(); + for (String p:principals) ps.add(new JMXPrincipal(p)); + return new Subject(true,ps,Collections.emptySet(),Collections.emptySet()); + } + + + public static void testSubject() throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + final String a = "a"; + final String b = a + NS + "b"; + + final Subject s1 = newSubject(new String[] {"chichille"}); + final Subject s2 = newSubject(new String[] {"alambic"}); + final Subject s3 = newSubject(new String[] {"virgule"}); + final Subject s4 = newSubject(new String[] {"funeste"}); + + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final Map smap = new HashMap(); + smap.put(JMXConnectorServer.AUTHENTICATOR, + new SubjectAuthenticator(new Subject[] {s1})); + final JMXConnectorServer rmi = + JMXConnectorServerFactory.newJMXConnectorServer(url,smap,null); + final ObjectName name = new ObjectName(CS); + server.registerMBean(rmi,name); + rmi.start(); + + try { + + final Map map = new HashMap(); + map.put(JMXConnector.CREDENTIALS,s1); + final JMXConnector c = + JMXConnectorFactory.connect(rmi.getAddress(),map); + final MBeanServerConnection mbsorig = c.getMBeanServerConnection(); + + final MBeanServerConnection mbs = + EventClientConnection.getEventConnectionFor(mbsorig,null); + + createNamespace(mbs,a,s2,true); + createNamespace(mbs,b,s3,true); + + final ObjectName longtar = new ObjectName(b+NS+BD); + + mbs.createMBean(Longtar.class.getName(),longtar); + final LongtarMBean proxy = + JMX.newMBeanProxy(mbs,longtar,LongtarMBean.class,true); + + + final BlockingQueue bbq = + new ArrayBlockingQueue(10); + final NotificationListener listener1 = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + System.out.println(notification.getSequenceNumber()+": "+ + notification.getMessage()); + bbq.add(notification); + } + }; + final NotificationListener listener2 = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + System.out.println(notification.getSequenceNumber()+": "+ + notification.getMessage()); + bbq.add(notification); + } + }; + + final NotificationEmitter ubpdalfdla = (NotificationEmitter)proxy; + try { + + // Add 1 NL, send 1 notif (1) + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(1)); + // Thread.sleep(180000); + + // We should have 1 notif with userdata = 1 + final Notification n1 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n1.getUserData()).intValue() != 1) + throw new Exception("Expected 1, got"+n1.getUserData()); + + // remove NL, send 1 notif (2) => we shouldn't receive it + ubpdalfdla.removeNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(2)); + + // add NL, send 1 notif (3) + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(3)); + + // we should receive only 1 notif (3) + final Notification n3 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n3.getUserData()).intValue() != 3) + throw new Exception("Expected 3, got"+n3.getUserData()); + + // remove NL, send 1 notif (4) => we shouldn't receive it. + ubpdalfdla.removeNotificationListener(listener1); + proxy.sendNotification(new Integer(4)); + + // add NL, send 1 notif (5). + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(5)); + + // next notif in queue should be (5) + final Notification n5 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n5.getUserData()).intValue() != 5) + throw new Exception("Expected 5, got"+n5.getUserData()); + + // add 2 NL, send 1 notif (6) + ubpdalfdla.addNotificationListener(listener2,null,listener2); + ubpdalfdla.addNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(6)); + + // We have 3 NL, we should receive (6) 3 times.... + final Notification n61 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n61.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#1), got"+n61.getUserData()); + final Notification n62 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n62.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#2), got"+n62.getUserData()); + final Notification n63 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n63.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#3), got"+n63.getUserData()); + + // Remove 1 NL, send 1 notif (7) + ubpdalfdla.removeNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(7)); + + // next notifs in queue should be (7), twice... + final Notification n71 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n71.getUserData()).intValue() != 7) + throw new Exception("Expected 7 (#1), got"+n71.getUserData()); + final Notification n72 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n72.getUserData()).intValue() != 7) + throw new Exception("Expected 7 (#2), got"+n72.getUserData()); + + // Add 1 NL, send 1 notif (8) + ubpdalfdla.addNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(8)); + + // Next notifs in queue should be (8), 3 times. + final Notification n81 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n81.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#1), got"+n81.getUserData()); + final Notification n82 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n82.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#2), got"+n82.getUserData()); + final Notification n83 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n83.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#3), got"+n83.getUserData()); + + // Remove 2 NL, send 1 notif (9) + ubpdalfdla.removeNotificationListener(listener2); + proxy.sendNotification(new Integer(9)); + + // Next notifs in queue should be (9), 1 time only. + final Notification n9 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n9.getUserData()).intValue() != 9) + throw new Exception("Expected 9, got"+n9.getUserData()); + + // send 1 notif (10) + proxy.sendNotification(new Integer(10)); + + // Next notifs in queue should be (10), 1 time only. + final Notification n10 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n10.getUserData()).intValue() != 10) + throw new Exception("Expected 10, got"+n10.getUserData()); + + ubpdalfdla.removeNotificationListener(listener1); + mbs.unregisterMBean(longtar); + + } finally { + c.close(); + } + } finally { + closeNamespace(server,b); + closeNamespace(server,a); + rmi.stop(); + } + + } + + public static void main(String[] args) throws Exception { + testSubject(); + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/RoutingServerProxyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/RoutingServerProxyTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,399 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test RoutingServerProxyTest.java 1.6 + * @summary General RoutingServerProxyTest test. + * @author Daniel Fuchs + * @run clean RoutingServerProxyTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true RoutingServerProxyTest.java + * @run build RoutingServerProxyTest Wombat WombatMBean + * @run main RoutingServerProxyTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.StandardEmitterMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; + +/** + * Class RoutingServerProxyTest + * + * @author Sun Microsystems, Inc. + */ +public class RoutingServerProxyTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(RoutingServerProxyTest.class.getName()); + + /** + * Creates a new instance of RoutingServerProxyTest + */ + public RoutingServerProxyTest() { + } + + public static class DynamicWombat extends StandardEmitterMBean { + DynamicWombat(Wombat w) throws NotCompliantMBeanException { + super(w,WombatMBean.class,w); + } + + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + final ObjectName myname = ((Wombat)getImplementation()). + preRegister(server,name); + return super.preRegister(server,myname); + } + + @Override + public void postRegister(Boolean registrationDone) { + try { + ((Wombat)getImplementation()). + postRegister(registrationDone); + } finally { + super.postRegister(registrationDone); + } + } + + @Override + public void preDeregister() throws Exception { + ((Wombat)getImplementation()). + preDeregister(); + super.preDeregister(); + + } + + @Override + public void postDeregister() { + try { + ((Wombat)getImplementation()). + postDeregister(); + } finally { + super.postDeregister(); + } + } + } + + public static class VirtualWombatHandler + extends JMXNamespace { + + public static class VirtualWombatRepository + extends MBeanServerSupport { + + final Map bush; + + VirtualWombatRepository(Map bush) { + this.bush = bush; + } + + @Override + protected Set getNames() { + return bush.keySet(); + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mb = bush.get(name); + if (mb == null) { + throw new InstanceNotFoundException(String.valueOf(name)); + } + return mb; + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) { + return (NotificationEmitter) mbean; + } + return null; + } + } + VirtualWombatRepository bush; + + VirtualWombatHandler(Map bush) { + this(new VirtualWombatRepository(Collections.synchronizedMap(bush))); + } + + private VirtualWombatHandler(VirtualWombatRepository repository) { + super(repository); + bush = repository; + } + + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + final ObjectName myname = super.preRegister(server, name); + return myname; + } + + @Override + public void postRegister(Boolean registrationDone) { + if (!registrationDone.booleanValue()) { + return; + } + final MBeanServer me = JMXNamespaces.narrowToNamespace(getMBeanServer(), + getObjectName().getDomain()); + for (Map.Entry e : bush.bush.entrySet()) { + final DynamicMBean obj = e.getValue(); + try { + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).preRegister(me, e.getKey()); + } + } catch (Exception x) { + System.err.println("preRegister failed for " + + e.getKey() + ": " + x); + bush.bush.remove(e.getKey()); + } + } + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).postRegister(registrationDone); + } + } + } + + @Override + public void preDeregister() throws Exception { + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).preDeregister(); + } + } + } + + @Override + public void postDeregister() { + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).postDeregister(); + } + } + } + } + + public static ObjectName getWombatName(String name) + throws MalformedObjectNameException { + return ObjectName.getInstance("australian.bush:type=Wombat,name="+name); + } + + public static ObjectName addDir(String dir, ObjectName name) + throws MalformedObjectNameException { + return name.withDomain( + dir+JMXNamespaces.NAMESPACE_SEPARATOR+ name.getDomain()); + } + + public static void simpleTest() + throws JMException, IOException { + final MBeanServer master = MBeanServerFactory.createMBeanServer(); + final MBeanServer agent1 = MBeanServerFactory.createMBeanServer(); + final Wombat w1 = new Wombat(); + final Wombat w2 = new Wombat(); + final Wombat w3 = new Wombat(); + final Map wombats = + new ConcurrentHashMap(); + wombats.put(getWombatName("LittleWombat"), + new DynamicWombat(w2)); + wombats.put(getWombatName("BigWombat"), + new DynamicWombat(w3)); + final Wombat w4 = new Wombat(); + final Wombat w5 = new Wombat(); + + final JMXNamespace agent2 = + new VirtualWombatHandler(wombats); + agent1.registerMBean(w4,getWombatName("LittleWombat")); + master.registerMBean(w1,getWombatName("LittleWombat")); + master.registerMBean(new JMXNamespace(agent1), + JMXNamespaces.getNamespaceObjectName("south.east")); + master.registerMBean(agent2, + JMXNamespaces.getNamespaceObjectName("north")); + master.registerMBean(w5,addDir("south.east", + getWombatName("GrandWombat"))); + + MBeanServer se = null; + + try { + se = JMXNamespaces.narrowToNamespace(master,"south.easht"); + } catch (Exception x) { + System.out.println("Caught expected exception: "+x); + } + if (se != null) + throw new RuntimeException("Expected exception for "+ + "cd(south.easht)"); + se = JMXNamespaces.narrowToNamespace(master,"south.east"); + + MBeanServer nth = JMXNamespaces.narrowToNamespace(master,"north"); + + final ObjectName ln = getWombatName("LittleWombat"); + MBeanInfo mb1 = master.getMBeanInfo(ln); + MBeanInfo mb2 = se.getMBeanInfo(ln); + MBeanInfo mb3 = nth.getMBeanInfo(ln); + + final WombatMBean grand = JMX.newMBeanProxy(se, + getWombatName("GrandWombat"),WombatMBean.class); + final WombatMBean big = JMX.newMBeanProxy(nth, + getWombatName("BigWombat"),WombatMBean.class); + grand.getCaption(); + big.getCaption(); + grand.setCaption("I am GrandWombat"); + big.setCaption("I am BigWombat"); + + final WombatMBean grand2 = + JMX.newMBeanProxy(master,addDir("south.east", + getWombatName("GrandWombat")),WombatMBean.class); + final WombatMBean big2 = + JMX.newMBeanProxy(master,addDir("north", + getWombatName("BigWombat")),WombatMBean.class); + if (!"I am GrandWombat".equals(grand2.getCaption())) + throw new RuntimeException("bad caption for GrandWombat"+ + grand2.getCaption()); + if (!"I am BigWombat".equals(big2.getCaption())) + throw new RuntimeException("bad caption for BigWombat"+ + big2.getCaption()); + + + final Set northWombats = + nth.queryMBeans(ObjectName.WILDCARD,null); + final Set seWombats = + se.queryMBeans(ObjectName.WILDCARD,null); + if (!northWombats.equals( + agent2.getSourceServer().queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in northern territory: got " + +northWombats+", expected "+ + agent2.getSourceServer(). + queryMBeans(ObjectName.WILDCARD,null)); + } + if (!seWombats.equals( + agent1.queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in south east: got " + +seWombats+", expected "+ + agent1. + queryMBeans(ObjectName.WILDCARD,null)); + } + + final MBeanServer supermaster = MBeanServerFactory.createMBeanServer(); + supermaster.registerMBean(new JMXNamespace(master), + JMXNamespaces.getNamespaceObjectName("australia")); + final MBeanServer proxymaster = + JMXNamespaces.narrowToNamespace(supermaster,"australia"); + final MBeanServer sem = + JMXNamespaces.narrowToNamespace(proxymaster,"south.east"); + final MBeanServer nthm = + JMXNamespaces.narrowToNamespace(proxymaster,"north"); + final Set northWombats2 = + nthm.queryMBeans(ObjectName.WILDCARD,null); + final Set seWombats2 = + sem.queryMBeans(ObjectName.WILDCARD,null); + if (!northWombats2.equals( + agent2.getSourceServer().queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in " + + "Australia // North"); + } + if (!seWombats2.equals( + agent1.queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in " + + "Australia // South East"); + } + final WombatMBean grand3 = + JMX.newMBeanProxy(supermaster, + addDir("australia//south.east", + getWombatName("GrandWombat")),WombatMBean.class); + final WombatMBean big3 = + JMX.newMBeanProxy(supermaster,addDir("australia//north", + getWombatName("BigWombat")),WombatMBean.class); + if (!"I am GrandWombat".equals(grand3.getCaption())) + throw new RuntimeException("bad caption for " + + "australia//south.east//GrandWombat"+ + grand3.getCaption()); + if (!"I am BigWombat".equals(big3.getCaption())) + throw new RuntimeException("bad caption for " + + "australia//north//BigWombat"+ + big3.getCaption()); + final WombatMBean grand4 = + JMX.newMBeanProxy(sem, + getWombatName("GrandWombat"),WombatMBean.class); + final WombatMBean big4 = + JMX.newMBeanProxy(nthm, + getWombatName("BigWombat"),WombatMBean.class); + if (!"I am GrandWombat".equals(grand4.getCaption())) + throw new RuntimeException("bad caption for " + + "[australia//south.east//] GrandWombat"+ + grand4.getCaption()); + if (!"I am BigWombat".equals(big4.getCaption())) + throw new RuntimeException("bad caption for " + + "[australia//north//] BigWombat"+ + big4.getCaption()); + + if (!(nthm instanceof RoutingServerProxy)) + throw new AssertionError("expected RoutingServerProxy for nthm"); + if (!(sem instanceof RoutingServerProxy)) + throw new AssertionError("expected RoutingServerProxy for sem"); + + if (!"australia//north".equals(( + (RoutingServerProxy)nthm).getSourceNamespace())) + throw new RuntimeException("north territory should be in australia"); + if (!"australia//south.east".equals(( + (RoutingServerProxy)sem).getSourceNamespace())) + throw new RuntimeException("south east territory should be in australia"); + + } + + public static void main(String[] args) { + try { + simpleTest(); + } catch (Exception x) { + System.err.println("SimpleTest failed: "+x); + throw new RuntimeException(x); + } + } + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/SerialParamProcessorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/SerialParamProcessorTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,571 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test SerialParamProcessorTest.java 1.8 + * @summary General SerialParamProcessorTest test. + * @author Daniel Fuchs + * @run clean SerialParamProcessorTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true SerialParamProcessorTest.java + * @run build SerialParamProcessorTest Wombat WombatMBean + * @run main SerialParamProcessorTest + */ + +import com.sun.jmx.namespace.serial.RewritingProcessor; +import java.beans.ConstructorProperties; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.management.AttributeChangeNotification; +import javax.management.AttributeList; +import javax.management.JMException; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +/** + * Class SerialParamProcessorTest + * + * @author Sun Microsystems, Inc. + */ +public class SerialParamProcessorTest { + + /** + * Creates a new instance of SerialParamProcessorTest + */ + public SerialParamProcessorTest() { + } + + public static class MyCompositeData implements Serializable { + private static final long serialVersionUID = 3186492415099133506L; + public MyCompositeData(ObjectName foobar,ObjectName absolute, + long count, String name) { + this(foobar,absolute,count,name,new ObjectName[]{foobar,absolute}); + } + @ConstructorProperties(value={"fooBar","absolute","count","name", + "allNames"}) + public MyCompositeData(ObjectName foobar,ObjectName absolute, + long count, String name, ObjectName[] allnames) { + this.foobar = foobar; + this.absolute = absolute; + this.count = count; + this.name = name; + this.allnames = allnames; + } + ObjectName foobar,absolute,allnames[]; + long count; + String name; + public ObjectName getFooBar() { + return foobar; + } + public ObjectName getAbsolute() { + return absolute; + } + public ObjectName[] getAllNames() { + return allnames; + } + public long getCount() { + return count; + } + public String getName() { + return name; + } + private Object[] toArray() { + final Object[] props = { + getName(),getFooBar(),getAbsolute(),getAllNames(),getCount() + }; + return props; + } + @Override + public boolean equals(Object o) { + if (o instanceof MyCompositeData) + return Arrays.deepEquals(toArray(), + ((MyCompositeData)o).toArray()); + return false; + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + } + + public static interface MyMXBean { + public Map getAll(); + public MyCompositeData lookup(String name); + public void put(String name, MyCompositeData data); + public MyCompositeData remove(String name); + } + + public static class My implements MyMXBean { + Map datas = + new HashMap(); + public Map getAll() { + return datas; + } + public MyCompositeData lookup(String name) { + return datas.get(name); + } + public void put(String name, MyCompositeData data) { + datas.put(name,data); + } + public MyCompositeData remove(String name) { + return datas.remove(name); + } + } + + public static class BandicootClass implements Serializable { + private static final long serialVersionUID = -5494055748633966355L; + public final Object gloups; + public BandicootClass(Object gloups) { + this.gloups = gloups; + } + private Object[] toArray() { + final Object[] one = {gloups}; + return one; + } + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BandicootClass)) return false; + final Object[] one = {gloups}; + return Arrays.deepEquals(toArray(),((BandicootClass)obj).toArray()); + } + @Override + public int hashCode() { + if (gloups == null) return 0; + return Arrays.deepHashCode(toArray()); + } + } + + // Need this to override equals. + public static class BandicootNotification extends Notification { + private static final long serialVersionUID = 664758643764049001L; + public BandicootNotification(String type, Object source, long seq) { + super(type,source,seq,0L,""); + } + private Object[] toArray() { + final Object[] vals = {getMessage(),getSequenceNumber(), + getSource(),getTimeStamp(),getType(),getUserData()}; + return vals; + } + @Override + public boolean equals(Object o) { + if (!(o instanceof BandicootNotification)) return false; + return Arrays.deepEquals(toArray(), + ((BandicootNotification)o).toArray()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + + } + + // Need this to override equals. + public static class BandicootAttributeChangeNotification + extends AttributeChangeNotification { + private static final long serialVersionUID = -1392435607144396125L; + public BandicootAttributeChangeNotification(Object source, + long seq, long time, String msg, String name, String type, + Object oldv, Object newv) { + super(source,seq,time,msg,name,type,oldv,newv); + } + private Object[] toArray() { + final Object[] vals = {getMessage(),getSequenceNumber(), + getSource(),getTimeStamp(),getType(),getUserData(), + getAttributeName(), getAttributeType(),getNewValue(), + getOldValue()}; + return vals; + } + @Override + public boolean equals(Object o) { + if (!(o instanceof BandicootAttributeChangeNotification)) + return false; + return Arrays.deepEquals(toArray(), + ((BandicootAttributeChangeNotification)o).toArray()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append(this.getClass().getName()).append(": "); + b.append("[type=").append(getType()).append("]"); + b.append("[source=").append(getSource()).append("]"); + b.append("[message=").append(getMessage()).append("]"); + b.append("[sequence=").append(getSequenceNumber()).append("]"); + + b.append("[attribute=").append(getAttributeName()).append("]"); + b.append("[class=").append(getAttributeType()).append("]"); + b.append("[oldvalue=").append(getOldValue()).append("]"); + b.append("[newvalue=").append(getNewValue()).append("]"); + + b.append("[time=").append(getTimeStamp()).append("]"); + b.append("[data=").append(getUserData()).append("]"); + return b.toString(); + } + } + + private static void addToList(Object[] foos, List foolist) { + final ArrayList fal = new ArrayList(foos.length); + for (Object f : foos) { + if (f.getClass().isArray()) { + foolist.add(new BandicootClass(f)); + fal.add(new BandicootClass(f)); + } else { + foolist.add(f); + fal.add(f); + } + } + foolist.add(new BandicootClass(foos)); + foolist.add(fal); + } + + public static void testSerial(String msg, Object foo, Object bar, + RewritingProcessor procForFoo, + RewritingProcessor procForBar, List foolist, + List barlist, boolean recurse) { + System.err.println(msg+" Testing serial - "+foo.getClass().getName()); + final Object bar1 = procForFoo.rewriteInput(foo); + final Object foo1 = procForFoo.rewriteOutput(bar); + final Object bar2 = procForFoo.rewriteInput(foo1); + final Object foo2 = procForFoo.rewriteOutput(bar1); + + final Object bar3 = procForBar.rewriteOutput(foo); + final Object foo3 = procForBar.rewriteInput(bar); + final Object bar4 = procForBar.rewriteOutput(foo3); + final Object foo4 = procForBar.rewriteInput(bar3); + + final Object bar5 = procForFoo.rewriteInput(foo3); + final Object foo5 = procForFoo.rewriteOutput(bar3); + + final Object bar6 = procForBar.rewriteOutput(foo1); + final Object foo6 = procForBar.rewriteInput(bar1); + + final Object[] foos = {foo, foo1, foo2, foo3, foo4, foo5, foo6}; + final Object[] bars = {bar, bar1, bar2, bar3, bar4, bar5, bar6}; + + final Object[] foot = { foo }; + final Object[] bart = { bar }; + for (int j=1;j foolist = new LinkedList(); + final List barlist = new LinkedList(); + for (Object[] row : objects) { + i++; + Object foo = row[0]; + Object bar = row[1]; + String msg1 = "[" +foo.getClass().getName() + "] step " + + i +": "; + + testSerial(msg1,foo,bar,procForFoo,procForBar,foolist,barlist,true); + + final BandicootClass kfoo = new BandicootClass(foo); + final BandicootClass kbar = new BandicootClass(bar); + + String msg2 = "[" +kfoo.getClass().getName() + "] step " + + i +": "; + testSerial(msg2,kfoo,kbar,procForFoo,procForBar,foolist,barlist,true); + } + String msg31 = "foo[] and bar[]: "; + testSerial(msg31,foolist.toArray(),barlist.toArray(), + procForFoo,procForBar,foolist,barlist,false); + + String msg3 = "foolist and barlist: "; + testSerial(msg3,new LinkedList(foolist), + new LinkedList(barlist), + procForFoo,procForBar,foolist,barlist,false); + + final BandicootClass kfoolist = new BandicootClass(foolist); + final BandicootClass kbarlist = new BandicootClass(barlist); + String msg4 = "kfoolist and kbarlist: "; + testSerial(msg4,kfoolist,kbarlist,procForFoo,procForBar,foolist,barlist,false); + } + + /** + * The idea of this method is to convert {@code foo} things into + * {@code bar} things... + * @param foo the string to replace. + * @param bar the replacement for {@code foo} + * ({@code foo} becomes {@code bar}). + * @param sfoo a string that may contain {@code foo}, that will be embedded + * in non-replaceable parts of the domain in order to attempt to + * trick the replacement logic. + * @param sbar a string that may contain {@code bar}, that will be embedded + * in non-replaceable parts of the domain in order to attempt to + * trick the replacement logic. + **/ + public static void doSerialTest(String foo, String bar, String sfoo, + String sbar) { + try { + final RewritingProcessor procForFoo = RewritingProcessor. + newRewritingProcessor(foo,bar); + final RewritingProcessor procForBar =RewritingProcessor. + newRewritingProcessor(bar,foo); + final String foop = (foo.isEmpty())?foo:foo+"//"; + final String pfoo = (foo.isEmpty())?foo:"//"+foo; + final String barp = (bar.isEmpty())?bar:bar+"//"; + final String pbar = (bar.isEmpty())?bar:"//"+bar; + final String sfoop = (sfoo.isEmpty())?sfoo:sfoo+"//"; + final String psfoo = (sfoo.isEmpty())?sfoo:"//"+sfoo; + final String sbarp = (sbar.isEmpty())?sbar:sbar+"//"; + final String psbar = (sbar.isEmpty())?sbar:"//"+sbar; + + // A trick to avoid writing Open Data by hand... + final My tricks = new My(); + + // A treat to automagically convert trick things into Open Data. + final StandardMBean treats = + new StandardMBean(tricks,MyMXBean.class,true); + + // datas[i][0] is expected to be transformed in datas[i][1] + // + final MyCompositeData[][] datas = { + { // this foo thing: + new MyCompositeData(new ObjectName(foop+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"),1,sfoop+sbarp+"foobar"), + // should be transformed into this bar thing: + new MyCompositeData(new ObjectName(barp+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"),1,sfoop+sbarp+"foobar"), + }, + { // this foo thing: + new MyCompositeData(new ObjectName(foop+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z"),1,sfoop+sbarp+"barfoo"), + // should be transformed into this bar thing: + new MyCompositeData(new ObjectName(barp+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z"),1,sfoop+sbarp+"barfoo"), + } + }; + + // objects[i][0] is expected to be transformed into objects[i][1] + // + final Object[][] objects = new Object[][] { + {new Long(1), new Long(1)}, + { + new ObjectName(foop+sbarp+"x:y=z"), + new ObjectName(barp+sbarp+"x:y=z") + }, + { + new ObjectName(foop+sfoop+"x:y=z"), + new ObjectName(barp+sfoop+"x:y=z") + }, + { + new ObjectName("//"+foop+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"), + }, + { + new ObjectName("//"+foop+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z") + }, + { + foop+sbarp+"x:y=z",foop+sbarp+"x:y=z" + }, + { + foop+sfoop+"x:y=z",foop+sfoop+"x:y=z" + }, + { + barp+sbarp+"x:y=z",barp+sbarp+"x:y=z" + }, + { + barp+sfoop+"x:y=z",barp+sfoop+"x:y=z" + }, + { + new BandicootNotification("test",new ObjectName(foop+sfoop+"x:y=z"),1L), + new BandicootNotification("test",new ObjectName(barp+sfoop+"x:y=z"),1L), + }, + { + new BandicootNotification("test",new ObjectName("//"+foop+sfoop+"x:y=z"),2L), + new BandicootNotification("test",new ObjectName("//"+foop+sfoop+"x:y=z"),2L), + }, + { + new BandicootAttributeChangeNotification( + new ObjectName(foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName(foop+sfoop+"x:y=old"), + new ObjectName(foop+sfoop+"x:y=new")), + new BandicootAttributeChangeNotification( + new ObjectName(barp+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName(barp+sfoop+"x:y=old"), + new ObjectName(barp+sfoop+"x:y=new")), + }, + { + new BandicootAttributeChangeNotification( + new ObjectName("//"+foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName("//"+foop+sfoop+"x:y=old"), + new ObjectName(foop+sfoop+"x:y=new")), + new BandicootAttributeChangeNotification( + new ObjectName("//"+foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName("//"+foop+sfoop+"x:y=old"), + new ObjectName(barp+sfoop+"x:y=new")), + } + }; + + // List that will merge datas & objects & datas converted to open + // types... + // + final List list = new ArrayList(); + + // Add all objects... + // + list.addAll(Arrays.asList(objects)); + + // Build Map with datas[i][0] (cfoo) + // + for (int i=0;i to TabularData + // (foo things) + final Object cfoo = treats.getAttribute("All"); + final AttributeList afoo = treats.getAttributes(new String[] {"All"}); + + // Build Map with datas[i][1] (cbar) + // + for (int i=0;i to TabularData + // (bar things) + final Object cbar = treats.getAttribute("All"); + final AttributeList abar = treats.getAttributes(new String[] {"All"}); + + // Add all datas to list + for (int i=0;i unmapped = new HashSet(); + final static Set mapped = new HashSet(); + + /** + * For each method define in one of the interfaces intf, tries + * to find a corresponding method in the reference class ref, where + * the method in ref has the same name, and takes an additional + * ObjectName as first parameter. + * + * So for instance, if ref is MBeanServer and intf is {DynamicMBean} + * the result map is: + * DynamicMBean.getAttribute -> MBeanServer.getAttribute + * DynamicMBean.setAttribute -> MBeanServer.setAttribute + * etc... + * If a method was mapped, it is additionally added to 'mapped' + * If a method couldn't be mapped, it is added to 'unmmapped'. + * In our example above, DynamicMBean.getNotificationInfo will end + * up in 'unmapped'. + * + * @param ref The reference class - to which calls will be forwarded + * with an additional ObjectName parameter inserted. + * @param intf The proxy interface classes - for which we must find an + * equivalent in 'ref' + * @return A map mapping the methods from intfs to the method of ref. + */ + static Map makeMapFor(Class ref, Class... intf) { + final Map map = new HashMap(); + for (Class clazz : intf) { + for (Method m : clazz.getMethods()) { + try { + final Method m2 = + ref.getMethod(m.getName(), + concat(ObjectName.class,m.getParameterTypes())); + map.put(m,m2); + mapped.add(m); + } catch (Exception x) { + unmapped.add(m); + } + } + } + return map; + } + + /** + * Tries to map all methods from DynamicMBean.class and + * NotificationEmitter.class to their equivalent in MBeanServer. + * This should be all the methods except + * DynamicMBean.getNotificationInfo. + */ + static final Map mbeanmap = + makeMapFor(MBeanServer.class,DynamicMBean.class, + NotificationEmitter.class); + /** + * Tries to map all methods from DynamicMBean.class and + * NotificationEmitter.class to an equivalent in DynamicWrapper. + * This time only DynamicMBean.getNotificationInfo will be mapped. + */ + static final Map selfmap = + makeMapFor(DynamicWrapper.class,DynamicMBean.class, + NotificationEmitter.class); + + /** + * Now check that we have mapped all methods. + */ + static { + unmapped.removeAll(mapped); + if (unmapped.size() > 0) + throw new ExceptionInInitializerError("Couldn't map "+ unmapped); + } + + /** + * The wrapped MBeanServer to which everything is delegated. + */ + private final MBeanServer server; + + /** + * The name of the MBean we're proxying. + */ + private final ObjectName name; + DynamicWrapper(MBeanServer server, ObjectName name) { + this.server=server; + this.name=name; + } + + /** + * Creates a new proxy for the given MBean. Implements + * NotificationEmitter/NotificationBroadcaster if the proxied + * MBean also does. + * @param name the name of the proxied MBean + * @param server the wrapped server + * @return a DynamicMBean proxy + * @throws javax.management.InstanceNotFoundException + */ + public static DynamicMBean newProxy(ObjectName name, MBeanServer server) + throws InstanceNotFoundException { + if (server.isInstanceOf(name, + NotificationEmitter.class.getName())) { + // implements NotificationEmitter + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {NotificationEmitter.class, + DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + if (server.isInstanceOf(name, + NotificationBroadcaster.class.getName())) { + // implements NotificationBroadcaster + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {NotificationBroadcaster.class, + DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + // Only implements DynamicMBean. + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + // Look for a method on this class (takes precedence) + final Method self = selfmap.get(method); + if (self != null) + return call(this,self,concat(name,args)); + + // no method found on this class, look for the same method + // on the wrapped MBeanServer + final Method mbean = mbeanmap.get(method); + if (mbean != null) + return call(server,mbean,concat(name,args)); + + // This isn't a method that can be forwarded to MBeanServer. + // If it's a method from Object, call it on this. + if (method.getDeclaringClass().equals(Object.class)) + return call(this,method,args); + throw new NoSuchMethodException(method.getName()); + } + + // Call a method using reflection, unwraps invocation target exceptions + public Object call(Object handle, Method m, Object[] args) + throws Throwable { + try { + return m.invoke(handle, args); + } catch (InvocationTargetException x) { + throw x.getCause(); + } + } + + // this method is called when DynamicMBean.getNotificationInfo() is + // called. This is the method that should be mapped in + // 'selfmap' + public MBeanNotificationInfo[] getNotificationInfo(ObjectName name) + throws JMException { + return server.getMBeanInfo(name).getNotifications(); + } + } + + /** + * Just so that we can call the same test twice but with two + * different implementations of VirtualMBeanServerSupport. + */ + public static interface MBeanServerWrapperFactory { + public MBeanServer wrapMBeanServer(MBeanServer wrapped); + } + + /** + * A VirtualMBeanServerSupport that wrapps an MBeanServer and does not + * use VirtualEventManager. + */ + public static class VirtualMBeanServerTest + extends MBeanServerSupport { + + final MBeanServer wrapped; + + public VirtualMBeanServerTest(MBeanServer wrapped) { + this.wrapped=wrapped; + } + + @Override + public DynamicMBean getDynamicMBeanFor(final ObjectName name) + throws InstanceNotFoundException { + if (wrapped.isRegistered(name)) + return DynamicWrapper.newProxy(name,wrapped); + throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + return wrapped.queryNames(null, null); + } + + public final static MBeanServerWrapperFactory factory = + new MBeanServerWrapperFactory() { + + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return new VirtualMBeanServerTest(wrapped); + } + @Override + public String toString() { + return VirtualMBeanServerTest.class.getName(); + } + }; + } + + /** + * A VirtualMBeanServerSupport that wrapps an MBeanServer and + * uses a VirtualEventManager. + */ + public static class VirtualMBeanServerTest2 + extends VirtualMBeanServerTest { + + final EventSubscriber sub; + final NotificationListener nl; + final VirtualEventManager mgr; + + /** + * We use an EventSubscriber to subscribe for all notifications from + * the wrapped MBeanServer, and publish them through a + * VirtualEventManager. Not a very efficient way of doing things. + * @param wrapped + */ + public VirtualMBeanServerTest2(MBeanServer wrapped) { + super(wrapped); + this.sub = EventSubscriber.getEventSubscriber(wrapped); + this.mgr = new VirtualEventManager(); + this.nl = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + mgr.publish((ObjectName)notification.getSource(), notification); + } + }; + try { + sub.subscribe(ObjectName.WILDCARD, nl, null, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new IllegalStateException("can't subscribe for notifications!"); + } + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return mgr.getNotificationEmitterFor(name); + return null; + } + + public final static MBeanServerWrapperFactory factory = + new MBeanServerWrapperFactory() { + + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return new VirtualMBeanServerTest2(wrapped); + } + @Override + public String toString() { + return VirtualMBeanServerTest2.class.getName(); + } + }; + } + + + public static void test(MBeanServerWrapperFactory factory) throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + // names[] are NotificationEmitters + final ObjectName[] emitters = new ObjectName[2]; + // shields[] have been shielded by wrapping them in a StandardMBean, + // so although the resource is an MBean that implements + // NotificationEmitter, the registered MBean (the wrapper) doesn't. + final ObjectName[] shielded = new ObjectName[2]; + + final List registered = new ArrayList(4); + + try { + // register two MBeans before wrapping + server.registerMBean(new Wombat(), + emitters[0] = new ObjectName("bush:type=Wombat,name=wom")); + registered.add(emitters[0]); + + // we shield the second MBean in a StandardMBean so that it does + // not appear as a NotificationEmitter. + server.registerMBean( + new StandardMBean(new Wombat(), WombatMBean.class), + shielded[0] = new ObjectName("bush:type=Wombat,name=womshield")); + registered.add(shielded[0]); + + final MBeanServer vserver = factory.wrapMBeanServer(server); + + // register two other MBeans after wrapping + server.registerMBean(new Wombat(), + emitters[1] = new ObjectName("bush:type=Wombat,name=bat")); + registered.add(emitters[1]); + + // we shield the second MBean in a StandardMBean so that it does + // not appear as a NotificationEmitter. + server.registerMBean( + new StandardMBean(new Wombat(), WombatMBean.class), + shielded[1] = new ObjectName("bush:type=Wombat,name=batshield")); + registered.add(shielded[1]); + + // Call test with this config - we have two wombats who broadcast + // notifs (emitters) and two wombats who don't (shielded). + test(vserver, emitters, shielded); + + System.out.println("*** Test passed for: " + factory); + } finally { + // Clean up the platform mbean server for the next test... + for (ObjectName n : registered) { + try { + server.unregisterMBean(n); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + } + + /** + * Perform the actual test. + * @param vserver A virtual MBeanServerSupport implementation + * @param emitters Names of NotificationBroadcaster MBeans + * @param shielded Names of non NotificationBroadcaster MBeans + * @throws java.lang.Exception + */ + public static void test(MBeanServer vserver, ObjectName[] emitters, + ObjectName[] shielded) throws Exception { + + // To catch exception in NotificationListener + final List fail = new CopyOnWriteArrayList(); + + // A queue of received notifications + final BlockingQueue notifs = + new ArrayBlockingQueue(50); + + // A notification listener that puts the notification it receives + // in the queue. + final NotificationListener handler = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + notifs.put(notification); + } catch (Exception x) { + fail.add(x); + } + } + }; + + // A list of attribute names for which we might receive an + // exception. If an exception is received when getting these + // attributes - the test will not fail. + final List exceptions = Arrays.asList( new String[] { + "UsageThresholdCount","UsageThreshold","UsageThresholdExceeded", + "CollectionUsageThresholdCount","CollectionUsageThreshold", + "CollectionUsageThresholdExceeded" + }); + + // This is just a sanity check. Get all attributes of all MBeans. + for (ObjectName n : vserver.queryNames(null, null)) { + final MBeanInfo m = vserver.getMBeanInfo(n); + for (MBeanAttributeInfo mba : m.getAttributes()) { + // System.out.println(n+":"); + Object val; + try { + val = vserver.getAttribute(n, mba.getName()); + } catch (Exception x) { + // only accept exception for those attributes that + // have a valid reason to fail... + if (exceptions.contains(mba.getName())) val = x; + else throw new Exception("Failed to get " + + mba.getName() + " from " + n,x); + } + // System.out.println("\t "+mba.getName()+": "+ val); + } + } + + // The actual tests. Register for notifications with notif emitters + for (ObjectName n : emitters) { + vserver.addNotificationListener(n, handler, null, n); + } + + // Trigger the emission of notifications, check that we received them. + for (ObjectName n : emitters) { + vserver.setAttribute(n, + new Attribute("Caption","I am a new wombat!")); + final Notification notif = notifs.poll(4, TimeUnit.SECONDS); + if (!notif.getSource().equals(n)) + throw new Exception("Bad source for "+ notif); + if (fail.size() > 0) + throw new Exception("Failed to handle notif",fail.remove(0)); + } + + // Check that we didn't get more notifs than expected + if (notifs.size() > 0) + throw new Exception("Extra notifications in queue: "+notifs); + + // Check that if the MBean doesn't exist, we get InstanceNotFound. + try { + vserver.addNotificationListener(new ObjectName("toto:toto=toto"), + handler, null, null); + throw new Exception("toto:toto=toto doesn't throw INFE"); + } catch (InstanceNotFoundException x) { + System.out.println("Received "+x+" as expected."); + } + + // For those MBeans that shouldn't be NotificationEmitters, check that + // we get IllegalArgumentException + for (ObjectName n : shielded) { + try { + vserver.addNotificationListener(n, handler, null, n); + } catch (RuntimeOperationsException x) { + System.out.println("Received "+x+" as expected."); + System.out.println("Cause is: "+x.getCause()); + if (!(x.getCause() instanceof IllegalArgumentException)) + throw new Exception("was expecting IllegalArgumentException cause. Got "+x.getCause(),x); + } + } + + // Sanity check. Remove our listeners. + for (ObjectName n : emitters) { + vserver.removeNotificationListener(n, handler, null, n); + } + + // That's it. + // Sanity check: we shouldn't have received any new notif. + if (notifs.size() > 0) + throw new Exception("Extra notifications in queue: "+notifs); + // The NotifListener shouldn't have logged any new exception. + if (fail.size() > 0) + throw new Exception("Failed to handle notif",fail.remove(0)); + } + + public static void main(String[] args) throws Exception { + // test with a regular MBeanServer (no VirtualMBeanServerSupport) + final MBeanServerWrapperFactory identity = + new MBeanServerWrapperFactory() { + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return wrapped; + } + }; + test(identity); + // test with no EventManager + test(VirtualMBeanServerTest.factory); + // test with VirtualEventManager + test(VirtualMBeanServerTest2.factory); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/VirtualMBeanTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/VirtualMBeanTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,409 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test VirtualMBeanTest.java + * @bug 5108776 + * @summary Test that Virtual MBeans can be implemented and emit notifs. + * @author Eamonn McManus + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; +import javax.management.SendNotification; +import javax.management.StandardEmitterMBean; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.VirtualEventManager; +import javax.management.namespace.MBeanServerSupport; +import javax.management.timer.TimerMBean; + +// In this test, we check that the two main use case types for +// MBeanServerSupport work correctly: +// (1) as a special-purpose implementation of MBeanServer for a fixed number +// of MBeans (e.g. for QueryNotificationFilter) +// (2) as an MBeanServer supporting Virtual MBeans. +// In each case we are particularly interested in the notification behaviour. +// We check that the behaviour is correct when calling addNotificationListener +// (a) for an MBean that does not exist; (b) for an MBean that does exist but +// is not a NotificationEmitter; and (c) for an MBean that exists and is +// a NotificationEmitter. We also check the degenerate and usual case +// where the MBeanServerSupport subclass does not support notifications +// at all. +// +// Each subclass will have an MBean called test:type=NotEmitter that +// does not support addNotificationListener. If it also has MBeans called +// test:type=Emitter,* then they are expected to support addNL. No subclass +// will have any other MBeans, so in particular no subclass will have +// test:type=Nonexistent. +// +public class VirtualMBeanTest { + static final ObjectName + nonExistentName, notEmitterName, emitterName1, emitterName2; + static { + try { + nonExistentName = new ObjectName("test:type=NonExistent"); + notEmitterName = new ObjectName("test:type=NotEmitter"); + emitterName1 = new ObjectName("test:type=Emitter,id=1"); + emitterName2 = new ObjectName("test:type=Emitter,id=2"); + } catch (MalformedObjectNameException e) { + throw new AssertionError(e); + } + } + + static final StandardMBean.Options wrappedVisible = new StandardMBean.Options(); + static { + wrappedVisible.setWrappedObjectVisible(true); + } + + public static interface NothingMBean {} + public static class Nothing implements NothingMBean {} + public static class NothingNBS extends NotificationBroadcasterSupport + implements NothingMBean {} + + // Class that has hardwired MBeans test:type=NotEmitter, + // test:type=Broadcaster, and test:type=Emitter. + private static class HardwiredMBS extends MBeanServerSupport + implements SendNotification { + private final DynamicMBean notEmitter = + new StandardMBean(new Nothing(), NothingMBean.class, wrappedVisible); + private final StandardEmitterMBean emitter1, emitter2; + { + NothingNBS nnbs1 = new NothingNBS(); + emitter1 = new StandardEmitterMBean( + nnbs1, NothingMBean.class, wrappedVisible, nnbs1); + NothingNBS nnbs2 = new NothingNBS(); + emitter2 = new StandardEmitterMBean( + nnbs2, NothingMBean.class, wrappedVisible, nnbs2); + } + + private final Map map = + new TreeMap(); + { + map.put(notEmitterName, notEmitter); + map.put(emitterName1, emitter1); + map.put(emitterName2, emitter2); + } + + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = map.get(name); + if (mbean != null) + return mbean; + else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return map.keySet(); + } + + @Override + public String toString() { + return "Hardwired MBeanServerSupport"; + } + + public void sendNotification(Notification notification) { + emitter1.sendNotification(notification); + emitter2.sendNotification(notification); + } + } + + // Class that has the notEmitter MBean but not either of the others, so does + // not support listeners. + private static class VirtualMBSWithoutListeners + extends MBeanServerSupport { + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (name.equals(notEmitterName)) { + return new StandardMBean( + new Nothing(), NothingMBean.class, wrappedVisible); + } else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return Collections.singleton(notEmitterName); + } + + @Override + public String toString() { + return "Virtual MBeanServerSupport without listener support"; + } + } + + // Class that has the notEmitter and emitter MBeans as Virtual MBeans, using + // VirtualEventManager to handle listeners for the emitter MBean. We + // implement the broadcaster MBean (which is a NotificationBroadcaster but + // not a NotificationEmitter) even though it's very hard to imagine a real + // use case where that would happen. + private static class VirtualMBSWithListeners + extends MBeanServerSupport implements SendNotification { + private final VirtualEventManager vem = new VirtualEventManager(); + + private static final List names = + Arrays.asList(notEmitterName, emitterName1, emitterName2); + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (names.contains(name)) { + return new StandardMBean( + new Nothing(), NothingMBean.class, wrappedVisible); + } else + throw new InstanceNotFoundException(name); + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + if (name.equals(emitterName1) || name.equals(emitterName2)) + return vem.getNotificationEmitterFor(name); + else if (name.equals(notEmitterName)) + return null; + else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return new TreeSet(Arrays.asList(notEmitterName, emitterName2)); + } + + @Override + public String toString() { + return "Virtual MBeanServerSupport with listener support"; + } + + public void sendNotification(Notification notification) { + vem.publish(emitterName1, notification); + vem.publish(emitterName2, notification); + } + } + + private static final MBeanServer[] vmbsss = { + new HardwiredMBS(), + new VirtualMBSWithoutListeners(), + new VirtualMBSWithListeners(), + }; + + public static void main(String[] args) throws Exception { + Exception lastEx = null; + for (MBeanServer vmbs : vmbsss) { + String testName = "\"" + vmbs + "\""; + System.out.println("===Test " + testName + "==="); + try { + test(vmbs); + } catch (Exception e) { + System.out.println( + "===Test " + testName + " failed with exception " + e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + String es = sw.toString(); + System.out.println("......" + es.replace("\n", "\n......")); + lastEx = e; + } + } + if (lastEx != null) + throw lastEx; + System.out.println("TEST PASSED"); + } + + private static class NothingListener implements NotificationListener { + public void handleNotification(Notification notification, + Object handback) { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + private static class QueueListener implements NotificationListener { + final BlockingQueue queue = + new ArrayBlockingQueue(10); + + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + } + + private static void test(MBeanServer vmbs) throws Exception { + MBeanServer mmbs = MBeanServerFactory.newMBeanServer(); + ObjectName namespaceName = new ObjectName("test//:type=JMXNamespace"); + JMXNamespace namespace = new JMXNamespace(vmbs); + mmbs.registerMBean(namespace, namespaceName); + MBeanServer mbs = JMXNamespaces.narrowToNamespace(mmbs, "test"); + + Set names = mbs.queryNames(null, null); + //names.remove(new ObjectName(":type=JMXNamespace")); + + // Make sure that notEmitterName exists according to query... + System.out.println("Checking query"); + if (!names.contains(notEmitterName)) + throw new Exception("Bad query result: " + names); + + // ...and according to getMBeanInfo + System.out.println("Checking getMBeanInfo(" + notEmitterName + ")"); + MBeanInfo mbi = mbs.getMBeanInfo(notEmitterName); + if (mbi.getNotifications().length > 0) + throw new Exception("notEmitter has NotificationInfo"); + + // Make sure we get the right exception for getMBeanInfo on a + // non-existent MBean + System.out.println("Checking getMBeanInfo on a non-existent MBean"); + try { + mbi = mbs.getMBeanInfo(nonExistentName); + throw new Exception("getMBI succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + + // Make sure we get the right exception for addNotificationListener on a + // non-existent MBean + System.out.println( + "Checking addNotificationListener on a non-existent MBean"); + try { + mbs.addNotificationListener( + nonExistentName, new NothingListener(), null, null); + throw new Exception("addNL succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + + // Make sure we get the right exception for isInstanceOf on a + // non-existent MBean + System.out.println( + "Checking isInstanceOf on a non-existent MBean"); + for (Class c : new Class[] { + Object.class, NotificationBroadcaster.class, NotificationEmitter.class, + }) { + try { + boolean is = mbs.isInstanceOf(nonExistentName, c.getName()); + throw new Exception( + "isInstanceOf " + c.getName() + + " succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + } + + // Make sure isInstanceOf works correctly for classes without special + // treatment + System.out.println( + "Checking isInstanceOf on normal classes"); + for (ObjectName name : names) { + boolean isNothing = mbs.isInstanceOf(name, NothingMBean.class.getName()); + if (!isNothing) { + throw new Exception("isInstanceOf " + NothingMBean.class.getName() + + " returned false, should be true"); + } + boolean isTimer = mbs.isInstanceOf(name, TimerMBean.class.getName()); + if (isTimer) { + throw new Exception("isInstanceOf " + TimerMBean.class.getName() + + " returned true, should be false"); + } + } + + // Make sure that addNL on notEmitterName gets the right exception + System.out.println("Checking addNL on non-broadcaster"); + try { + mbs.addNotificationListener( + notEmitterName, new NothingListener(), null, null); + throw new Exception("addNL succeeded but should not have"); + } catch (RuntimeOperationsException e) { + if (!(e.getCause() instanceof IllegalArgumentException)) + throw new Exception("Wrong exception from addNL", e); + } + + if (!(vmbs instanceof SendNotification)) { + System.out.println("Not testing notifications for this implementation"); + return; + } + + QueueListener qListener = new QueueListener(); + + System.out.println("Testing addNL on emitters"); + mbs.addNotificationListener(emitterName1, qListener, null, null); + mbs.addNotificationListener(emitterName2, qListener, null, null); + + System.out.println("Testing that listeners work"); + Notification notif = new Notification("notif.type", "source", 0L); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 2); + + System.out.println("Testing 2-arg removeNL on emitter1"); + mbs.removeNotificationListener(emitterName1, qListener); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 1); + + System.out.println("Testing 4-arg removeNL on emitter2"); + mbs.removeNotificationListener(emitterName2, qListener, null, null); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 0); + } + + private static void testListeners( + QueueListener qListener, String expectedNotifType, int expectedNotifs) + throws Exception { + for (int i = 1; i <= expectedNotifs; i++) { + Notification rNotif = qListener.queue.poll(1, TimeUnit.SECONDS); + if (rNotif == null) + throw new Exception("Notification " + i + " never arrived"); + if (!rNotif.getType().equals(expectedNotifType)) + throw new Exception("Wrong type notif: " + rNotif.getType()); + } + Notification xNotif = qListener.queue.poll(10, TimeUnit.MILLISECONDS); + if (xNotif != null) + throw new Exception("Extra notif: " + xNotif); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/VirtualNamespaceQueryTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/VirtualNamespaceQueryTest.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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * + * @test VirtualNamespaceQueryTest.java + * @summary General VirtualNamespaceQueryTest test. + * @author Daniel Fuchs + * @run clean VirtualNamespaceQueryTest Wombat WombatMBean + * NamespaceController NamespaceControllerMBean + * JMXRemoteTargetNamespace + * @compile -XDignore.symbol.file=true VirtualNamespaceQueryTest.java + * Wombat.java WombatMBean.java + * NamespaceController.java NamespaceControllerMBean.java + * JMXRemoteTargetNamespace.java + * @run main VirtualNamespaceQueryTest + */ + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; + +/** + * + * @author dfuchs + */ +public class VirtualNamespaceQueryTest { + public static class WombatRepository extends MBeanServerSupport { + final Wombat wombat; + final StandardMBean mbean; + final ObjectName wombatName; + + public WombatRepository(ObjectName wombatName) { + try { + wombat = new Wombat(); + mbean = wombat; + this.wombatName = wombatName; + wombat.preRegister(null,wombatName); + } catch (Exception x) { + throw new IllegalArgumentException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (wombatName.equals(name)) return mbean; + else throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + final Set res = Collections.singleton(wombatName); + return res; + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + DynamicMBean mb = getDynamicMBeanFor(name); + if (mb instanceof NotificationEmitter) + return (NotificationEmitter)mb; + return null; + } + } + public static class WombatNamespace extends JMXNamespace { + public WombatNamespace(ObjectName wombatName) { + super(new WombatRepository(wombatName)); + } + } + + public static void simpleTest() throws Exception { + final MBeanServer server = MBeanServerFactory.newMBeanServer(); + final ObjectName wombatName = new ObjectName("burrow:type=Wombat"); + final JMXNamespace ns = new WombatNamespace(wombatName); + server.registerMBean(ns, JMXNamespaces.getNamespaceObjectName("wombats")); + final Set dirs = + server.queryNames(new ObjectName("wombats//*//:type=JMXNamespace"), + wombatName); + System.out.println("all dirs: "+dirs); + if (dirs.size()>0) + throw new RuntimeException("Unexpected ObjectNames returned: "+dirs); + + final ObjectInstance inst = NamespaceController.createInstance(server); + final NamespaceControllerMBean controller = + JMX.newMBeanProxy(server, inst.getObjectName(), + NamespaceControllerMBean.class); + final String[] dirNames = controller.findNamespaces(null,null,2); + System.err.println(Arrays.toString(dirNames)); + } + + public static void main(String[] args) throws Exception { + simpleTest(); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/VirtualPropsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/VirtualPropsTest.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,179 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 5108776 + * @summary Test the properties use case for Virtual MBeans that is documented + * in MBeanServerSupport. + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.VirtualEventManager; +import javax.management.namespace.MBeanServerSupport; + +public class VirtualPropsTest { + public static interface PropertyMBean { + public String getValue(); + } + + public static 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 getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + ObjectName namePattern = newObjectName( + "com.example:type=Property,name=\"*\""); + if (!namePattern.apply(name)) + throw new InstanceNotFoundException(name); + + String propName = ObjectName.unquote(name.getKeyProperty("name")); + if (System.getProperty(propName) == null) + throw new InstanceNotFoundException(name); + PropertyMBean propMBean = new PropertyImpl(propName); + return new StandardMBean(propMBean, PropertyMBean.class, false); + } + + @Override + protected Set getNames() { + 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; + } + + private final VirtualEventManager vem = new VirtualEventManager(); + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + getDynamicMBeanFor(name); // check that the name is valid + return vem.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.publish(objectName, n); + } + } + + static class QueueListener implements NotificationListener { + BlockingQueue q = new ArrayBlockingQueue(10); + public void handleNotification(Notification notification, + Object handback) { + q.add(notification); + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mmbs = ManagementFactory.getPlatformMBeanServer(); + String namespace = "props"; + PropsMBS pmbs = new PropsMBS(); + Object namespaceMBean = new JMXNamespace(pmbs); + mmbs.registerMBean(namespaceMBean, new ObjectName( + namespace + "//:type=JMXNamespace")); + MBeanServer mbs = JMXNamespaces.narrowToNamespace(mmbs, namespace); + + Properties props = System.getProperties(); + + int nprops = props.stringPropertyNames().size(); + if (nprops != mbs.getMBeanCount()) { + throw new Exception(String.format("Properties: %d; MBeans: %d", + nprops, mbs.getMBeanCount())); + } + + for (String propName : props.stringPropertyNames()) { + ObjectName propObjectName = new ObjectName( + "com.example:type=Property,name=" + ObjectName.quote(propName)); + PropertyMBean propProx = JMX.newMBeanProxy( + mbs, propObjectName, PropertyMBean.class); + String propValue = propProx.getValue(); + String realPropValue = props.getProperty(propName); + if (!realPropValue.equals(propValue)) { + throw new Exception(String.format("Property %s: value is \"%s\"; " + + "mbean says \"%s\"", propName, realPropValue, propValue)); + } + } + + ObjectName fooPropObjectName = + new ObjectName("com.example:type=Property,name=\"java.home\""); + QueueListener ql = new QueueListener(); + mbs.addNotificationListener(fooPropObjectName, ql, null, null); + pmbs.propertyChanged("java.home", "bar"); + Notification n = ql.q.poll(1, TimeUnit.SECONDS); + if (n == null) + throw new Exception("Notif didn't arrive"); + if (!"bar".equals(n.getUserData())) + throw new Exception("Bad user data: " + n.getUserData()); + + System.out.println("TEST PASSED"); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/Wombat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/Wombat.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,254 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.Random; +import java.util.Set; +import javax.management.AttributeChangeNotification; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardMBean; + + +/** + * Dynamic MBean based on StandardMBean + * Class Wombat + * Wombat Description + * @author dfuchs + */ +public class Wombat extends StandardMBean + implements WombatMBean, NotificationEmitter, MBeanRegistration { + + /** + * Attribute : Caption + */ + private String caption = "I'm a wombat"; + + private final long MAX_SEED = 36000; + private final long seed; + private final long period; + private volatile int mood = 0; + + public int getMood() { + final long degree = seed + (System.currentTimeMillis()/period)%MAX_SEED; + final double angle = ((double)degree)/100; + mood = (int)(100.0*Math.sin(angle)); + return mood; + } + + public Wombat() throws NotCompliantMBeanException { + super(WombatMBean.class); + final Random r = new Random(); + seed = ((r.nextLong() % MAX_SEED) + MAX_SEED)%MAX_SEED; + period = 200 + (((r.nextLong()%80)+80)%80)*10; + } + + /** + * Next are the methods to compute MBeanInfo. + * You shouldn't update these methods. + */ + @Override + protected String getDescription(MBeanInfo info) { + return "Wombats are strange beasts. You will find them down under " + + "and in some computer programms."; + } + + @Override + protected String getDescription(MBeanAttributeInfo info) { + String description = null; + if (info.getName().equals("Caption")) { + description = "A simple caption to describe a wombat"; + } + if (info.getName().equals("Mood")) { + description = "This Wombat's mood on a [-100,+100] scale."+ + " -100 means that this wombat is very angry."; + } + return description; + } + + @Override + protected String getDescription(MBeanOperationInfo op, + MBeanParameterInfo param, + int sequence) { + return null; + } + + @Override + protected String getParameterName(MBeanOperationInfo op, + MBeanParameterInfo param, + int sequence) { + return null; + } + + @Override + protected String getDescription(MBeanOperationInfo info) { + String description = null; + return description; + } + + @Override + public MBeanInfo getMBeanInfo() { + MBeanInfo mbinfo = super.getMBeanInfo(); + return new MBeanInfo(mbinfo.getClassName(), + mbinfo.getDescription(), + mbinfo.getAttributes(), + mbinfo.getConstructors(), + mbinfo.getOperations(), + getNotificationInfo()); + } + + /** + * Get A simple caption to describe a wombat + */ + public synchronized String getCaption() { + return caption; + } + + /** + * Set A simple caption to describe a wombat + */ + public void setCaption(String value) { + final String oldValue; + synchronized (this) { + oldValue = caption; + caption = value; + } + final AttributeChangeNotification notif = + new AttributeChangeNotification(objectName, + getNextSeqNumber(), + System.currentTimeMillis(), + "Caption changed","Caption", + String.class.getName(),oldValue,value); + broadcaster.sendNotification(notif); + } + + /** + * MBeanNotification support + * You shouldn't update these methods + */ + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { + broadcaster.addNotificationListener(listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + javax.management.AttributeChangeNotification.class.getName(), + "Sent when the caption changes") + }; + } + + 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 synchronized long getNextSeqNumber() { + return seqNumber++; + } + + private long seqNumber; + + private final NotificationBroadcasterSupport broadcaster = new NotificationBroadcasterSupport(); + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. This name is null if the + * name parameter to one of the createMBean or registerMBean methods in + * the MBeanServer interface is null. In that case, this method must + * return a non-null ObjectName for the new MBean. + * @return The name under which the MBean is to be registered. This value + * must not be null. If the name parameter is not null, it will usually + * but not necessarily be the returned value. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + objectName = name; + mbeanServer = server; + return super.preRegister(server, name); + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * @param registrationDone Indicates wether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + @Override + public void postRegister(Boolean registrationDone) { + super.postRegister(registrationDone); + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + @Override + public void preDeregister() throws Exception { + super.preDeregister(); + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + */ + @Override + public void postDeregister() { + super.postDeregister(); + } + + public Set listMatching(ObjectName pattern) { + return mbeanServer.queryNames(pattern, null); + } + + private MBeanServer mbeanServer; + + private ObjectName objectName; +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/WombatMBean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/WombatMBean.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,59 @@ + +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.Set; +import javax.management.ObjectName; + +/** + * Interface WombatMBean + * Wombat Description + * @author dfuchs + */ +public interface WombatMBean +{ + /** + * This Wombat's mood on a [-100,+100] scale. + * -100 means that this wombat is very angry. + * @return The wombat's mood. + */ + public int getMood(); + + /** + * Get A simple caption to describe a wombat + */ + public String getCaption(); + + /** + * Set A simple caption to describe a wombat + */ + public void setCaption(String value); + + /** + * List matching MBeans in the same server. + * @param pattern an ObjectName pattern or null. + * @return A list of matching MBeans. + */ + public Set listMatching(ObjectName pattern); + +} diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/javax/management/namespace/namespace.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/namespace/namespace.policy Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,85 @@ +grant codebase "file:/-" { + permission java.util.PropertyPermission "jmx.wait", "read"; + permission java.util.PropertyPermission "jmx.rmi.port", "read"; + permission java.net.SocketPermission "*", "accept,connect,resolve"; + permission java.security.SecurityPermission "*"; + + // Attribute Caption: allow get everywhere + // ================== + + // allow getAttribute(*:*,Caption) in all MBeanServers + permission javax.management.MBeanPermission "#Caption", "getAttribute"; + // allow getAttribute(*:*,Caption) in all namespaces recursively. + permission javax.management.namespace.JMXNamespacePermission "Caption", + "getAttribute"; + + // Attribute Mood: allow get only in MBeanServers named rmi* + // =============== + + // allow to get attribute Mood of Wombat MBeans only in namespaces + // whose name match rmi*, wherever they are. + // for this we need two permissions: + permission javax.management.namespace.JMXNamespacePermission + "*::Mood[**//rmi*//wombat:*]", + "getAttribute"; + permission javax.management.namespace.JMXNamespacePermission + "*::Mood[rmi*//wombat:*]", + "getAttribute"; + + // allow to get attribute mood in any MBeanServer whose name starts with + // rmi + permission javax.management.MBeanPermission "rmi*::#Mood", + "getAttribute"; + + // Attribute UUID: + // =============== + + // allow to get attribute "UUID" everywhere. + permission javax.management.namespace.JMXNamespacePermission + "*::UUID[*//**//:*]", + "getAttribute"; + permission javax.management.MBeanPermission + "#UUID[*//:*]", + "getAttribute"; + + + + // Let getMBeanInfo and queryNames through everywhere... + // + permission javax.management.namespace.JMXNamespacePermission "[]", + "getMBeanInfo,queryNames"; + permission javax.management.MBeanPermission "*", + "getMBeanInfo,queryNames"; + + // special permission for all wombats: + // + permission javax.management.namespace.JMXNamespacePermission + "[**//*:type=Wombat,*]", + "getObjectInstance,isInstanceOf,queryMBeans"; + permission javax.management.MBeanPermission "[*:type=Wombat,*]", + "getObjectInstance,isInstanceOf,queryMBeans"; + + // allow JMXNamespace::getDefaultDomain + permission javax.management.namespace.JMXNamespacePermission + "*::DefaultDomain", + "getAttribute"; + + // These permissions are required to connect visualvm. + // + permission javax.management.MBeanPermission "default::[java.lang:*]", + "getObjectInstance,isInstanceOf,getAttribute,getMBeanInfo,queryNames,queryMBeans"; + permission javax.management.MBeanPermission "root::", + "isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance,getDomains"; + permission javax.management.namespace.JMXNamespacePermission + "[**//JMImplementation:type=MBeanServerDelegate]", + "addNotificationListener,removeNotificationListener,isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance"; + permission javax.management.MBeanPermission + "javax.management.MBeanServerDelegate", + "addNotificationListener,removeNotificationListener,isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance"; + + // Thread monitoring + permission java.lang.management.ManagementPermission "monitor"; + permission javax.management.MBeanPermission "*::sun.management.*#*[java.lang:*]", "invoke"; +}; + + diff -r 5a725d2f0daa -r 3e5496df0d2b jdk/test/sun/nio/cs/CheckICNE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/nio/cs/CheckICNE.java Wed Jul 05 16:41:30 2017 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 4849617 + @summary Checks "+" is a legal character for charset name + */ +import java.nio.charset.*; + +public class CheckICNE { + static int failed = 0; + public static void main (String[] args) throws Exception { + try { + Charset.forName("abc+"); + } catch (UnsupportedCharsetException uce) {} + + try { + java.nio.charset.Charset.forName("+abc"); + } catch (IllegalCharsetNameException icne) {} + + String[] euros = {"PC-Multilingual-850+euro", + "ebcdic-us-037+euro", + "ebcdic-de-273+euro", + "ebcdic-no-277+euro", + "ebcdic-dk-277+euro", + "ebcdic-fi-278+euro", + "ebcdic-se-278+euro", + "ebcdic-it-280+euro", + "ebcdic-es-284+euro", + "ebcdic-gb-285+euro", + "ebcdic-fr-277+euro", + "ebcdic-international-500+euro", + "ebcdic-s-871+euro" + }; + + System.out.println("Test Passed!"); + } +} diff -r 5a725d2f0daa -r 3e5496df0d2b make/Defs-internal.gmk --- a/make/Defs-internal.gmk Thu Sep 11 11:25:48 2008 -0700 +++ b/make/Defs-internal.gmk Wed Jul 05 16:41:30 2017 +0200 @@ -257,8 +257,3 @@ COMMON_BUILD_ARGUMENTS += ANT_HOME="$(ANT_HOME)" endif -ifdef FINDBUGS_HOME - COMMON_BUILD_ARGUMENTS += FINDBUGS_HOME="$(FINDBUGS_HOME)" -endif - - diff -r 5a725d2f0daa -r 3e5496df0d2b make/README.pre-components --- a/make/README.pre-components Thu Sep 11 11:25:48 2008 -0700 +++ b/make/README.pre-components Wed Jul 05 16:41:30 2017 +0200 @@ -20,7 +20,6 @@ VARIANT If DBG, debug build, if OPT, optimized build TARGET_CLASS_VERSION The classfile version number (currently 5) ANT_HOME Home of ant to use, if provided - FINDBUGS_HOME Home of findbugs to use, if provided QUIET If defined, be quiet VERBOSE If defined, be verbose JDK_VERSION Version being built diff -r 5a725d2f0daa -r 3e5496df0d2b make/jprt.config --- a/make/jprt.config Thu Sep 11 11:25:48 2008 -0700 +++ b/make/jprt.config Wed Jul 05 16:41:30 2017 +0200 @@ -1,7 +1,7 @@ #!echo "This is not a shell script" ############################################################################# # -# Copyright 2006-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-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 @@ -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 # If ALT_PREVIOUS_RELEASE_IMAGE not defined, set it to the bootdir area for # any possible image comparisons. @@ -152,7 +148,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 @@ -189,7 +185,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 @@ -237,7 +233,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}" @@ -255,7 +251,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"