diff --git a/.hgtags b/.hgtags index 92c22dd5bf001935229e502bf99330dec20fa92a..8a91ce7fabc4260c84be51f037b58a2ad6070c8c 100644 --- a/.hgtags +++ b/.hgtags @@ -7,3 +7,8 @@ e21f4266466cd1306b176aaa08b2cd8337a9be3d jdk7-b29 b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30 b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31 c51121419e30eac5f0fbbce45ff1711c4ce0de28 jdk7-b32 +fa4c0a6cdd25d97d4e6f5d7aa180bcbb0e0d56af jdk7-b33 +434055a0716ee44bca712ebca02fc04b20e6e288 jdk7-b34 +cf4894b78ceb966326e93bf221db0c2d14d59218 jdk7-b35 +134fd1a656ea85acd1f97f6700f75029b9b472a0 jdk7-b36 +14f50aee4989b75934d385c56a83da0c23d2f68b jdk7-b37 diff --git a/make/ASSEMBLY_EXCEPTION b/make/ASSEMBLY_EXCEPTION deleted file mode 100644 index 8b7ac1d08137f9354fa6a78ac8ca489292984cd4..0000000000000000000000000000000000000000 --- a/make/ASSEMBLY_EXCEPTION +++ /dev/null @@ -1,27 +0,0 @@ - -OPENJDK ASSEMBLY EXCEPTION - -The OpenJDK source code made available by Sun at openjdk.java.net and -openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the -GNU General Public License version 2 -only ("GPL2"), with the following clarification and special exception. - - Linking this OpenJDK Code statically or dynamically with other code - is making a combined work based on this library. Thus, the terms - and conditions of GPL2 cover the whole combination. - - As a special exception, Sun gives you permission to link this - OpenJDK Code with certain code licensed by Sun as indicated at - http://openjdk.java.net/legal/exception-modules-2007-05-08.html - ("Designated Exception Modules") to produce an executable, - regardless of the license terms of the Designated Exception Modules, - and to copy and distribute the resulting executable under GPL2, - provided that the Designated Exception Modules continue to be - governed by the licenses under which they were offered by Sun. - -As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to -build an executable that includes those portions of necessary code that Sun -could not provide under GPL2 (or that Sun has provided under GPL2 with the -Classpath exception). If you modify or add to the OpenJDK code, that new -GPL2 code may still be combined with Designated Exception Modules if the -new code is made subject to this exception by its copyright holder. diff --git a/make/LICENSE b/make/LICENSE deleted file mode 100644 index eeab58c21c9a42ab1dfe8a17a9aed6607100bec2..0000000000000000000000000000000000000000 --- a/make/LICENSE +++ /dev/null @@ -1,347 +0,0 @@ -The GNU General Public License (GPL) - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to share -and change it. By contrast, the GNU General Public License is intended to -guarantee your freedom to share and change free software--to make sure the -software is free for all its users. This General Public License applies to -most of the Free Software Foundation's software and to any other program whose -authors commit to using it. (Some other Free Software Foundation software is -covered by the GNU Library General Public License instead.) You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom to -distribute copies of free software (and charge for this service if you wish), -that you receive source code or can get it if you want it, that you can change -the software or use pieces of it in new free programs; and that you know you -can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to deny -you these rights or to ask you to surrender the rights. These restrictions -translate to certain responsibilities for you if you distribute copies of the -software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or for -a fee, you must give the recipients all the rights that you have. You must -make sure that they, too, receive or can get the source code. And you must -show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If the -software is modified by someone else and passed on, we want its recipients to -know that what they have is not the original, so that any problems introduced -by others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program proprietary. -To prevent this, we have made it clear that any patent must be licensed for -everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice -placed by the copyright holder saying it may be distributed under the terms of -this General Public License. The "Program", below, refers to any such program -or work, and a "work based on the Program" means either the Program or any -derivative work under copyright law: that is to say, a work containing the -Program or a portion of it, either verbatim or with modifications and/or -translated into another language. (Hereinafter, translation is included -without limitation in the term "modification".) Each licensee is addressed as -"you". - -Activities other than copying, distribution and modification are not covered by -this License; they are outside its scope. The act of running the Program is -not restricted, and the output from the Program is covered only if its contents -constitute a work based on the Program (independent of having been made by -running the Program). Whether that is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code as -you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this License -and to the absence of any warranty; and give any other recipients of the -Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you may -at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, thus -forming a work based on the Program, and copy and distribute such modifications -or work under the terms of Section 1 above, provided that you also meet all of -these conditions: - - a) You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in whole or - in part contains or is derived from the Program or any part thereof, to be - licensed as a whole at no charge to all third parties under the terms of - this License. - - c) If the modified program normally reads commands interactively when run, - you must cause it, when started running for such interactive use in the - most ordinary way, to print or display an announcement including an - appropriate copyright notice and a notice that there is no warranty (or - else, saying that you provide a warranty) and that users may redistribute - the program under these conditions, and telling the user how to view a copy - of this License. (Exception: if the Program itself is interactive but does - not normally print such an announcement, your work based on the Program is - not required to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable -sections of that work are not derived from the Program, and can be reasonably -considered independent and separate works in themselves, then this License, and -its terms, do not apply to those sections when you distribute them as separate -works. But when you distribute the same sections as part of a whole which is a -work based on the Program, the distribution of the whole must be on the terms -of this License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your -rights to work written entirely by you; rather, the intent is to exercise the -right to control the distribution of derivative or collective works based on -the Program. - -In addition, mere aggregation of another work not based on the Program with the -Program (or with a work based on the Program) on a volume of a storage or -distribution medium does not bring the other work under the scope of this -License. - -3. You may copy and distribute the Program (or a work based on it, under -Section 2) in object code or executable form under the terms of Sections 1 and -2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 above - on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three years, to - give any third party, for a charge no more than your cost of physically - performing source distribution, a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed only - for noncommercial distribution and only if you received the program in - object code or executable form with such an offer, in accord with - Subsection b above.) - -The source code for a work means the preferred form of the work for making -modifications to it. For an executable work, complete source code means all -the source code for all modules it contains, plus any associated interface -definition files, plus the scripts used to control compilation and installation -of the executable. However, as a special exception, the source code -distributed need not include anything that is normally distributed (in either -source or binary form) with the major components (compiler, kernel, and so on) -of the operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the source -code from the same place counts as distribution of the source code, even though -third parties are not compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as -expressly provided under this License. Any attempt otherwise to copy, modify, -sublicense or distribute the Program is void, and will automatically terminate -your rights under this License. However, parties who have received copies, or -rights, from you under this License will not have their licenses terminated so -long as such parties remain in full compliance. - -5. You are not required to accept this License, since you have not signed it. -However, nothing else grants you permission to modify or distribute the Program -or its derivative works. These actions are prohibited by law if you do not -accept this License. Therefore, by modifying or distributing the Program (or -any work based on the Program), you indicate your acceptance of this License to -do so, and all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the Program), -the recipient automatically receives a license from the original licensor to -copy, distribute or modify the Program subject to these terms and conditions. -You may not impose any further restrictions on the recipients' exercise of the -rights granted herein. You are not responsible for enforcing compliance by -third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), conditions -are imposed on you (whether by court order, agreement or otherwise) that -contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy -simultaneously your obligations under this License and any other pertinent -obligations, then as a consequence you may not distribute the Program at all. -For example, if a patent license would not permit royalty-free redistribution -of the Program by all those who receive copies directly or indirectly through -you, then the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply and -the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or -other property right claims or to contest validity of any such claims; this -section has the sole purpose of protecting the integrity of the free software -distribution system, which is implemented by public license practices. Many -people have made generous contributions to the wide range of software -distributed through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing to -distribute software through any other system and a licensee cannot impose that -choice. - -This section is intended to make thoroughly clear what is believed to be a -consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain -countries either by patents or by copyrighted interfaces, the original -copyright holder who places the Program under this License may add an explicit -geographical distribution limitation excluding those countries, so that -distribution is permitted only in or among countries not thus excluded. In -such case, this License incorporates the limitation as if written in the body -of this License. - -9. The Free Software Foundation may publish revised and/or new versions of the -General Public License from time to time. Such new versions will be similar in -spirit to the present version, but may differ in detail to address new problems -or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any later -version", you have the option of following the terms and conditions either of -that version or of any later version published by the Free Software Foundation. -If the Program does not specify a version number of this License, you may -choose any version ever published by the Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs -whose distribution conditions are different, write to the author to ask for -permission. For software which is copyrighted by the Free Software Foundation, -write to the Free Software Foundation; we sometimes make exceptions for this. -Our decision will be guided by the two goals of preserving the free status of -all derivatives of our free software and of promoting the sharing and reuse of -software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR -THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE -STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE -PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND -PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, -YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL -ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE -PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR -INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA -BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER -OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible -use to the public, the best way to achieve this is to make it free software -which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach -them to the start of each source file to most effectively convey the exclusion -of warranty; and each file should have at least the "copyright" line and a -pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - - Copyright (C) - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when it -starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author Gnomovision comes - with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free - software, and you are welcome to redistribute it under certain conditions; - type 'show c' for details. - -The hypothetical commands 'show w' and 'show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than 'show w' and 'show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your school, -if any, to sign a "copyright disclaimer" for the program, if necessary. Here -is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - 'Gnomovision' (which makes passes at compilers) written by James Hacker. - - signature of Ty Coon, 1 April 1989 - - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. - - -"CLASSPATH" EXCEPTION TO THE GPL - -Certain source files distributed by Sun Microsystems, Inc. are subject to -the following clarification and special exception to the GPL, but only where -Sun has expressly included in the particular source file's header the words -"Sun designates this particular file as subject to the "Classpath" exception -as provided by Sun in the LICENSE file that accompanied this code." - - Linking this library statically or dynamically with other modules is making - a combined work based on this library. Thus, the terms and conditions of - the GNU General Public License cover the whole combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent modules, - and to copy and distribute the resulting executable under terms of your - choice, provided that you also meet, for each linked independent module, - the terms and conditions of the license of that module. An independent - module is a module which is not derived from or based on this library. If - you modify this library, you may extend this exception to your version of - the library, but you are not obligated to do so. If you do not wish to do - so, delete this exception statement from your version. diff --git a/make/README b/make/README deleted file mode 100644 index d774ab80b70466958efc3ae02347b54eb84fc1b5..0000000000000000000000000000000000000000 --- a/make/README +++ /dev/null @@ -1,34 +0,0 @@ -README: - This file should be located at the top of the jdk Mercurial repository. - - See http://openjdk.java.net/ for more information about the OpenJDK. - -Simple Build Instructions: - - 1. Download and install a JDK 6 from - http://java.sun.com/javase/downloads/index.jsp - Set the environment variable ALT_BOOTDIR to the location of this JDK 6. - - 2. Download and install the Binary Plugs for the most recent JDK7 from - http://download.java.net/openjdk/jdk7/ - Set the environment variable ALT_BINARY_PLUGS_PATH to the location of - these binary plugs. - - 3. Either download and install the latest JDK7 from - http://download.java.net/openjdk/jdk7/, or build your own complete - OpenJDK7 by using the top level Makefile in the OpenJDK Mercurial forest. - Set the environment variable ALT_JDK_IMPORT_PATH to the location of - this latest JDK7 or OpenJDK7 build. - - 4. Check the sanity of doing a build with the current machine: - cd make && gnumake sanity - See README-builds.html if you run into problems. - - 5. Do a partial build of the jdk: - cd make && gnumake all - - 6. Construct the images: - cd make && gnumake images - The resulting JDK image should be found in build/*/j2sdk-image - - diff --git a/make/README-builds.html b/make/README-builds.html deleted file mode 100644 index 6530865db54a3695e47ffe6f88ce7d4b92b35970..0000000000000000000000000000000000000000 --- a/make/README-builds.html +++ /dev/null @@ -1,1452 +0,0 @@ - - - -OpenJDK Build README - - -
- -
-

OpenJDK Build README

-
- - -
- -

Introduction

- -
-

- This README file contains build instructions for the - OpenJDK. - Building the source code for the - OpenJDK - requires - a certain degree of technical expertise. -

- - -
- -

Contents

- -
- -
- - -
- -

Minimum Build Environments

- -
-

- This file often describes specific requirements for what we call the - "minimum build environments" (MBE) for the JDK. - Building with the MBE will generate the most compatible - bits that install on, and run correctly on, the most variations - of the same base OS and hardware architecture. - These usually represent what is often called the - least common denominator platforms. - It is understood that most developers will NOT be using these - specific platforms, and in fact creating these specific platforms - may be difficult due to the age of some of this software. -

- -

- The minimum OS and C/C++ compiler versions needed for building the - OpenJDK: -

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Base OS and ArchitectureOSCompiler
Linux X86 (32bit)Red Hat Enterprise Linux 4 gcc 4
Linux X64 (64bit)Red Hat Enterprise Linux 4 gcc 4
Solaris SPARC (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris SPARCV9 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X86 (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X64 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Windows X86 (32bit)Windows XPMicrosoft Visual Studio .NET 2003 Professional
Windows X64 (64bit)Windows Server 2003 - Enterprise x64 EditionMicrosoft Platform SDK - April 2005
-
-
- - -
- -

Specific Developer Build Environments

- -
-

- We won't be listing all the possible environments, but - we will try to provide what information we have available to us. -

- -

Fedora

- -
- TBD -
- -

Debian

- -
- TBD -
- -

Ubuntu

- -
-

- In addition to needing the Bootstrap JDK and the Binary Plugs, - when building on Ubuntu you will need to - make sure certain packages are installed. - In particular, certain X11 packages, make, m4, gawk, gcc 4, - binutils, cups, freetype - and alsa. - -

Ubuntu 6.06

- -

- The following list of packages for Ubuntu 6.06 is a working set that - does appear to work. - -

- Note that it's quite possible that some of these - packages are not required, so anyone discovering that some of the - packages listed below are NOT required, - please let the - OpenJDK - team know. -

- All the packages below can be installed with the - Synaptic Package manager provided with the base Ubuntu 6.06 release. - -

-
    -
  • binutils (2.16.1cvs20060117-1ubuntu2.1)
  • -
  • cpp (4:4.0.3-1)
  • -
  • cpp-4.0 (4.0.3-1ubuntu5)
  • -
  • libfreetype6-dev
  • -
  • g++ (4:4.0.3-1)
  • -
  • g++-4.0 (4.0.3-1ubuntu5)
  • -
  • gawk (1:3.1.5-2build1)
  • -
  • gcc (4:4.0.3-1)
  • -
  • gcc-4.0 (4.0.3-1ubuntu5)
  • -
  • libasound2-dev (1.0.10-2ubuntu4)
  • -
  • libc6 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libc6-dev (2.3.6-0ubuntu20.4)
  • -
  • libc6-i686 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libcupsys2-dev (1.2.2-0ubuntu0.6.06)
  • -
  • libgcrypt11-dev (1.2.2-1)
  • -
  • libgnutls-dev (1.2.9-2ubuntu1.1)
  • -
  • libgnutls12 (1.2.9-2ubuntu1) to 1.2.9-2ubuntu1.1
  • -
  • libgpg-error-dev (1.1-4)
  • -
  • libice-dev (2:1.0.0-0ubuntu2)
  • -
  • liblockfile1 (1.06.1)
  • -
  • libopencdk8-dev (0.5.7-2)
  • -
  • libpopt-dev (1.7-5)
  • -
  • libsm-dev (2:1.0.0-0ubuntu2)
  • -
  • libstdc++6-4.0-dev (4.0.3-1ubuntu5)
  • -
  • libtasn1-2-dev (0.2.17-1ubuntu1)
  • -
  • libx11-dev (2:1.0.0-0ubuntu9)
  • -
  • libxau-dev (1:1.0.0-0ubuntu4)
  • -
  • libxaw-headers (2:1.0.1-0ubuntu3)
  • -
  • libxaw7-dev (2:1.0.1-0ubuntu3)
  • -
  • libxdmcp-dev (1:1.0.0-0ubuntu2)
  • -
  • libxext-dev (2:1.0.0-0ubuntu4)
  • -
  • libxi-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-headers (2:1.0.0-0ubuntu3)
  • -
  • libxmuu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxp-dev (6.8.2-11ubuntu2)
  • -
  • libxpm-dev (1:3.5.4.2-0ubuntu3)
  • -
  • libxrandr-dev (1:1.1.0.2-0ubuntu4)
  • -
  • libxt-dev (1:1.0.0-0ubuntu3)
  • -
  • libxtrap-dev (2:1.0.0-0ubuntu2)
  • -
  • libxtst-dev (2:1.0.1-0ubuntu2)
  • -
  • libxv-dev (2:1.0.1-0ubuntu3)
  • -
  • linux-kernel-headers (2.6.11.2-0ubuntu18)
  • -
  • m4 (1.4.4-1)
  • -
  • make (3.80+3.81.b4-1)
  • -
  • ssl-cert (1.0.13)
  • -
  • x-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-core-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-input-dev (1.3.2-0ubuntu2)
  • -
  • x11proto-kb-dev (1.0.2-0ubuntu2)
  • -
  • x11proto-randr-dev (1.1.2-0ubuntu2)
  • -
  • x11proto-record-dev (1.13.2-0ubuntu2)
  • -
  • x11proto-trap-dev (3.4.3-0ubuntu2)
  • -
  • x11proto-video-dev (2.2.2-0ubuntu2)
  • -
  • x11proto-xext-dev (7.0.2-0ubuntu2)
  • -
  • xlibs-dev (7.0.0-0ubuntu45)
  • -
  • zlib1g-dev (1:1.2.3-6ubuntu4)
  • -
-
- -

Ubuntu 7.04

- -

- Using the Synaptic Package Manager, download the following - packages (double indented packages are automatically aquired - due to package dependencies): - -

-
    -
  • build-essential
  • -
      -
    • dpkg-dev
    • -
    • g++
    • -
    • g++-4.1
    • -
    • libc6-dev
    • -
    • libstdc++6.4.1-dev
    • -
    • linux-libc-dev
    • -
    -
  • gawk
  • -
  • m4
  • -
  • libasound2-dev
  • -
  • libcupsys2-dev
  • -
      -
    • libgcrypt11-dev
    • -
    • lgnutls-dev
    • -
    • libgpg-error-dev
    • -
    • liblzo-dev
    • -
    • libopencdk8-dev
    • -
    • libpopt-dev
    • -
    • libtasn1-3-dev
    • -
    • zlib1g-dev
    • -
    -
  • sun-java6-jdk
  • -
      -
    • java-common
    • -
    • libltdl3
    • -
    • odbcinst1debian1
    • -
    • sun-java6-bin
    • -
    • sun-java6-jre
    • -
    • unixodbc
    • -
    -
  • xlibs-dev
  • -
      -
    • (many)
    • -
    -
  • x11proto-print-dev
  • -
  • libxaw7-dev
  • -
      -
    • libxaw-headers
    • -
    -
  • libxp-dev
  • -
  • libfreetype6-dev
  • -
-
-
- - -
- -

Source Directory Structure

- -
-

- The source code for the - OpenJDK is - delivered in 3 sibling directories: - hotspot, - langtools, - corba, - jaxws, - jaxp, - jdk - and - The hotspot directory contains the source code and make - files for - building the - OpenJDK - Hotspot Virtual Machine. - The jdk - directory contains the source code and make files for - building the - OpenJDK - runtime libraries, tools and demos. - The top level Makefile is used to build the complete OpenJDK - release including building the hotspot - VM, staging the VM binaries, and building the - OpenJDK - runtime libraries, - tools and demos. -

- - -
- -

Build Information

- -
-

- Building the - OpenJDK - is done with a gmake - command line and various - environment or make variable settings that direct the make rules - to where various components have been installed. - Where possible the makefiles will attempt to located the various - components in the default locations or any component specific - variable settings. - When the normal defaults fail or components cannot be found, - the various - ALT_* variables (alternates) - can be used to help the makefiles locate components. -

- Refer to the bash/sh/ksh setup file - jdk/make/jdk_generic_profile.sh - if you need help in setting up your environment variables. - A build could be as simple as: -

-

-                bash
-                . jdk/make/jdk_generic_profile.sh
-                gmake sanity && gmake
-        
-
-

- Of course ksh or sh would work too. - But some customization will probably be necessary. - The sanity rule will make some basic checks on build - dependencies and generate appropriate warning messages - regarding missing, out of date, or newer than expected components - found on your system. -

- - -
- -

GNU make (gmake)

- -
-

- The Makefiles in the - OpenJDK - are only valid when used with the - GNU version of the utility command make - (gmake). - A few notes about using GNU make: -

    -
  • - In general, you need GNU make version 3.78.1 or newer. -
  • -
  • - Place the location of the GNU make binary in the PATH. -
  • -
  • - Linux: - The /usr/bin/make command should work fine for you. -
  • -
  • - Solaris: - Do NOT use /usr/bin/make on Solaris. - If your Solaris system has the software - from the Solaris Companion CD installed, - you should use gmake - which will be located in either the /opt/sfw/bin or - /usr/sfw/bin directory. -
  • -
  • - Windows: - Make sure you start your build inside a bash/sh/ksh shell. -
    - WARNING: Watch out for make version 3.81, it may - not work due to a lack of support for drive letter paths - like C:/. Use a 3.80 version, or find a newer - version that has this problem fixed. -
  • -
-

- Information on GNU make, and access to ftp download sites, are - available on the - - GNU make web site - . - The latest source to GNU make is available at - ftp.gnu.org/pub/gnu/make/. -

- - -
- -

Basic Linux System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the Linux version - is a Pentium class processor or better, at least 256 MB of RAM, and - approximately 1.5 GB of free disk space. -

- X64 only: - The minimum recommended hardware for building the Linux - version is an AMD Opteron class processor, at least 512 MB of RAM, and - approximately 4 GB of free disk space. -

- The build will use the tools contained in - /bin and - /usr/bin - of a standard installation of the Linux operating environment. - You should ensure that these directories are in your - PATH. -

- Note that some Linux systems have a habit of pre-populating - your environment variables for you, for example JAVA_HOME - might get pre-defined for you to refer to the JDK installed on - your Linux system. - You will need to unset JAVA_HOME. - It's a good idea to run env and verify the - environment variables you are getting from the default system - settings make sense for building the - OpenJDK. -

- - - -

Basic Linux Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install or upgrade the FreeType development - package. -
  6. -
-
- - -
- -

Basic Solaris System Setup

- -
-

- The minimum recommended hardware for building the - Solaris SPARC version is an UltraSPARC with 512 MB of RAM. - For building - the Solaris x86 version, a Pentium class processor or better and at - least 128 MB of RAM are recommended. - Approximately 1.4 GB of free disk - space is needed for a 32-bit build. -

- If you are building the 64bit version, you should - run the command "isainfo -v" to verify that you have a - 64-bit installation. - An additional 7 GB of free disk space is needed - for a 64-bit build. -

- The build uses the tools contained in /usr/ccs/bin - and /usr/bin of a standard developer or full installation of - the Solaris operating environment. -

- - - -

Basic Solaris Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install the - Sun Studio Compilers, set - ALT_COMPILER_PATH. -
  6. -
  7. - Install the - CUPS Include files, set - ALT_CUPS_HEADERS_PATH. -
  8. -
-
- - -
- -

Basic Windows System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the 32bit or X86 - Windows version is an Pentium class processor or better, at least - 512 MB of RAM, and approximately 600 MB of free disk space. - - NOTE: The Windows 2000 build machines need to use the - file system NTFS. - Build machines formatted to FAT32 will not work - because FAT32 doesn't support case-sensitivity in file names. - -

- X64 only: - The minimum recommended hardware for building - the Windows X64 version is an AMD Opteron class processor, at least 1 - GB of RAM, and approximately 10 GB of free disk space. -

- - - -

Windows Paths

- -
-

- Windows: - Note that GNU make is a historic utility and is based very - heavily on shell scripting, so it does not tolerate the Windows habit - of having spaces in pathnames or the use of the \characters in pathnames. - Luckily on most Windows systems, you can use /instead of \, and - there is always a 'short' pathname without spaces for any path that - contains spaces. - Unfortunately, this short pathname can be somewhat dynamic and the - formula is difficult to explain. - You can use cygpath utility to map pathnames with spaces - or the \character into the C:/ style of pathname - (called 'mixed'), e.g. - cygpath -s -m "path". -

- The makefiles will try to translate any pathnames supplied - to it into the C:/ style automatically. -

- Note that use of CYGWIN creates a unique problem with regards to - setting PATH. Normally on Windows - the PATH variable contains directories - separated with the ";" character (Solaris and Linux uses ":"). - With CYGWIN, it uses ":", but that means that paths like "C:/path" - cannot be placed in the CYGWIN version of PATH and - instead CYGWIN uses something like /cygdrive/c/path - which CYGWIN understands, but only CYGWIN understands. - So be careful with paths on Windows. -

- - - -

Basic Windows Check List

- -
-
    -
  1. - Install the - CYGWIN product. -
  2. -
  3. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  4. -
  5. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH.. -
  6. -
  7. - Install the - Microsoft Visual Studio .NET 2003 Professional or the - Microsoft Platform SDK. -
  8. -
  9. - Setup all environment variables for compilers - (see compilers). -
  10. -
  11. - Install - Microsoft DirectX SDK. -
  12. -
-
- - -
- -

Build Dependencies

- -
-

- Depending on the platform, the - OpenJDK - build process has some basic - dependencies on components not part of the - OpenJDK - sources. - Some of these are specific to a platform, some even specific to - an architecture. - Each dependency will have a set of ALT variables that can be set - to tell the makefiles where to locate the component. - In most cases setting these ALT variables may not be necessary - and the makefiles will find defaults on the system in standard - install locations or through component specific variables. - -

Bootstrap JDK

- -
-

- All - OpenJDK - builds require access to the previously released - JDK 6, this is often called a bootstrap JDK. - The JDK 6 binaries can be downloaded from Sun's - JDK 6 download site. - For build performance reasons - is very important that this bootstrap JDK be made available on the - local disk of the machine doing the build. - You should always set - ALT_BOOTDIR - to point to the location of - the bootstrap JDK installation, this is the directory pathname - that contains a bin, lib, and include - It's also a good idea to also place its bin directory - in the PATH environment variable, although it's - not required. -

- Solaris: - Some pre-installed JDK images may be available to you in the - directory /usr/jdk/instances. - If you don't set - ALT_BOOTDIR - the makefiles will look in that location for a JDK it can use. -

- -

Binary Plugs

- -
-

- Not all of the source code that makes up the JDK is available - under an open-source license. - In order to build an OpenJDK binary from source code, - you must first download and install the appropriate - binary plug bundles from the OpenJDK Download area. - During the OpenJDK build process these "binary plugs" - for the encumbered components will be copied into your - resulting OpenJDK binary build image. - These binary plug files are only for the purpose of - building an OpenJDK binary. - Download the Binary Plugs by selecting the Downloads - link at - the OpenJDK site, - install the bundle, - and make sure you set - ALT_BINARY_PLUGS_PATH - to the root of this installation. -

- -

Certificate Authority File (cacert)

- -
-

- See - www.wikipedia.org/wiki/CAcert - for a better understanding of the Certificate Authority (CA). - A certificates file named "cacerts" - represents a system-wide keystore with CA certificates. - In JDK and JRE - binary bundles, the "cacerts" file contains root CA certificates from - several public CAs (e.g., VeriSign, Thawte, and Baltimore). - The source contain a cacerts file - without CA root certificates. - Formal JDK builders will need to secure - permission from each public CA and include the certificates into their - own custom cacerts file. - Failure to provide a populated cacerts file - will result in verification errors of a certificate chain during runtime. - The variable - ALT_CACERTS_FILE - can be used to override the default location of the - cacerts file that will get placed in your build. - By default an empty cacerts file is provided and that should be - fine for most JDK developers. -

- -

Compilers

- -
- - - Linux gcc/binutils - - -
-

- The GNU gcc compiler version should be 3.2.2 or newer. - The binutils package should be 2.11.93.0.2-11 or newer. - The compiler used should be the default compiler installed - in /usr/bin. -

- - Solaris: Sun Studio - -
-

- At a minimum, the - - Sun Studio 11 Compilers - (containing version 5.8 of the C and C++ compilers) is required, - with patches from the - - SunSolve web site. -

- Set - ALT_COMPILER_PATH - to point to the location of - the compiler binaries, and place this location in the PATH. -

- The Sun Studio Express compilers at: - - Sun Studio Express Download site - are also an option, although these compilers have not - been extensively used yet. -

- - - Windows i586: Microsoft Visual Studio .NET 2003 Professional - - -
-

- The 32-bit - OpenJDK - Windows build - requires Microsoft Visual Studio .NET 2003 (VS2003) Professional - Edition compiler. - The compiler and other tools are expected to reside - in the location defined by the variable VS71COMNTOOLS which - is set by the Microsoft Visual Studio .NET installer. -

- Once the compiler is installed, - it is recommended that you run VCVARS32.BAT - to set the compiler environment variables - MSVCDIR, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- The Microsoft Visual Studio .NET 2005 (VS2005) compiler - will not work at this time due to the new runtime dll - and the manifest requirements. -

- - - Windows X64: Microsoft Platform SDK April 2005 - - -
-

- On X64, - the Microsoft Platform Software - Development Kit (SDK), April 2005 Edition compiler, is required for - building the - OpenJDK - because it contains the C/C++ compiler. - You will need to minimally install the Core SDK and - the MDAC SDK features of this compiler. -

- Once the Platform SDK is installed, - it is recommended that you run SetEnv.Cmd /X64 - to set the compiler environment variables - MSSDK, - MSTOOLS, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- Note that this compiler may say it's version is a - Microsoft Visual Studio .NET 2005 (VS2005), but be careful, - it will not match the official VS2005 product. - This Platform SDK compiler is only used on X64 builds. -

- -
- -

Common UNIX Printing System (CUPS) Headers (Solaris & Linux)

- -
-

- Solaris: - CUPS header files are required for building the - OpenJDK on Solaris. - The Solaris header files can be obtained by installing - the package SFWcups from the Solaris Software - Companion CD/DVD, these often will be installed into - /opt/sfw/cups. -

- Linux: - CUPS header files are required for building the - OpenJDK on Linux. - The Linux header files are usually available from a "cups" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. -

- The CUPS header files can always be downloaded from - www.cups.org. - The variable - ALT_CUPS_HEADERS_PATH - can be used to override the default location of the - CUPS Header files. -

- -

FreeType 2

- -
-

- Version 2.3 or newer of FreeType is required for building the OpenJDK. - On Unix systems required files can be available as part of your - distribution (while you still may need to upgrade them). - Note that you need development version of package that - includes both FreeType library and header files. -

-

- You can always download latest FreeType version from the - FreeType website. -

-

- Makefiles will try to pick FreeType from /usr/lib and /usr/include. - In case it is installed elsewhere you will need to set environment - variables - ALT_FREETYPE_LIB_PATH - and - ALT_FREETYPE_HEADERS_PATH - to refer to place where library and header files are installed. -

-
- -

Advanced Linux Sound Architecture (ALSA) (Linux only)

- -
-

- Linux only: - Version 0.9.1 or newer of the ALSA files are - required for building the - OpenJDK on Linux. - These Linux files are usually available from an "alsa" - of "libasound" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. - The makefiles will check this emit a sanity error if it is - missing or the wrong version. - As a last resort you can go to the - - Advanced Linux Sound Architecture Site. -

- -

Windows Specific Dependencies

- -
- - Unix Command Tools (CYGWIN) - -
-

- The - OpenJDK - requires access to a set of unix command tools - on Windows which can be supplied by - CYGWIN. -

- The - OpenJDK - build - requires CYGWIN version 1.5.12 or newer. - Information about CYGWIN can - be obtained from the CYGWIN website at - www.cygwin.com. -

- By default CYGWIN doesn't install all the tools required for building - the OpenJDK. - Along with the default installation, you need to install - the following tools. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Binary NamePackageDescription
ar.exeDevelbinutils: The GNU assembler, linker and binary - utilities
make.exeDevelmake: The GNU version of the 'make' utility
m4.exeInterpretersm4: GNU implementation of the traditional Unix macro - processor
cpio.exeUtilscpio: A program to manage archives of files
file.exeUtilsfile: Determines file type using 'magic' numbers
-
-
- - - Microsoft DirectX 9.0 SDK header files and libraries - - -
-

- Microsoft DirectX 9.0 SDK (Summer 2004) - headers are required for building - OpenJDK. - This SDK can be downloaded from - - Microsoft DirectX 9.0 SDK (Summer 2004). - If the link above becomes obsolete, the SDK can be found from - the Microsoft Download Site - (search with "DirectX 9.0 SDK Update Summer 2004"). - The location of this SDK can be set with - ALT_DXSDK_PATH - but it's normally found via the DirectX environment variable - DXSDK_DIR. -

- - - MSVCRT.DLL - - -
-

- i586 only: - The - OpenJDK - 32bit build requires - access to MSVCRT.DLL - version 6.00.8337.0 or newer. - If the MSVCRT.DLL is not installed in - the system32 directory set the - ALT_MSVCRT_DLL_PATH - variable to the location. -

- X64 only: - The OpenJDK 64bit build requires access to - MSVCRT.DLL version 7.0.3790.0 or newer, which is - usually supplied by the - Platform SDK. - If it is not available from the Platform SDK, - set the - ALT_MSVCRT_DLL_PATH - variable to the location. -

- - - MSVCR71.DLL - - -
-

- i586 only: - The - OpenJDK - build requires access to - MSVCR71.DLL version 7.10.3052.4 or newer which should be - supplied by the - Visual Studio product - If the MSVCR71.DLL is not available from the - Visual Studio product - set the - ALT_MSVCR71_DLL_PATH - variable to the location. -

- -
- - -
- - -
- -

Creating the Build

- -
-

- Once a machine is setup to build the - OpenJDK, - the steps to create the - build are fairly simple. - The various ALT settings can either be made into variables - or can be supplied on the - gmake - command. -

-

    -
  1. Use the sanity rule to double check all the ALT settings: -
    - - gmake - sanity - [ARCH_DATA_MODEL=32 or 64] - [other "ALT_" overrides] - -
    -
  2. -
  3. Start the build with the command: -
    - - gmake - [ARCH_DATA_MODEL=32 or 64] - [ALT_OUTPUTDIR=output_directory] - [other "ALT_" overrides] - -
    -
  4. -
-

- Solaris: - Note that ARCH_DATA_MODEL is really only needed on Solaris to - indicate you want to built the 64-bit version. - And before the Solaris 64-bit binaries can be used, they - must be merged with the binaries from a separate 32-bit build. - The merged binaries may then be used in either 32-bit or 64-bit mode, with - the selection occurring at runtime - with the -d32 or -d64 options. -

- - -
- -

Testing the Build

- -
-

- When the build is completed, you should see the generated - binaries and associated files in the j2sdk-image - directory in the output directory. - The default output directory is - build/platform, - where platform is one of -

    -
  • solaris-sparc
  • -
  • solaris-sparcv9
  • -
  • solaris-i586
  • -
  • solaris-amd64
  • -
  • linux-i586
  • -
  • linux-amd64
  • -
  • windows-i586
  • -
  • windows-amd64
  • -
- In particular, the - build/platform/j2sdk-image/bin - directory should contain executables for the - OpenJDK - tools and utilities. -

- You can test that the build completed properly by using the build - to run the various demos that you will find in the - build/platform/j2sdk-image/demo - directory. -

- The provided regression tests can be run with the jtreg - utility from - the jtreg site. -

- - -
- -

Environment/Make Variables

- -

-Some of the -environment or make variables (just called variables in this -document) that can impact the build are: - -

- -
- -
PATH
-
Typically you want to set the PATH to include: -
    -
  • The location of the GNU make binary
  • -
  • The location of the JDK 6 java - (see Bootstrap JDK)
  • -
  • The location of the C/C++ compilers - (see compilers)
  • -
  • The location or locations for the Unix command utilities - (e.g. /usr/bin)
  • -
-
- -
ARCH_DATA_MODEL
-
The ARCH_DATA_MODEL variable - is used to specify whether the build is to generate 32-bit or 64-bit - binaries. - The Solaris build supports either 32-bit or 64-bit builds, but - Windows and Linux will support only one, depending on the specific - OS being used. - Normally, setting this variable is only necessary on Solaris. - Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, - or to 64 for generating 64-bit binaries. -
- -
ALT_BOOTDIR
-
- The location of the bootstrap JDK installation. - See Bootstrap JDK for more information. - You should always install your own local Bootstrap JDK and - always set ALT_BOOTDIR explicitly. -
- -
ALT_OUTPUTDIR
-
- An override for specifying the (absolute) path of where the - build output is to go. - The default output directory will be build/platform. -
- -
ALT_COMPILER_PATH
-
- The location of the C/C++ compiler. - The default varies depending on the platform. -
- -
ALT_CACERTS_FILE
-
- The location of the cacerts file. - The default will refer to - jdk/src/share/lib/security/cacerts. -
- -
ALT_BINARY_PLUGS_PATH
-
- The location of the binary plugs installation. - See Binary Plugs for more information. - You should always have a local copy of a - recent Binary Plugs install image - and set this variable to that location. -
- -
ALT_CUPS_HEADERS_PATH
-
- The location of the CUPS header files. - See CUPS information for more information. - If this path does not exist the fallback path is - /usr/include. -
- - -
ALT_FREETYPE_LIB_PATH
-
- The location of the FreeType shared library. - See FreeType information for details. -
- -
ALT_FREETYPE_HEADERS_PATH
-
- The location of the FreeType header files. - See FreeType information for details. -
- -
Windows specific:
-
-
-
ALT_MSDEVTOOLS_PATH
-
- The location of the Microsoft Visual Studio .NET 2003 - tools 'bin' directory. - The default is usually derived from - ALT_COMPILER_PATH. -
- -
ALT_DXSDK_PATH
-
- The location of the - Microsoft DirectX 9 SDK. - The default will be to try and use the DirectX environment - variable DXSDK_DIR, - failing that, look in C:/DXSDK. -
- -
ALT_MSVCRT_DLL_PATH
-
- The location of the - MSVCRT.DLL. -
- -
ALT_MSVCR71_DLL_PATH
-
- i586 only: - The location of the - MSVCR71.DLL. -
-
-
- -
-
- - -
- -

Troubleshooting

- -
-

- A build can fail for any number of reasons. - Most failures - are a result of trying to build in an environment in which all the - pre-build requirements have not been met. - The first step in - troubleshooting a build failure is to recheck that you have satisfied - all the pre-build requirements for your platform. - Look for the check list of the platform you are building on in the - Table of Contents. - -

- You can validate your build environment by using the sanity - target. - Any errors listed - will stop the build from starting, and any warnings may result in - a flawed product build. - We strongly encourage you to evaluate every - sanity check warning and fix it if required, before you proceed - further with your build. - -

- Some of the more common problems with builds are briefly described - below, with suggestions for remedies. - -

    -
  • - Slow Builds: -
    -

    - If your build machine seems to be overloaded from too many - simultaneous C++ compiles, try setting the HOTSPOT_BUILD_JOBS - variable to 1 (if you're using a multiple CPU - machine, setting it to more than the the number of CPUs is probably - not a good idea). -

    - Creating the javadocs can be very slow, if you are running - javadoc, consider skipping that step. -

    - Faster hardware and more RAM always helps too. - The VM build tends to be CPU intensive (many C++ compiles), - and the rest of the JDK will often be disk intensive. -

    - Faster compiles are possible using a tool called - ccache. -

    -
  • -
  • - File time issues: -
    -

    - If you see warnings that refer to file time stamps, e.g. -

    - Warning message: File `xxx' has modification time in - the future. -
    - Warning message: Clock skew detected. Your build may - be incomplete. -
    -

    - These warnings can occur when the clock on the build machine is out of - sync with the timestamps on the source files. Other errors, apparently - unrelated but in fact caused by the clock skew, can occur along with - the clock skew warnings. These secondary errors may tend to obscure the - fact that the true root cause of the problem is an out-of-sync clock. - For example, an out-of-sync clock has been known to cause an old - version of javac to be used to compile some files, resulting in errors - when the pre-1.4 compiler ran across the new assert keyword - in the 1.4 source code. -

    - If you see these warnings, reset the clock on the build - machine, run "gmake clobber" or delete the directory - containing the build output, and restart the build from the beginning. -

    -
  • -
  • - Error message: Trouble writing out table to disk -
    -

    - Increase the amount of swap space on your build machine. -

    -
  • -
  • - Error Message: libstdc++ not found: -
    - This is caused by a missing libstdc++.a library. - This is installed as part of a specific package - (e.g. libstdc++.so.devel.386). - By default some 64bit Linux versions (e.g. Fedora) - only install the 64bit version of the libstdc++ package. - Various parts of the JDK build require a static - link of the C++ runtime libraries to allow for maximum - portability of the built images. -
    -
  • -
  • - Error Message: cannot restore segment prot after reloc -
    - This is probably an issue with SELinux (See - http://en.wikipedia.org/wiki/SELinux). - Parts of the VM is built without the -fPIC for - performance reasons. -

    - To completely disable SELinux: -

      - -
    1. $ su root
    2. -
    3. # system-config-securitylevel
    4. -
    5. In the window that appears, select the SELinux tab
    6. -
    7. Disable SELinux
    8. -
    -

    - Alternatively, instead of completely disabling it you could - disable just this one check. -

      -
    1. Select System->Administration->SELinux Management
    2. -
    3. In the SELinux Management Tool which appears, - select "Boolean" from the menu on the left
    4. -
    5. Expand the "Memory Protection" group
    6. -
    7. Check the first item, labeled - "Allow all unconfined executables to use libraries requiring text relocation ..."
    8. -
    -
    -
  • -
-
- -
diff --git a/make/README.html b/make/README.html deleted file mode 100644 index ae415b1590aeae965c18ee6e77c3a23251a7ff6c..0000000000000000000000000000000000000000 --- a/make/README.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - OpenJDK README - - -
-
-

OpenJDK README

-
- - -
- -

TBD

- -

Building the OpenJDK

- -

- Refer to the OpenJDK Build README - for build instructions. - - - -


- - - diff --git a/make/THIRD_PARTY_README b/make/THIRD_PARTY_README deleted file mode 100644 index 9f4d7e5087a200b17e0ea8778c9de8dfe892d5a2..0000000000000000000000000000000000000000 --- a/make/THIRD_PARTY_README +++ /dev/null @@ -1,1616 +0,0 @@ -DO NOT TRANSLATE OR LOCALIZE. - -%% This notice is provided with respect to Thai dictionary for text breaking, which may be included with this software: - ---- begin of LICENSE file --- - -Copyright (C) 1982 The Royal Institute, Thai Royal Government. - -Copyright (C) 1998 National Electronics and Computer Technology Center, - National Science and Technology Development Agency, - Ministry of Science Technology and Environment, - Thai Royal Government. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without -limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to -whom the Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - ---- end of LICENSE file --- -%% This notice is provided with respect to ASM, which may be included with this software: -Copyright (c) 2000-2005 INRIA, France Telecom -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. 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. - -3. Neither the name of the copyright holders nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. -%% This notice is provided with respect to zlib 1.1.3, which may be included with this software: - -Acknowledgments: - - The deflate format used by zlib was defined by Phil Katz. The deflate - and zlib specifications were written by L. Peter Deutsch. Thanks to all the - people who reported problems and suggested various improvements in zlib; - they are too numerous to cite here. - -Copyright notice: - - (C) 1995-1998 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - -If you use the zlib library in a product, we would appreciate *not* -receiving lengthy legal documents to sign. The sources are provided -for free but without warranty of any kind. The library has been -entirely written by Jean-loup Gailly and Mark Adler; it does not -include third-party code. - -If you redistribute modified sources, we would appreciate that you include -in the file ChangeLog history information documenting your changes. - -%% This notice is provided with respect to W3C (DTD for XML Signatures), which may be included with this software: -W3C® SOFTWARE NOTICE AND LICENSE -Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ -This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: -Permission to use, copy, modify, and distribute this software and its documentation, with or without modification,  for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: -1.The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. -2.Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © [$date-of-software] World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/" -3.Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) -THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. -COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. -The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. -____________________________________ -This formulation of W3C's notice and license became active on August 14 1998 so as to improve compatibility with GPL. This version ensures that W3C software licensing terms are no more restrictive than GPL and consequently W3C software may be distributed in GPL packages. See the older formulation for the policy prior to this date. Please see our Copyright FAQ for common questions about using materials from our site, including specific terms and conditions for packages like libwww, Amaya, and Jigsaw. Other questions about this notice can be directed to site-policy@w3.org. -  -%% This notice is provided with respect to jscheme.jar, which may be included with this software: -Software License Agreement -Copyright © 1998-2002 by Peter Norvig. -Permission is granted to anyone to use this software, in source or object code form, on any computer system, and to modify, compile, decompile, run, and redistribute it to anyone else, subject to the following restrictions: -1.The author makes no warranty of any kind, either expressed or implied, about the suitability of this software for any purpose. -2.The author accepts no liability of any kind for damages or other consequences of the use of this software, even if they arise from defects in the software. -3.The origin of this software must not be misrepresented, either by explicit claim or by omission. -4.Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. Altered versions may be distributed in packages under other licenses (such as the GNU license). -If you find this software useful, it would be nice if you let me (peter@norvig.com) know about it, and nicer still if you send me modifications that you are willing to share. However, you are not required to do so. - - -%% This notice is provided with respect to PC/SC Lite for Suse Linux v. 1.1.1, which may be included with this software: - -Copyright (c) 1999-2004 David Corcoran -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. 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. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -Changes to this license can be made only by the copyright author with -explicit written consent. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -%% This notice is provided with respect to IAIK PKCS Wrapper, which may be included with this software: - -Copyright (c) 2002 Graz University of Technology. All rights reserved. -Redistribution and use in source and binary forms, with or without modification,are permitted provided that the following conditions are met: - - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. 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. - -3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: - - "This product includes software developed by IAIK of Graz University of Technology." - - Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. - -4. The names "Graz University of Technology" and "IAIK of Graz University of Technology" must not be used to endorse or promote products derived from this software without prior written permission. - -5. Products derived from this software may not be called "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior written permission of Graz University of Technology. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 LICENSOR BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -%% This notice is provided with respect to Document Object Model (DOM) v. Level 3, which may be included with this software: - -W3Cýý SOFTWARE NOTICE AND LICENSE - -http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 - -This work (and included software, documentation such as READMEs, or other related items) is being -provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you -(the licensee) agree that you have read, understood, and will comply with the following terms and conditions. - -Permission to copy, modify, and distribute this software and its documentation, with or without modification, for -any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies -of the software and documentation or portions thereof, including modifications: - 1.The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. - 2.Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the - W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body - of any redistributed or derivative code. - 3.Notice of any changes or modifications to the files, including the date changes were made. (We - recommend you provide URIs to the location from which the code is derived.) -THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKENO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, -WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THEUSE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. - -COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL ORCONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. -The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the -software without specific, written prior permission. Title to copyright in this software and any associated -documentation will at all times remain with copyright holders. - -____________________________________ - -This formulation of W3C's notice and license became active on December 31 2002. This version removes the -copyright ownership notice such that this license can be used with materials other than those owned by the -W3C, reflects that ERCIM is now a host of the W3C, includes references to this specific dated version of the -license, and removes the ambiguous grant of "use". Otherwise, this version is the same as the previous -version and is written so as to preserve the Free Software Foundation's assessment of GPL compatibility and -OSI's certification under the Open Source Definition. Please see our Copyright FAQ for common questions -about using materials from our site, including specific terms and conditions for packages like libwww, Amaya, -and Jigsaw. Other questions about this notice can be directed to -site-policy@w3.org. - -%% This notice is provided with respect to Xalan, Xerces, which may be included with this software: - -/* - * The Apache Software License, Version 1.1 - * - * - * Copyright (c) 1999-2003 The Apache Software Foundation. All rights * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. * - * 2. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * - * 4. The names "Xerces" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.ibm.com. For more - * information on the Apache Software Foundation, please see - * - -%% This notice is provided with respect to JavaScript, which may be included with this software: - -AMENDMENTS -The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License.  Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1. -Additional Terms applicable to the Netscape Public License. -I. Effect. -These additional terms described in this Netscape Public License -- Amendments shall apply to the Mozilla Communicator client code and to all Covered Code under this License. -II. ''Netscape's Branded Code'' means Covered Code that Netscape distributes and/or permits others to distribute under one or more trademark(s) which are controlled by Netscape but which are not licensed for use under this License. -III. Netscape and logo. -This License does not grant any rights to use the trademarks "Netscape'', the "Netscape N and horizon'' logo or the "Netscape lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript", "Smart Browsing" even if such marks are included in the Original Code or Modifications. -IV. Inability to Comply Due to Contractual Obligation. -Prior to licensing the Original Code under this License, Netscape has licensed third party code for use in Netscape's Branded Code. To the extent that Netscape is limited contractually from making such third party code available under this License, Netscape may choose to reintegrate such code into Covered Code without being required to distribute such code in Source Code form, even if such code would otherwise be considered ''Modifications'' under this License. -V. Use of Modifications and Covered Code by Initial Developer. -V.1. In General. -The obligations of Section 3 apply to Netscape, except to the extent specified in this Amendment, Section V.2 and V.3. -V.2. Other Products. -Netscape may include Covered Code in products other than the Netscape's Branded Code which are released by Netscape during the two (2) years following the release date of the Original Code, without such additional products becoming subject to the terms of this License, and may license such additional products on different terms from those contained in this License. -V.3. Alternative Licensing. -Netscape may license the Source Code of Netscape's Branded Code, including Modifications incorporated therein, without such Netscape Branded Code becoming subject to the terms of this License, and may license such Netscape Branded Code on different terms from those contained in this License. -  -VI. Litigation. -Notwithstanding the limitations of Section 11 above, the provisions regarding litigation in Section 11(a), (b) and (c) of the License shall apply to all disputes relating to this License. - -EXHIBIT A-Netscape Public License. -  -''The contents of this file are subject to the Netscape Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/NPL/ -Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. -The Original Code is Mozilla Communicator client code, released March 31, 1998. -The Initial Developer of the Original Code is Netscape Communications Corporation. Portions created by Netscape are Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights Reserved. -Contributor(s): ______________________________________. -  -Alternatively, the contents of this file may be used under the terms of the _____ license (the  "[___] License"), in which case the provisions of [______] License are applicable  instead of those above.  If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting  the provisions above and replace  them with the notice and other provisions required by the [___] License.  If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License." - -MOZILLA PUBLIC LICENSE -Version 1.1 - -1. Definitions. -1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. -1.1. ''Contributor'' means each entity that creates or contributes to the creation of Modifications. -1.2. ''Contributor Version'' means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. -1.3. ''Covered Code'' means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. -1.4. ''Electronic Distribution Mechanism'' means a mechanism generally accepted in the software development community for the electronic transfer of data. -1.5. ''Executable'' means Covered Code in any form other than Source Code. -1.6. ''Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. -1.7. ''Larger Work'' means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. -1.8. ''License'' means this document. -1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. -1.9. ''Modifications'' means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: -A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. -B. Any new file that contains any part of the Original Code or previous Modifications. -  -1.10. ''Original Code'' means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. -1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation,  method, process, and apparatus claims, in any patent Licensable by grantor. -1.11. ''Source Code'' means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. -1.12. "You'' (or "Your")  means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You'' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control'' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. -2. Source Code License. -2.1. The Initial Developer Grant. -The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: -(a)  under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and -(b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). -  -(c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. -(d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code;  or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. -  -2.2. Contributor Grant. -Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license -  -(a)  under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and -(b) under Patent Claims infringed by the making, using, or selling of  Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of  Modifications made by that Contributor with its Contributor Version (or portions of such combination). -(c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. -(d)    Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2)  separate from the Contributor Version;  3)  for infringements caused by: i) third party modifications of Contributor Version or ii)  the combination of Modifications made by that Contributor with other software  (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. - -3. Distribution Obligations. -3.1. Application of License. -The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. -3.2. Availability of Source Code. -Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. -3.3. Description of Modifications. -You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. -3.4. Intellectual Property Matters -(a) Third Party Claims. -If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL'' which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. -(b) Contributor APIs. -If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. -  -          (c)    Representations. -Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. - -3.5. Required Notices. -You must duplicate the notice in Exhibit A in each file of the Source Code.  If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice.  If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A.  You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code.  You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. -3.6. Distribution of Executable Versions. -You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. -3.7. Larger Works. -You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. -4. Inability to Comply Due to Statute or Regulation. -If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. -5. Application of this License. -This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. -6. Versions of the License. -6.1. New Versions. -Netscape Communications Corporation (''Netscape'') may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. -6.2. Effect of New Versions. -Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. -6.3. Derivative Works. -If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL", ''NPL'' or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) -7. DISCLAIMER OF WARRANTY. -COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. -8. TERMINATION. -8.1.  This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. -8.2.  If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant")  alleging that: -(a)  such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i)  agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant.  If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. -(b)  any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. -8.3.  If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. -8.4.  In the event of termination under Sections 8.1 or 8.2 above,  all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. -9. LIMITATION OF LIABILITY. -UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. -10. U.S. GOVERNMENT END USERS. -The Covered Code is a ''commercial item,'' as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer software'' and ''commercial computer software documentation,'' as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. -11. MISCELLANEOUS. -This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. -12. RESPONSIBILITY FOR CLAIMS. -As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. -13. MULTIPLE-LICENSED CODE. -Initial Developer may designate portions of the Covered Code as "Multiple-Licensed".  "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. -``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ -Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -ANY KIND, either express or implied. See the License for the specific language governing rights and -limitations under the License. -The Original Code is ______________________________________. -The Initial Developer of the Original Code is ________________________. Portions created by - ______________________ are Copyright (C) ______ _______________________. All Rights -Reserved. -Contributor(s): ______________________________________. -Alternatively, the contents of this file may be used under the terms of the _____ license (the  "[___] License"), in which case the provisions of [______] License are applicable  instead of those above.  If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting  the provisions above and replace  them with the notice and other provisions required by the [___] License.  If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." -[NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] - -%% This notice is provided with respect to Mesa 3-D graphics library v. 5, which may be included with this software: - -Copyright (c) 2007 The Khronos Group Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. - -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - -%% This notice is provided with respect to Byte Code Engineering Library (BCEL), which may be included with this software: - - Apache Software License - - /* -==================================================================== * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. Allrights - * reserved. - * - * Redistribution and use in source and binary forms, withor without - * modification, are permitted provided that the followingconditions - * are met: - * - * 1. Redistributions of source code must retain the abovecopyright - * notice, this list of conditions and the followingdisclaimer. - * - * 2. Redistributions in binary form must reproduce theabove copyright - * notice, this list of conditions and the followingdisclaimer in - * the documentation and/or other materials providedwith the - * distribution. - * - * 3. The end-user documentation included with theredistribution, - * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation -(http://www.apache.org/)." - * Alternately, this acknowledgment may appear in thesoftware itself, - * if and wherever such third-party acknowledgmentsnormally appear. - * - * 4. The names "Apache" and "Apache Software Foundation"and - * "Apache BCEL" must not be used to endorse or promoteproducts - * derived from this software without prior writtenpermission. For - * written permission, please contact apache@apache.org. * - * 5. Products derived from this software may not be called"Apache", - * "Apache BCEL", nor may "Apache" appear in their name,without - * prior written permission of the Apache SoftwareFoundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED ORIMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDWARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWAREFOUNDATION OR - * ITS 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) HOWEVERCAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTLIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING INANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF - * SUCH DAMAGE. - * -==================================================================== * - * This software consists of voluntary contributions madeby many - * individuals on behalf of the Apache Software -Foundation. For more - * information on the Apache Software Foundation, pleasesee - * . - */ - -%% This notice is provided with respect to Regexp, Regular Expression Package, which may be included with this software: - -The Apache Software License, Version 1.1 -Copyright (c) 2001 The Apache Software Foundation. All rights -reserved. -Redistribution and use in source and binary forms, with or without modification,are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -2. 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. - -3. The end-user documentation included with the redistribution, -if any, must include the following acknowledgment: -"This product includes software developed by the -Apache Software Foundation (http://www.apache.org/)." -Alternately, this acknowledgment may appear in the software itself, -if and wherever such third-party acknowledgments normally appear. - -4. The names "Apache" and "Apache Software Foundation" and -"Apache Turbine" must not be used to endorse or promote products -derived from this software without prior written permission. For -written permission, please contact apache@apache.org. - -5. Products derived from this software may not be called "Apache", -"Apache Turbine", nor may "Apache" appear in their name, without -prior written permission of the Apache Software Foundation. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR -ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -==================================================================== -This software consists of voluntary contributions made by many -individuals on behalf of the Apache Software Foundation. For more -information on the Apache Software Foundation, please see - -http://www.apache.org. - -%% This notice is provided with respect to CUP Parser Generator for Java, which may be included with this software: - -CUP Parser Generator Copyright Notice, License, and Disclaimer - -Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, provided thatthe above copyright notice appear in all copies and that both the copyrightnotice and this permission notice and warranty disclaimer appear in -supporting documentation, and that the names of the authors or their employersnot be used in advertising or publicity pertaining to distribution of -the software without specific, written prior permission. - -The authors and their employers disclaim all warranties with regard to thissoftware, including all implied warranties of merchantability and -fitness. In no event shall the authors or their employers be liable for anyspecial, indirect or consequential damages or any damages whatsoever -resulting from loss of use, data or profits, whether in an action of contract,negligence or other tortious action, arising out of or in connection withthe use or performance of this software. - -%% This notice is provided with respect to SAX v. 2.0.1, which may be included with this software: - -Copyright Status - - SAX is free! - - In fact, it's not possible to own a license to SAX, since it's been placed in the public - domain. - - No Warranty - - Because SAX is released to the public domain, there is no warranty for the design or for - the software implementation, to the extent permitted by applicable law. Except when - otherwise stated in writing the copyright holders and/or other parties provide SAX "as is" - without warranty of any kind, either expressed or implied, including, but not limited to, the - implied warranties of merchantability and fitness for a particular purpose. The entire risk as - to the quality and performance of SAX is with you. Should SAX prove defective, you - assume the cost of all necessary servicing, repair or correction. - - In no event unless required by applicable law or agreed to in writing will any copyright - holder, or any other party who may modify and/or redistribute SAX, be liable to you for - damages, including any general, special, incidental or consequential damages arising out of - the use or inability to use SAX (including but not limited to loss of data or data being - rendered inaccurate or losses sustained by you or third parties or a failure of the SAX to - operate with any other programs), even if such holder or other party has been advised of - the possibility of such damages. - - Copyright Disclaimers - - This page includes statements to that effect by David Megginson, who would have been - able to claim copyright for the original work. - SAX 1.0 - - Version 1.0 of the Simple API for XML (SAX), created collectively by the membership of - the XML-DEV mailing list, is hereby released into the public domain. - - No one owns SAX: you may use it freely in both commercial and non-commercial - applications, bundle it with your software distribution, include it on a CD-ROM, list the - source code in a book, mirror the documentation at your own web site, or use it in any - other way you see fit. - - David Megginson, sax@megginson.com - 1998-05-11 - - SAX 2.0 - - I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and release - all of the SAX 2.0 source code, compiled code, and documentation contained in this - distribution into the Public Domain. SAX comes with NO WARRANTY or guarantee of - fitness for any purpose. - - David Megginson, david@megginson.com - 2000-05-05 - -%% This notice is provided with respect to Cryptix, which may be included with this software: - -Cryptix General License - -Copyright © 1995-2003 The Cryptix Foundation Limited. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions aremet: - - 1.Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2.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. -THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS ORIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FORA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOTLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESSINTERRUPTION) 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 OFTHE POSSIBILITY OF SUCH DAMAGE. - -%% This notice is provided with respect to X Window System, which may be included with this software: - -Copyright The Open Group - -Permission to use, copy, modify, distribute, and sell this software and itsdocumentation for any purpose is hereby granted without fee, provided that theabove copyright notice appear in all copies and that both that copyright noticeand this permission notice appear in supporting documentation. - -The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESSFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUPBE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OFCONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. - -Portions also covered by other licenses as noted in the above URL. - -%% This notice is provided with respect to Retroweaver, which may be included with this software: - -Copyright (c) February 2004, Toby Reyelts -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 Toby Reyelts nor the names of his 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, STRICTLIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -%% This notice is provided with respect to stripper, which may be included with this software: - -Stripper : debug information stripper - Copyright (c) 2003 Kohsuke Kawaguchi - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. 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. 3. Neither the name of the copyright holders nor the names of its - contributors may be used to endorse or promote products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -%% This notice is provided with respect to libpng official PNG reference library, which may be included with this software: - -This copy of the libpng notices is provided for your convenience. In case ofany discrepancy between this copy and the notices in the file png.h that isincluded in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately followingthis sentence. - -libpng version 1.2.6, December 3, 2004, is -Copyright (c) 2004 Glenn Randers-Pehrson, and is -distributed according to the same disclaimer and license as libpng-1.2.5with the following individual added to the list of Contributing Authors - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, areCopyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6with the following individuals added to the list of Contributing Authors - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, areCopyright (c) 1998, 1999 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-0.96,with the following individuals added to the list of Contributing Authors: - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88,with the following individuals added to the list of Contributing Authors: - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors"is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authorsand Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and offitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary,or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute thissource code, or portions hereof, for any purpose, without fee, subjectto the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, withoutfee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use thissource code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about"boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is acertification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -December 3, 2004 - -%% This notice is provided with respect to Libungif - An uncompressed GIF library, which may be included with this software: - -The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond - -Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE. - -%% This notice is provided with respect to XML Resolver library, Xalan J2, and StAX API, which may be included with this software: - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - -%% Some Portions licensed from IBM are available at: -http://www.ibm.com/software/globalization/icu/ - -%% This notice is provided with respect to ICU4J, ICU 1.8.1 and later, which may be included with this software: - -ICU License - ICU 1.8.1 and later COPYRIGHT AND PERMISSION NOTICE Cop -yright (c) -1995-2003 International Business Machines Corporation and others All rightsreserved. Permission is hereby granted, free of charge, to any person obtaininga copy of this software and associated documentation files (the "Software"), todeal in the Software without restriction, including without limitation therights to use, copy, modify, merge, publish, distribute, and/or sell copies ofthe Software, and to permit persons to whom the Software is furnished to do so,provided that the above copyright notice(s) and this permission notice appear inall copies of the Software and that both the above copyright notice(s) and thispermission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOTLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSEAND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHTHOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY C - LAIM, OR ANYSPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTINGFROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCEOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE ORPERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of acopyright holder shall not be used in advertising or otherwise to promote thesale, use or other dealings in this Software without prior written authorizationof the copyright holder. - -%% This notice is provided with respect to Jing, which may be included with this software: - -Jing Copying Conditions - -Copyright (c) 2001-2003 Thai Open Source Software Center Ltd -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/orother materials provided with the distribution. - * Neither the name of the Thai Open Source Software Center Ltd nor the namesof its contributors may be used to endorse or promote products derived from thissoftware without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ANDANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AREDISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANYDIRECT, 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 ONANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THISSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -%% This notice is provided with respect to RELAX NG Object Model/Parser, which may be included with this software: - - -The MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy ofthis software and associated documentation files (the "Software"), to deal inthe Software without restriction, including without limitation the rights touse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies ofthe Software, and to permit persons to whom the Software is furnished to do so,subject to the following conditions: - -The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESSFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS ORCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHERIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR INCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -%% This notice is provided with respect to XFree86-VidMode Extension, which may be included with this software: - -Version 1.1 of XFree86 ProjectLicence. - - Copyright (C) 1994-2004 The XFree86 Project, Inc. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to deal inthe Software without restriction, including without limitation the rights touse, copy, modify, merge, publish, distribute, sublicence, and/or sell copies ofthe Software, and to permit persons to whom the Software is furnished to do so,subject to the following conditions: - - 1. Redistributions of source code must retain the above copyright notice,this list of conditions, and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyrightnotice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution, and in thesame place and form as other copyright, license and disclaimer information. 3. The end-user documentation included with the redistribution, if any,must include the following acknowledgment: "This product includes softwaredeveloped by The XFree86 Project, Inc (http://www.xfree86.org/) and itscontributors", in the same place and form as other third-party acknowledgments.Alternately, this acknowledgment may appear in the software itself, in the sameform and location as other such third-party acknowledgments. - 4. Except as contained in this notice, the name of The XFree86 Project,Inc shall not be used in advertising or otherwise to promote the sale, use orother dealings in this Software without prior written authorization from TheXFree86 Project, Inc. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ANDFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XFREE86PROJECT, INC OR ITS 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; ORBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISINGIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITYOF SUCH DAMAGE. - -%% This notice is provided with respect to XML Security, which may be included with this software: - - The Apache Software License, - Version 1.1 - - - PDF - - - Copyright (C) 2002 The Apache SoftwareFoundation. - All rights reserved. Redistribution anduse in - source and binary forms, with or withoutmodifica- - tion, are permitted provided that thefollowing - conditions are met: 1. Redistributions ofsource - code must retain the above copyrightnotice, this - list of conditions and the followingdisclaimer. - 2. Redistributions in binary form mustreproduce - the above copyright notice, this list of conditions and the following disclaimerin the - documentation and/or other materialsprovided with - the distribution. 3. The end-userdocumentation - included with the redistribution, if any,must - include the following acknowledgment:"This - product includes software developed bythe Apache - Software Foundation -(http://www.apache.org/)." - Alternately, this acknowledgment mayappear in the - software itself, if and wherever suchthird-party - acknowledgments normally appear. 4. Thenames - "Apache Forrest" and "Apache SoftwareFoundation" - must not be used to endorse or promoteproducts - derived from this software without priorwritten - permission. For written permission,please contact - apache@apache.org. 5. Products derivedfrom this - software may not be called "Apache", normay - "Apache" appear in their name, withoutprior - written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED``AS IS'' - AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEIMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESSFOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NOEVENT - SHALL THE APACHE SOFTWARE FOUNDATION ORITS - CONTRIBUTORS BE LIABLE FOR ANY DIRECT,INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL - DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ORSERVICES; LOSS - OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANYTHEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICTLIABILITY, - OR TORT (INCLUDING NEGLIGENCE OROTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF - SUCH DAMAGE. This software consists ofvoluntary - contributions made by many individuals onbehalf - of the Apache Software Foundation. Formore - information on the Apache SoftwareFoundation, - please see . - -%% This notice is provided with respect to Independent JPEG Group's software (libjpeg), which may be included with this software: - -In plain English: - -1. We don't promise that this software works. (But if you find any bugs, - please let us know!) -2. You can use this software for whatever you want. You don't have to pay us. -3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. - -In legalese: - -The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. - -This software is copyright (C) 1991-1998, Thomas G. Lane. -All Rights Reserved except as specified below. - -Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: - -(1) If any part of the source code for this software is distributed, then this -README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. - -(2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". - -(3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. - -These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. - -Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". - -We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. - -ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. ansi2knr.c is NOT covered by the above copyright and conditions, but instead by the usual distribution terms of the Free Software Foundation; principally, that you must include source code if you redistribute it. (See the file ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part of any program generated from the IJG code, this does not limit you more than the foregoing paragraphs do. - -The Unix configuration script "configure" was produced with GNU Autoconf. It is copyright by the Free Software Foundation but is freely distributable. The same holds for its supporting scripts (config.guess, config.sub, ltconfig, ltmain.sh). Another support script, install-sh, is copyright by M.I.T. but is also freely distributable. - -It appears that the arithmetic coding option of the JPEG spec is covered by patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot legally be used without obtaining one or more licenses. For this reason, support for arithmetic coding has been removed from the free JPEG software. (Since arithmetic coding provides only a marginal gain over the unpatented Huffman mode, it is unlikely that very many implementations will support it.) So far as we are aware, there are no patent restrictions on the remaining code. - -The IJG distribution formerly included code to read and write GIF files. To avoid entanglement with the Unisys LZW patent, GIF reading support has been removed altogether, and the GIF writer has been simplified to produce "uncompressed GIFs". This technique does not use the LZW algorithm; the resulting GIF files are larger than usual, but are readable by all standard GIF decoders. - -We are required to state that - "The Graphics Interchange Format(c) is the Copyright property of - CompuServe Incorporated. GIF(sm) is a Service Mark property of - CompuServe Incorporated." - -%% This notice is provided with respect to X Resize and Rotate (Xrandr) Extension, which may be included with this software: -2. XFree86 License - -XFree86 code without an explicit copyright is covered by the following -copyright/license: - -Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 -PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the XFree86 Project shall not be -used in advertising or otherwise to promote the sale, use or other dealings in -this Software without prior written authorization from the XFree86 Project. - -%% This notice is provided with respect to fontconfig, which may be included with this software: -Id: COPYING,v 1.3 2003/04/04 20:17:40 keithp Exp $ -Copyright 2001,2003 Keith Packard - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation, and that the name of Keith Packard not be used in -advertising or publicity pertaining to distribution of the software without -specific, written prior permission. Keith Packard makes no -representations about the suitability of this software for any purpose. It -is provided "as is" without express or implied warranty. - -KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO -EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR -CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -%% This notice is provided with respect to XFree86, which may be included with this software: -Copyright (C) 1994-2002 The XFree86 Project, Inc. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated -documentation files (the "Software"), to deal in the Software without -restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the XFree86 Project shall not be -used in advertising or otherwise -to promote the sale, use or other dealings in this Software without prior -written authorization from the XFree86 -Project. -%% This notice is provided with respect to Fast Infoset, which may be included with this software: -* Fast Infoset ver. 0.1 software ("Software") -* -* Copyright, 2004-2005 Sun Microsystems, Inc. All Rights Reserved. -* -* Software is licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. You may -* obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations. -* -* Sun supports and benefits from the global community of open source -* developers, and thanks the community for its important contributions and -* open standards-based technology, which Sun has adopted into many of its -* products. -* -* Please note that portions of Software may be provided with notices and -* open source licenses from such communities and third parties that govern the -* use of those portions, and any licenses granted hereunder do not alter any -* rights and obligations you may have under such open source licenses, -* however, the disclaimer of warranty and limitation of liability provisions -* in this License will apply to all Software in this distribution. -* -* You acknowledge that the Software is not designed, licensed or intended -* for use in the design, construction, operation or maintenance of any nuclear -* facility. -* -* Apache License -* Version 2.0, January 2004 -* http://www.apache.org/licenses/ -* -*/ -/* -* ==================================================================== -* -* This code is subject to the freebxml License, Version 1.1 -* -* Copyright (c) 2001 - 2005 freebxml.org. All rights reserved. -* -* $Header: /cvs/fi/FastInfoset/src/com/sun/xml/internal/fastinfoset/AbstractResourceBundle.java,v 1.2 -*  ==================================================================== -*/ -%% This notice is provided with respect to Kerberos, which may be included with this software: - -/* - * Copyright (C) 1998 by the FundsXpress, INC. - * - * All rights reserved. - * - * Export of this software from the United States of America may require - * a specific license from the United States Government.  It is the - * responsibility of any person or organization contemplating export to - * obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of FundsXpress. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. FundsXpress makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -%% This notice is provided with respect to Unicode's CLDR data repository, which may be included with this software: - - Unicode Copyright - - For the general privacy policy governing access to this site, see the -Unicode Privacy Policy. For trademark usage, see the the Unicode Consortium -Trademarks and Logo Policy. - Notice to End User: Terms of Use - Carefully read the following legal agreement ("Agreement"). Use or copying -of the software and/or codes provided with this agreement (The "Software") -constitutes your acceptance of these terms - - 1. Unicode Copyright. - 1. Copyright © 1991-2005 Unicode, Inc. All rights reserved. - 2. Certain documents and files on this website contain a legend -indicating that "Modification is permitted." Any person is hereby authorized, -without fee, to modify such documents and files to create derivative works -conforming to the Unicode® Standard, subject to Terms and Conditions herein. - 3. Any person is hereby authorized, without fee, to view, use, -reproduce, and distribute all documents and files solely for informational -purposes in the creation of products supporting the Unicode Standard, subject to -the Terms and Conditions herein. - 4. Further specifications of rights and restrictions pertaining to -the use of the particular set of data files known as the "Unicode Character -Database" can be found in Exhibit 1. - 5. Further specifications of rights and restrictions pertaining to -the use of the particular set of files that constitute the online edition of The -Unicode Standard, Version 4.0, may be found in V4.0 online edition. - 6. No license is granted to "mirror" the Unicode website where a -fee is charged for access to the "mirror" site. - 7. Modification is not permitted with respect to this document. All -copies of this document must be verbatim. - 2. Restricted Rights Legend. Any technical data or software which is -licensed to the United States of America, its agencies and/or instrumentalities -under this Agreement is commercial technical data or commercial computer -software developed exclusively at private expense as defined in FAR 2.101, or -DFARS 252.227-7014 (June 1995), as applicable. For technical data, use, -duplication, or disclosure by the Government is subject to restrictions as set -forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov 1995) and -this Agreement. For Software, in accordance with FAR 12-212 or DFARS 227-7202, -as applicable, use, duplication or disclosure by the Government is subject to -the restrictions set forth in this Agreement. - 3. Warranties and Disclaimers. - 1. This publication and/or website may include technical or -typographical errors or other inaccuracies . Changes are periodically added to -the information herein; these changes will be incorporated in new editions of -the publication and/or website. Unicode may make improvements and/or changes in -the product(s) and/or program(s) described in this publication and/or website at -any time. - 2. If this file has been purchased on magnetic or optical media -from Unicode, Inc. the sole and exclusive remedy for any claim will be exchange -of the defective media within ninety (90) days of original purchase. - 3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR -SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, -IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. UNICODE -AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR OMISSIONS IN THIS -PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH ARE REFERENCED BY OR LINKED -TO THIS PUBLICATION OR THE UNICODE WEBSITE. - 4. Waiver of Damages. In no event shall Unicode or its licensors be -liable for any special, incidental, indirect or consequential damages of any -kind, or any damages whatsoever, whether or not Unicode was advised of the -possibility of the damage, including, without limitation, those resulting from -the following: loss of use, data or profits, in connection with the use, -modification or distribution of this information or its derivatives. - 5. Trademarks. - 1. Unicode and the Unicode logo are registered trademarks of -Unicode, Inc. - 2. This site contains product names and corporate names of other -companies. All product names and company names and logos mentioned herein are -the trademarks or registered trademarks of their respective owners. Other -products and corporate names mentioned herein which are trademarks of a third -party are used only for explanation and for the owners' benefit and with no -intent to infringe. - 3. Use of third party products or information referred to herein is -at the user's risk. - 6. Miscellaneous. - 1. Jurisdiction and Venue. This server is operated from a location -in the State of California, United States of America. Unicode makes no -representation that the materials are appropriate for use in other locations. If -you access this server from other locations, you are responsible for compliance -with local laws. This Agreement, all use of this site and any claims and damages -resulting from use of this site are governed solely by the laws of the State of -California without regard to any principles which would apply the laws of a -different jurisdiction. The user agrees that any disputes regarding this site -shall be resolved solely in the courts located in Santa Clara County, -California. The user agrees said courts have personal jurisdiction and agree to -waive any right to transfer the dispute to any other forum. - 2. Modification by Unicode Unicode shall have the right to modify -this Agreement at any time by posting it to this site. The user may not assign -any part of this Agreement without Unicode's prior written consent. - 3. Taxes. The user agrees to pay any taxes arising from access to -this website or use of the information herein, except for those based on -Unicode's net income. - 4. Severability. If any provision of this Agreement is declared -invalid or unenforceable, the remaining provisions of this Agreement shall -remain in effect. - 5. Entire Agreement. This Agreement constitutes the entire -agreement between the parties. - -EXHIBIT 1 -UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE - - Unicode Data Files include all data files under the directories -http://www.unicode.org/Public/ and http://www.unicode.org/reports/. Unicode -Software includes any source code under the directories -http://www.unicode.org/Public/ and http://www.unicode.org/reports/. - - NOTICE TO USER: Carefully read the following legal agreement. BY -DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES -("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND -AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU -DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES -OR SOFTWARE. - - COPYRIGHT AND PERMISSION NOTICE - - Copyright Ã?Â,Ã,© 1991-2004 Unicode, Inc. All rights reserved. Distributed under -the Terms of Use in http://www.unicode.org/copyright.html. - - Permission is hereby granted, free of charge, to any person obtaining a copy -of the Unicode data files and associated documentation (the "Data Files") or -Unicode software and associated documentation (the "Software") to deal in the -Data Files or Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files or -Software are furnished to do so, provided that (a) the above copyright notice(s) -and this permission notice appear with all copies of the Data Files or Software, -(b) both the above copyright notice(s) and this permission notice appear in -associated documentation, and (c) there is clear notice in each modified Data -File or in the Software as well as in the documentation associated with the Data -File(s) or Software that the data or software has been modified. - - THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD -PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. - - Except as contained in this notice, the name of a copyright holder shall not -be used in advertising or otherwise to promote the sale, use or other dealings -in these Data Files or Software without prior written authorization of the -copyright holder. - - Unicode and the Unicode logo are trademarks of Unicode, Inc., and may be -registered in some jurisdictions. All other trademarks and registered trademarks -mentioned herein are the property of their respective owners. -%% This notice is provided with respect to RSA PKCS#11 Header Files & Specification, which may be included with this software: - -/* - * Copyright (C) 1998 by the FundsXpress, INC. - * - * All rights reserved. - * - * Export of this software from the United States of America may require - * a specific license from the United States Government.  It is the - * responsibility of any person or organization contemplating export to - * obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of FundsXpress. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission.  FundsXpress makes no representations about the suitability of - * this software for any purpose.  It is provided "as is" without express - * or implied warranty. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -%% This notice is provided with respect to certain files/code which may included in the implementation of AWT within the software: - -****************************************************** -BEGIN  src/solaris/native/sun/awt/HPkeysym.h -Copyright 1987, 1998  The Open Group - -All Rights Reserved. - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization -from The Open Group. - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, - -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the names of Hewlett Packard -or Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD -TO THIS SOFWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE.  Hewlett-Packard shall not be liable for errors -contained herein or direct, indirect, special, incidental or -consequential damages in connection with the furnishing, -performance, or use of this material. - -END  src/solaris/native/sun/awt/HPkeysym.h -****************************************************** -****************************************************** -BEGIN src/solaris/native/sun/awt/Xrandr.h -/* - * $XFree86: xc/lib/Xrandr/Xrandr.h,v 1.9 2002/09/29 23:39:44 keithp Exp $ - * - * Copyright © 2000 Compaq Computer Corporation, Inc. - * Copyright © 2002 Hewlett-Packard Company, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Compaq not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission.  HP makes no representations about the - * suitability of this software for any purpose.  It is provided "as is" - * without express or implied warranty. - * - * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ - * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author:  Jim Gettys, HP Labs, HP. - */ - - -END src/solaris/native/sun/awt/Xrandr.h -****************************************************** -BEGIN src/solaris/native/sun/awt/extutil.h -/* - * $Xorg: extutil.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $ - * -Copyright 1989, 1998  The Open Group - -All Rights Reserved. - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - * - * Author:  Jim Fulton, MIT The Open Group - * - *                     Xlib Extension-Writing Utilities - * - * This package contains utilities for writing the client API for various - * protocol extensions.  THESE INTERFACES ARE NOT PART OF THE X STANDARD AND - * ARE SUBJECT TO CHANGE! - */ -/* $XFree86: xc/include/extensions/extutil.h,v 1.5 2001/01/17 17:53:20 dawes Exp $ */ - -END src/solaris/native/sun/awt/extutil.h -****************************************************** -BEGIN   src/solaris/native/sun/awt/fontconfig.h -/* - * $RCSId: xc/lib/fontconfig/fontconfig/fontconfig.h,v 1.30 2002/09/26 00:17:27 -keithp Exp $ - * - * Copyright © 2001 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission.  Keith Packard makes no - * representations about the suitability of this software for any purpose.  It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - -END   src/solaris/native/sun/awt/fontconfig.h -****************************************************** -BEGIN src/solaris/native/sun/awt/list.c -AND  src/solaris/native/sun/awt/list.h -AND src/solaris/native/sun/awt/multiVis.c -AND  src/solaris/native/sun/awt/multiVis.h -AND  src/solaris/native/sun/awt/wsutils.h - -Copyright (c) 1994 Hewlett-Packard Co. -Copyright (c) 1996  X Consortium - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the X Consortium shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization -from the X Consortium. - -END src/solaris/native/sun/awt/list.c -AND  src/solaris/native/sun/awt/list.h -AND src/solaris/native/sun/awt/multiVis.c -AND  src/solaris/native/sun/awt/multiVis.h -AND  src/solaris/native/sun/awt/wsutils.h - -***************************************************************** -BEGIN src/solaris/native/sun/awt/randr.h - - * - * Copyright © 2000, Compaq Computer Corporation, - * Copyright © 2002, Hewlett Packard, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Compaq or HP not be used in advertising - * or publicity pertaining to distribution of the software without specific, - * written prior permission.  HP makes no representations about the - * suitability of this software for any purpose.  It is provided "as is" - * without express or implied warranty. - * - * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HP - * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author:  Jim Gettys, HP Labs, Hewlett-Packard, Inc. - -END src/solaris/native/sun/awt/randr.h -***************************************************** - -BEGIN src/solaris/native/sun/java2d/opengl/J2D_GL/glx.h - * Mesa 3-D graphics library - * Version:  4.1 - * - * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -END src/solaris/native/sun/java2d/opengl/J2D_GL/glx.h diff --git a/make/com/sun/crypto/provider/Makefile b/make/com/sun/crypto/provider/Makefile index 64e4320b19a90dba7e346fb9746847c1a18e9d69..f8134de149ba9352fa66124341afc959b0fde82b 100644 --- a/make/com/sun/crypto/provider/Makefile +++ b/make/com/sun/crypto/provider/Makefile @@ -193,7 +193,7 @@ build-jar: $(UNSIGNED_DIR)/sunjce_provider.jar $(UNSIGNED_DIR)/sunjce_provider.jar: build $(JCE_MANIFEST_FILE) $(prep-target) $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) @@ -253,7 +253,7 @@ endif @$(CD) $(OBFUS_DIR); $(java-vm-cleanup) $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ -C $(OBFUS_DIR)/build com \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) $(sign-target) @$(java-vm-cleanup) diff --git a/make/com/sun/inputmethods/indicim/Makefile b/make/com/sun/inputmethods/indicim/Makefile index 638854a0b379d81e284dce8b61cd7ad48fca2666..e6e7c0dfdf20cd5ca8948f37e2d53caf3c588a66 100644 --- a/make/com/sun/inputmethods/indicim/Makefile +++ b/make/com/sun/inputmethods/indicim/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2002-2006 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 @@ -71,7 +71,7 @@ $(IMJAR): $(FILES_class) $(FILES_copy) $(PROVIDER_CONF_FILE) $(BOOT_JAR_CMD) -cf $@ \ -C $(CLASSDESTDIR) com \ -C $(CLASSDESTDIR) $(SERVICESDIR) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) clean:: diff --git a/make/com/sun/inputmethods/thaiim/Makefile b/make/com/sun/inputmethods/thaiim/Makefile index e565319aaf8aebbfaf23834319d6bb92e3ef1e39..d4f47a69d5339e10e963d8d35a78fcb912282873 100644 --- a/make/com/sun/inputmethods/thaiim/Makefile +++ b/make/com/sun/inputmethods/thaiim/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2002-2006 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 @@ -71,7 +71,7 @@ $(IMJAR): $(FILES_class) $(FILES_copy) $(PROVIDER_CONF_FILE) $(BOOT_JAR_CMD) -cf $@ \ -C $(CLASSDESTDIR) com \ -C $(CLASSDESTDIR) $(SERVICESDIR) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) clean:: diff --git a/make/com/sun/java/pack/Makefile b/make/com/sun/java/pack/Makefile index 9229e3f4c99dfb0e00b4d538f30fdfab164da1fd..c8b4e990984a2cc24cef84542f9540d2f95fc45e 100644 --- a/make/com/sun/java/pack/Makefile +++ b/make/com/sun/java/pack/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/make/com/sun/security/auth/module/Makefile b/make/com/sun/security/auth/module/Makefile index d9f705d4df7e5778bc7b13179993d227e3943144..d7a4abdf1652e7c334f9809ab6b56ebcc161900e 100644 --- a/make/com/sun/security/auth/module/Makefile +++ b/make/com/sun/security/auth/module/Makefile @@ -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 diff --git a/make/common/BuildToolJar.gmk b/make/common/BuildToolJar.gmk index 7d4ad4169fccef6c3ef4a4c2ad8955a347ddbc14..2c5ad8e3f6e528c99e276dbaec8e7f11ccbaa65d 100644 --- a/make/common/BuildToolJar.gmk +++ b/make/common/BuildToolJar.gmk @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 @@ -46,7 +46,7 @@ $(BUILDTOOL_JAR_FILE): $(BUILDTOOL_MANIFEST_FILE) \ -sourcepath $(BUILDTOOL_SOURCE_ROOT) $(BUILDTOOL_MAIN_SOURCE_FILE) $(BOOT_JAR_CMD) cfm $@ $(BUILDTOOL_MANIFEST_FILE) \ -C $(BUILDTOOLCLASSDIR) $(PKGDIR) \ - $(JAR_JFLAGS) || $(RM) $@ + $(BOOT_JAR_JFLAGS) || $(RM) $@ @$(java-vm-cleanup) # Printing out a build tool information line diff --git a/make/common/Defs-linux.gmk b/make/common/Defs-linux.gmk index 65814ba472a3d92e135b90dd1d9c6894f6bd76e1..28d58376fe279f7fb831a455e6520601181846c4 100644 --- a/make/common/Defs-linux.gmk +++ b/make/common/Defs-linux.gmk @@ -86,18 +86,22 @@ HPIS = native # # Default optimization # -CC_HIGHEST_OPT = -O3 -CC_HIGHER_OPT = -O3 -CC_LOWER_OPT = -O2 -CC_NO_OPT = -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) - CPPFLAGS_DBG += -DLOGGING +ifndef OPTIMIZATION_LEVEL + ifeq ($(PRODUCT), java) + OPTIMIZATION_LEVEL = HIGHER + else + OPTIMIZATION_LEVEL = LOWER + endif endif +CC_OPT/NONE = +CC_OPT/LOWER = -O2 +CC_OPT/HIGHER = -O3 +CC_OPT/HIGHEST = -O3 + +CC_OPT = $(CC_OPT/$(OPTIMIZATION_LEVEL)) + # For all platforms, do not omit the frame pointer register usage. # We need this frame pointer to make it easy to walk the stacks. # This should be the default on X86, but ia64 and amd64 may not have this @@ -112,18 +116,6 @@ LDFLAGS_COMMON_sparc += -m32 -mcpu=v9 CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) -# Add in platform specific optimizations for all opt levels -CC_HIGHEST_OPT += $(_OPT_$(ARCH)) -CC_HIGHER_OPT += $(_OPT_$(ARCH)) -CC_LOWER_OPT += $(_OPT_$(ARCH)) - -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) -endif - # # Selection of warning messages # @@ -162,19 +154,19 @@ ifeq ($(FASTDEBUG), true) endif endif -CFLAGS_OPT = $(POPT) +CFLAGS_OPT = $(CC_OPT) CFLAGS_DBG = $(DEBUG_FLAG) CFLAGS_COMMON += $(CFLAGS_REQUIRED) CXXFLAGS_COMMON = $(GLOBAL_KPIC) -DCC_NOEX $(GCC_WARNINGS) -CXXFLAGS_OPT = $(POPT) +CXXFLAGS_OPT = $(CC_OPT) CXXFLAGS_DBG = $(DEBUG_FLAG) CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) # FASTDEBUG: Optimize the code in the -g versions, gives us a faster debug java ifeq ($(FASTDEBUG), true) - CFLAGS_DBG += $(CC_LOWER_OPT) - CXXFLAGS_DBG += $(CC_LOWER_OPT) + CFLAGS_DBG += $(CC_OPT/LOWER) + CXXFLAGS_DBG += $(CC_OPT/LOWER) endif CPPFLAGS_COMMON = -D$(ARCH) -DARCH='"$(ARCH)"' -DLINUX $(VERSION_DEFINES) \ @@ -186,6 +178,9 @@ endif CPPFLAGS_OPT = CPPFLAGS_DBG = -DDEBUG +ifneq ($(PRODUCT), java) + CPPFLAGS_DBG += -DLOGGING +endif ifdef LIBRARY # Libraries need to locate other libraries at runtime, and you can tell diff --git a/make/common/Defs-solaris.gmk b/make/common/Defs-solaris.gmk index d0874e4307023e6539ffcfac86ac31b78effad5e..9b5cc8b721bf830bf932f134d23e1c960d4ba509 100644 --- a/make/common/Defs-solaris.gmk +++ b/make/common/Defs-solaris.gmk @@ -86,15 +86,16 @@ HPIS = native # # Java default optimization (-x04/-O2) etc. Applies to the VM. # -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) - CPPFLAGS_DBG += -DLOGGING -DDBINFO +ifndef OPTIMIZATION_LEVEL + ifeq ($(PRODUCT), java) + OPTIMIZATION_LEVEL = HIGHER + else + OPTIMIZATION_LEVEL = LOWER + endif endif # -# If -Xa is in CFLAGS_COMMON it will end up ahead of $(POPT) for the +# If -Xa is in CFLAGS_COMMON it will end up ahead of $(CC_OPT) for the # optimized build, and that ordering of the flags completely freaks # out cc. Hence, -Xa is instead in each CFLAGS variant. # @@ -123,8 +124,8 @@ endif # # Debug flag for C and C++ compiler # -CFLAGS_DEBUG_OPTION=-g -CXXFLAGS_DEBUG_OPTION=-g +CFLAGS_DEBUG_OPTION = -g $(CC_OPT/NONE) +CXXFLAGS_DEBUG_OPTION = -g $(CXX_OPT/NONE) # Turn off -g if we are doing tcov build ifdef TCOV_BUILD @@ -142,9 +143,8 @@ endif # Performance/size of files should be about the same, maybe smaller. # ifeq ($(FASTDEBUG), true) - CC_FASTDEBUG_OPT = $(CC_LOWER_OPT) - CFLAGS_DEBUG_OPTION = -g $(CC_FASTDEBUG_OPT) - CXXFLAGS_DEBUG_OPTION = -g0 $(CC_FASTDEBUG_OPT) + CFLAGS_DEBUG_OPTION = -g $(CC_OPT/LOWER) + CXXFLAGS_DEBUG_OPTION = -g0 $(CXX_OPT/LOWER) endif CFLAGS_COMMON = -L$(OBJDIR) @@ -160,7 +160,7 @@ CFLAGS_COMMON += -errshort=tags CXXFLAGS_COMMON += -errtags=yes # Optimization flags -CFLAGS_OPT = $(POPT) +CFLAGS_OPT = $(CC_OPT) # Debug version flags CFLAGS_DBG = $(CFLAGS_DEBUG_OPTION) @@ -197,7 +197,7 @@ ifeq ($(COMPILER_WARNINGS_FATAL),true) CXXFLAGS_COMMON += -errwarn=%all endif -CXXFLAGS_OPT = $(POPT) +CXXFLAGS_OPT = $(CXX_OPT) CXXFLAGS_DBG = $(CXXFLAGS_DEBUG_OPTION) CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) @@ -267,6 +267,10 @@ CPPFLAGS_COMMON = -D__solaris__ -D$(ARCH_FAMILY) CPPFLAGS_OPT = -DNDEBUG CPPFLAGS_DBG = -DDEBUG +ifneq ($(PRODUCT), java) + CPPFLAGS_DBG += -DLOGGING -DDBINFO +endif + ifeq ($(ARCH_FAMILY), i586) # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN @@ -410,63 +414,151 @@ endif # Different "levels" of optimization. # ifeq ($(CC_VERSION),gcc) - CC_HIGHEST_OPT = -O3 - CC_HIGHER_OPT = -O3 - CC_LOWER_OPT = -O2 + + CC_OPT/NONE = + CC_OPT/LOWER = -O2 + CC_OPT/HIGHER = -O3 + CC_OPT/HIGHEST = -O3 + + CXX_OPT/NONE = + CXX_OPT/LOWER = -O2 + CXX_OPT/HIGHER = -O3 + CXX_OPT/HIGHEST = -O3 + CFLAGS_REQUIRED_i586 += -fno-omit-frame-pointer CFLAGS_REQUIRED_amd64 += -fno-omit-frame-pointer + # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) # (See Rules.gmk) May need to wait for gcc 5? AUTOMATIC_PCH_OPTION = + else + # Highest could be -xO5, but indications are that -xO5 should be reserved # for a per-file use, on sources with known performance impacts. - CC_HIGHEST_OPT = -xO4 - CC_HIGHER_OPT = -xO4 - CC_LOWER_OPT = -xO2 + OPT_LEVEL/LOWER = 2 + OPT_LEVEL/HIGHER = 4 + OPT_LEVEL/HIGHEST = 4 + + CC_OPT/NONE = + CC_OPT/LOWER = $(OPT_LEVEL/LOWER:%=-xO%) + CC_OPT/HIGHER = $(OPT_LEVEL/HIGHER:%=-xO%) + CC_OPT/HIGHEST = $(OPT_LEVEL/HIGHEST:%=-xO%) + + CXX_OPT/NONE = + CXX_OPT/LOWER = $(OPT_LEVEL/LOWER:%=-xO%) + CXX_OPT/HIGHER = $(OPT_LEVEL/HIGHER:%=-xO%) + CXX_OPT/HIGHEST = $(OPT_LEVEL/HIGHEST:%=-xO%) + + # We need stack frames at all times + USE_XKEEPFRAME_OPTION = false + ifeq ($(USE_XKEEPFRAME_OPTION),true) + + # Unknown spelling on this option at this time (Maybe in SS13?) + CC_XKEEPFRAME_OPTIONS = -xkeepframe + CXX_XKEEPFRAME_OPTIONS = -xkeepframe + + else + + # On X86, make sure tail call optimization is off + # The z and y are the tail call optimizations. + ifeq ($(ARCH_FAMILY), i586) + ifeq ($(shell $(EXPR) $(CC_VER) \> 5.8), 1) + # Somehow, tail call optimization is creeping in. + # Make sure it is off. + # WARNING: These may cause compiler warnings about duplicate -O options + CC_XKEEPFRAME_OPTIONS += -Wu,-O$(OPT_LEVEL/$(OPTIMIZATION_LEVEL))~yz + CXX_XKEEPFRAME_OPTIONS += -Qoption ube -O$(OPT_LEVEL/$(OPTIMIZATION_LEVEL))~yz + endif + endif + + # On i586 we need to tell the code generator to ALWAYS use a + # frame pointer. + ifeq ($(ARCH_FAMILY), i586) + # Note that in 5.7, this is done with -xregs=no%frameptr + ifeq ($(CC_VER), 5.5) + # It's not exactly clear when this optimization kicks in, the + # current assumption is -xO4 or greater and for C++ with + # the -features=no%except option and -xO4 and greater. + # Bottom line is, we ALWAYS want a frame pointer! + CC_XKEEPFRAME_OPTIONS += -Wu,-Z~B + CXX_XKEEPFRAME_OPTIONS += -Qoption ube -Z~B + endif + ifeq ($(shell $(EXPR) $(CC_VER) \> 5.6), 1) + # Do NOT use frame pointer register as a general purpose opt register + CC_OPT/NONE += -xregs=no%frameptr + CXX_OPT/NONE += -xregs=no%frameptr + CC_XKEEPFRAME_OPTIONS += -xregs=no%frameptr + CXX_XKEEPFRAME_OPTIONS += -xregs=no%frameptr + endif + endif + + # Optimizer for sparc needs to be told not to do certain things + # related to frames or save instructions. + ifeq ($(ARCH_FAMILY), sparc) + # Do not use save instructions instead of add instructions + # This was an optimization starting in SC5.0 that made it hard for us to + # find the "save" instruction (which got turned into an "add") + CC_XKEEPFRAME_OPTIONS += -Wc,-Qrm-s + CXX_XKEEPFRAME_OPTIONS += -Qoption cg -Qrm-s + # Don't allow tail call code optimization. Started in SC5.0. + # We don't like code of this form: + # save + # + # call foo + # restore + # because we can't tell if the method will have a stack frame + # and register windows or not. + CC_XKEEPFRAME_OPTIONS += -Wc,-Qiselect-T0 + CXX_XKEEPFRAME_OPTIONS += -Qoption cg -Qiselect-T0 + endif + + endif + + # Extra options used with HIGHEST # - # WARNING: Use of _OPT=$(CC_HIGHEST_OPT) in your Makefile needs to be + # WARNING: Use of OPTIMIZATION_LEVEL=HIGHEST in your Makefile needs to be # done with care, there are some assumptions below that need to # be understood about the use of pointers, and IEEE behavior. # # Use non-standard floating point mode (not IEEE 754) - CC_HIGHEST_OPT += -fns + CC_HIGHEST_EXTRAS += -fns # Do some simplification of floating point arithmetic (not IEEE 754) - CC_HIGHEST_OPT += -fsimple + CC_HIGHEST_EXTRAS += -fsimple # Use single precision floating point with 'float' - CC_HIGHEST_OPT += -fsingle + CC_HIGHEST_EXTRAS += -fsingle # Assume memory references via basic pointer types do not alias # (Source with excessing pointer casting and data access with mixed # pointer types are not recommended) - CC_HIGHEST_OPT += -xalias_level=basic + CC_HIGHEST_EXTRAS += -xalias_level=basic # Use intrinsic or inline versions for math/std functions # (If you expect perfect errno behavior, do not use this) - CC_HIGHEST_OPT += -xbuiltin=%all + CC_HIGHEST_EXTRAS += -xbuiltin=%all # Loop data dependency optimizations (need -xO3 or higher) - CC_HIGHEST_OPT += -xdepend + CC_HIGHEST_EXTRAS += -xdepend # Pointer parameters to functions do not overlap # (Similar to -xalias_level=basic usage, but less obvious sometimes. # If you pass in multiple pointers to the same data, do not use this) - CC_HIGHEST_OPT += -xrestrict + CC_HIGHEST_EXTRAS += -xrestrict # Inline some library routines # (If you expect perfect errno behavior, do not use this) - CC_HIGHEST_OPT += -xlibmil + CC_HIGHEST_EXTRAS += -xlibmil # Use optimized math routines # (If you expect perfect errno behavior, do not use this) # Can cause undefined external on Solaris 8 X86 on __sincos, removing for now - # CC_HIGHEST_OPT += -xlibmopt + # CC_HIGHEST_EXTRAS += -xlibmopt ifeq ($(ARCH_FAMILY), sparc) # Assume at most 8byte alignment, raise SIGBUS on error ### Presents an ABI issue with customer JNI libs? - ####CC_HIGHEST_OPT += -xmemalign=8s + ####CC_HIGHEST_EXTRAS += -xmemalign=8s # Automatic prefetch instructions, explicit prefetch macros - CC_HIGHEST_OPT += -xprefetch=auto,explicit + CC_HIGHEST_EXTRAS += -xprefetch=auto,explicit # Pick ultra as the chip to optimize to - CC_HIGHEST_OPT += -xchip=ultra + CC_HIGHEST_EXTRAS += -xchip=ultra endif ifeq ($(ARCH), i586) # Pick pentium as the chip to optimize to - CC_HIGHEST_OPT += -xchip=pentium + CC_HIGHEST_EXTRAS += -xchip=pentium endif ifdef LIBRARY # The Solaris CBE (Common Build Environment) requires that the use @@ -476,9 +568,6 @@ else CFLAGS_REQUIRED_sparcv9 += -xregs=no%appl endif ifeq ($(shell $(EXPR) $(CC_VER) \> 5.6), 1) - # Do NOT use the frame pointer register as a general purpose opt register - CFLAGS_REQUIRED_i586 += -xregs=no%frameptr - CFLAGS_REQUIRED_amd64 += -xregs=no%frameptr # We MUST allow data alignment of 4 for sparc V8 (32bit) # Presents an ABI issue with customer JNI libs? We must be able to # to handle 4byte aligned objects? (rare occurance, but possible?) @@ -492,77 +581,28 @@ else # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) # (See Rules.gmk) The SS11 -xpch=auto* options appear to be broken. AUTOMATIC_PCH_OPTION = + + # Add in keep frame options + CC_OPT/LOWER += $(CC_XKEEPFRAME_OPTIONS) + CC_OPT/HIGHER += $(CC_XKEEPFRAME_OPTIONS) + CC_OPT/HIGHEST += $(CC_XKEEPFRAME_OPTIONS) + CXX_OPT/LOWER += $(CXX_XKEEPFRAME_OPTIONS) + CXX_OPT/HIGHER += $(CXX_XKEEPFRAME_OPTIONS) + CXX_OPT/HIGHEST += $(CXX_XKEEPFRAME_OPTIONS) + + # Add in highest optimization settings + CC_OPT/HIGHEST += $(CC_HIGHEST_EXTRAS) + CXX_OPT/HIGHEST += $(CC_HIGHEST_EXTRAS) + endif -CC_NO_OPT = -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) -endif +# Default optimization settings based on level. +CC_OPT = $(CC_OPT/$(OPTIMIZATION_LEVEL)) +CXX_OPT = $(CXX_OPT/$(OPTIMIZATION_LEVEL)) # Flags required all the time CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) -# Add processor specific options for optimizations -CC_HIGHEST_OPT += $(_OPT_$(ARCH)) -CC_HIGHER_OPT += $(_OPT_$(ARCH)) -CC_LOWER_OPT += $(_OPT_$(ARCH)) - -# Secret compiler optimization options that should be in the above macros -# but since they differ in format from C to C++, are added into the C or -# C++ specific macros for compiler flags. -# -# On i586 we need to tell the code generator to ALWAYS use a -# frame pointer. -ifeq ($(ARCH_FAMILY), i586) - # Note that in 5.7, this is done with -xregs=no%frameptr - ifeq ($(CC_VER), 5.5) - # It's not exactly clear when this optimization kicks in, the - # current assumption is -xO4 or greater and for C++ with - # the -features=no%except option and -xO4 and greater. - # Bottom line is, we ALWAYS want a frame pointer! - CXXFLAGS_OPT += -Qoption ube -Z~B - CFLAGS_OPT += -Wu,-Z~B - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption ube -Z~B - CFLAGS_DBG += -Wu,-Z~B - endif - endif -endif -# -# Optimizer for sparc needs to be told not to do certain things -# related to frames or save instructions. -ifeq ($(ARCH_FAMILY), sparc) - # NOTE: Someday the compilers will provide a high-level option for this. - # Use save instructions instead of add instructions - # This was an optimization starting in SC5.0 that made it hard for us to - # find the "save" instruction (which got turned into an "add") - CXXFLAGS_OPT += -Qoption cg -Qrm-s - CFLAGS_OPT += -Wc,-Qrm-s - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption cg -Qrm-s - CFLAGS_DBG += -Wc,-Qrm-s - endif - # - # NOTE: Someday the compilers will provide a high-level option for this. - # Don't allow tail call code optimization. Started in SC5.0. - # We don't like code of this form: - # save - # - # call foo - # restore - # because we can't tell if the method will have a stack frame - # and register windows or not. - CXXFLAGS_OPT += -Qoption cg -Qiselect-T0 - CFLAGS_OPT += -Wc,-Qiselect-T0 - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption cg -Qiselect-T0 - CFLAGS_DBG += -Wc,-Qiselect-T0 - endif -endif - # # Path and option to link against the VM, if you have to. Note that # there are libraries that link against only -ljava, but they do get diff --git a/make/common/Defs-windows.gmk b/make/common/Defs-windows.gmk index d7c11837e96819a402283ea0035bba658c664393..4ec2a0467a8219b6134e8e744ba9d4e5dd9df054 100644 --- a/make/common/Defs-windows.gmk +++ b/make/common/Defs-windows.gmk @@ -84,6 +84,15 @@ EXTRA_LFLAGS += /LIBPATH:$(DXSDK_LIB_PATH) # # Default optimization # + +ifndef OPTIMIZATION_LEVEL + ifeq ($(PRODUCT), java) + OPTIMIZATION_LEVEL = HIGHER + else + OPTIMIZATION_LEVEL = LOWER + endif +endif + ifeq ($(CC_VERSION),msvc) # Visual Studio .NET 2003 or VS2003 compiler option definitions: # -O1 Favors reduced size over speed (-Og -Os -Oy -Ob2 -Gs -GF -Gy) @@ -113,21 +122,28 @@ ifeq ($(CC_VERSION),msvc) # NOTE: With VC6, -Ox, -O1, and -O2 used -Ob1, not -Ob2. # NOTE: With VC6, -O1 and -O2 used -Gf, not -GF. # + + CC_OPT/NONE = -Od + CC_OPT/LOWER = -O2 + CC_OPT/HIGHER = -O3 + CC_OPT/HIGHEST = -O3 + ifeq ($(COMPILER_VERSION), VC6) # VC6 (6.2) msvc compiler (the way Tiger and early Mustang were built) # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) AUTOMATIC_PCH_OPTION = GX_OPTION = -GX ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -Ox -Gy -Os -GB - CC_HIGHER_OPT = -Ox -Gy -Os -GB - CC_LOWER_OPT = -Ox -Gy -Os -GB + CC_OPT/HIGHEST = -Ox -Gy -Os -GB + CC_OPT/HIGHER = -Ox -Gy -Os -GB + CC_OPT/LOWER = -Ox -Gy -Os -GB else - CC_HIGHEST_OPT = -Ox -Gy -Op - CC_HIGHER_OPT = -Ox -Gy -Op - CC_LOWER_OPT = -Ox -Gy -Op + CC_OPT/HIGHEST = -Ox -Gy -Op + CC_OPT/HIGHER = -Ox -Gy -Op + CC_OPT/LOWER = -Ox -Gy -Op endif endif + ifeq ($(COMPILER_VERSION), VS2003) # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) AUTOMATIC_PCH_OPTION = -YX @@ -135,53 +151,45 @@ ifeq ($(CC_VERSION),msvc) GX_OPTION = -GX ifeq ($(ARCH_DATA_MODEL), 32) # Lowered opt level to try and reduce footprint, dll size especially. - # Was: CC_HIGHEST_OPT = -O2 -G6 - # Was: CC_HIGHER_OPT = -O2 - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 + # Was: CC_OPT/HIGHEST = -O2 -G6 + # Was: CC_OPT/HIGHER = -O2 + CC_OPT/HIGHEST = -O2 + CC_OPT/HIGHER = -O1 + CC_OPT/LOWER = -O1 else - CC_HIGHEST_OPT = -O2 -Op - CC_HIGHER_OPT = -O2 -Op - CC_LOWER_OPT = -O1 -Op + CC_OPT/HIGHEST = -O2 -Op + CC_OPT/HIGHER = -O2 -Op + CC_OPT/LOWER = -O1 -Op endif endif + ifeq ($(COMPILER_VERSION), VS2005) # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) AUTOMATIC_PCH_OPTION = # VS2005 compiler, only with Platform SDK right now? GX_OPTION = -EHsc ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 + CC_OPT/HIGHEST = -O2 + CC_OPT/HIGHER = -O1 + CC_OPT/LOWER = -O1 else - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 + CC_OPT/HIGHEST = -O2 + CC_OPT/HIGHER = -O1 + CC_OPT/LOWER = -O1 endif endif - CC_NO_OPT = -Od + else # CC_VERSION + # GCC not supported, but left for historical reference... - CC_HIGHEST_OPT = -O3 - CC_HIGHER_OPT = -O2 - CC_LOWER_OPT = -O2 - CC_NO_OPT = -endif + CC_OPT/NONE = + CC_OPT/LOWER = -O2 + CC_OPT/HIGHER = -O2 + CC_OPT/HIGHEST = -O3 -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) endif -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) -endif +CC_OPT = $(CC_OPT/$(OPTIMIZATION_LEVEL)) # Select the runtime support library carefully, need to be consistent # @@ -233,7 +241,7 @@ ifeq ($(CC_VERSION),msvc) # Use static link for the C++ runtime (so msvcp71.dll not needed) # CFLAGS_COMMON += -Zi -nologo - CFLAGS_OPT = $(POPT) + CFLAGS_OPT = $(CC_OPT) CFLAGS_DBG = -Od $(MS_RUNTIME_DEBUG_OPTION) # Starting from VS2005 the wchar_t is handled as a built-in C/C++ data type diff --git a/make/common/Defs.gmk b/make/common/Defs.gmk index 16eb1e2258f94d110ec0a559e0fbd9bd17cfa12f..33eedad16a4150050be56f7519ebe9dbcd68281e 100644 --- a/make/common/Defs.gmk +++ b/make/common/Defs.gmk @@ -451,7 +451,7 @@ vpath %.$(OBJECT_SUFFIX) $(OBJDIR) # namely jni.h, jvm.h, and jni_utils.h, plus their platform-specific # relatives. # -VPATH.h = $(PLATFORM_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/include$(CLASSPATH_SEPARATOR)$(PLATFORM_SRC)/javavm/include +VPATH.h = $(PLATFORM_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/export vpath %.h $(VPATH.h) # @@ -482,11 +482,6 @@ PKGDIR = $(subst .,/,$(PACKAGE)) # include $(JDK_MAKE_SHARED_DIR)/Defs-java.gmk -# -# Set opt level to ALT_OPT if set otherwise _OPT -# -POPT = $(_OPT$(ALT_OPT))$(ALT_OPT) - # # Convenient macros # @@ -709,7 +704,20 @@ endif # 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 --git a/make/common/Demo.gmk b/make/common/Demo.gmk index 086a1da97a7b8d9d34cebdea678563bae386fa37..12a3ce105e4735080376fb8feeb21b8fdeb5858d 100644 --- a/make/common/Demo.gmk +++ b/make/common/Demo.gmk @@ -1,5 +1,5 @@ # -# Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-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 @@ -251,7 +251,7 @@ $(DEMO_JAR): \ @$(DEMO_JAVAC_INPUT) $(BOOT_JAR_CMD) -cfm $@ $(DEMO_MANIFEST) \ -C $(DEMO_JAR_IMAGE) . \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) endif @@ -317,7 +317,11 @@ bundles: $(DEMO_BUILD_SRCZIP) # Applets are special, no jar file, no src.zip, everything expanded. ifdef DEMO_IS_APPLET @$(ECHO) "Expanding jar file into demos area at $(DEMO_DESTDIR)" - ( $(CD) $(DEMO_DESTDIR) && $(BOOT_JAR_CMD) -xfv $(DEMONAME).jar && $(RM) -r META-INF $(DEMONAME).jar ) + ( $(CD) $(DEMO_DESTDIR) && \ + $(BOOT_JAR_CMD) -xfv $(DEMONAME).jar \ + $(BOOT_JAR_JFLAGS) && \ + $(RM) -r META-INF $(DEMONAME).jar && \ + $(java-vm-cleanup) ) @( $(CD) $(DEMO_DESTDIR) && $(java-vm-cleanup) ) @$(ECHO) "Expanding source into demos area at $(DEMO_DESTDIR)" ( $(CD) $(DEMO_DESTDIR) && $(UNZIP) -o src.zip && $(RM) src.zip ) diff --git a/make/common/Library.gmk b/make/common/Library.gmk index 2b9fe5d46dc197a9d18591b8f17927b9b3ad0e1a..3e4318ecd2323120d8ecf4c093ec842936b2113b 100644 --- a/make/common/Library.gmk +++ b/make/common/Library.gmk @@ -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 @@ -238,7 +238,7 @@ else # PLATFORM # $(ACTUAL_LIBRARY):: $(COMPILE_FILES_o) $(FILES_m) $(FILES_reorder) @$(prep-target) - @$(ECHO) "STATS: LIBRARY=$(LIBRARY), PRODUCT=$(PRODUCT), _OPT=$(_OPT)" + @$(ECHO) "STATS: LIBRARY=$(LIBRARY), PRODUCT=$(PRODUCT), OPTIMIZATION_LEVEL=$(OPTIMIZATION_LEVEL)" @$(ECHO) "Rebuilding $@ because of $?" ifeq ($(LIBRARY), fdlibm) $(AR) -r $@ $(FILES_o) diff --git a/make/common/Release.gmk b/make/common/Release.gmk index 42de79f70d63844bc59be271374303bde52d0f0d..76a1bc466f2ca9d983e496d9c86a61eb45647bc8 100644 --- a/make/common/Release.gmk +++ b/make/common/Release.gmk @@ -63,15 +63,6 @@ endif JTG_DOCS = $(JDK_TOPDIR)/src/solaris/doc -# Choose the right set of documents for the images -ifdef OPENJDK - SHARE_JDK_DOC_SRC = $(JDK_TOPDIR)/make - SHARE_JRE_DOC_SRC = $(JDK_TOPDIR)/make -else - SHARE_JDK_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jdk - SHARE_JRE_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jre -endif - #We use this for man page header jdkversion := $(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION) @@ -81,13 +72,20 @@ ifeq ($(PLATFORM), windows) endif # The base names of all the license and document files for the jdk and jre +# (These files get placed in the jdk and jre install images) ifdef OPENJDK + # Where to find these files + SHARE_JDK_DOC_SRC = $(JDK_TOPDIR) + SHARE_JRE_DOC_SRC = $(JDK_TOPDIR) # Same files for jdk and jre, no name changes LICENSE_DOCLIST_JDK = LICENSE ASSEMBLY_EXCEPTION LICENSE_DOCLIST_JRE = LICENSE ASSEMBLY_EXCEPTION - OTHER_DOCLIST_JDK = README.html THIRD_PARTY_README - OTHER_DOCLIST_JRE = README.html THIRD_PARTY_README + OTHER_DOCLIST_JDK = THIRD_PARTY_README + OTHER_DOCLIST_JRE = THIRD_PARTY_README else + # Where to find these files + SHARE_JDK_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jdk + SHARE_JRE_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jre # Select the pre-release or FCS license version based on the build milestone. LICENSE_VERSION=.pre ifeq ($(MILESTONE), fcs) @@ -662,7 +660,7 @@ $(RES_JAR_ARGLIST): $(RES_JAR_FILELIST) $(RESOURCES_JAR): $(RES_JAR_ARGLIST) $(JAR_MANIFEST_FILE) $(prep-target) $(BOOT_JAR_CMD) c0mf $(JAR_MANIFEST_FILE) $@ \ - @$(RES_JAR_ARGLIST) $(JAR_JFLAGS) + @$(RES_JAR_ARGLIST) $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) # Create jsse.jar containing SunJSSE implementation classes @@ -671,7 +669,7 @@ $(JSSE_JAR): $(JAR_MANIFEST_FILE) $(prep-target) $(BOOT_JAR_CMD) c0mf $(JAR_MANIFEST_FILE) $@ \ $(JSSE_CLASSES_DIRS:%=-C $(CLASSBINDIR) %) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) # Create sec-bin.zip @@ -721,7 +719,7 @@ $(RT_JAR_ARGLIST): $(RT_JAR_FILELIST) $(RT_JAR): $(RT_JAR_ARGLIST) $(JAR_MANIFEST_FILE) $(prep-target) $(BOOT_JAR_CMD) c0mf $(JAR_MANIFEST_FILE) $@ \ - @$(RT_JAR_ARGLIST) $(JAR_JFLAGS) + @$(RT_JAR_ARGLIST) $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) # Meta-index construction to make core class loaders lazier @@ -955,7 +953,7 @@ initial-image-jdk:: initial-image-jdk-setup \ @# $(BOOT_JAR_CMD) c0f $(LIBDIR)/tools.jar $(addprefix \ -C $(CLASSBINDIR) , $(TOOLS)) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) $(CP) $(LIBDIR)/tools.jar $(JDK_IMAGE_DIR)/lib/tools.jar @# @@ -968,7 +966,7 @@ initial-image-jdk:: initial-image-jdk-setup \ -Acom.sun.tools.javac.sym.Dest=$(OUTPUTDIR)/symbols/META-INF/sym/rt.jar \ $(CORE_PKGS) $(NON_CORE_PKGS) $(EXCLUDE_PROPWARN_PKGS) $(BOOT_JAR_CMD) c0f $(LIBDIR)/ct.sym \ - -C $(OUTPUTDIR)/symbols META-INF $(JAR_JFLAGS) + -C $(OUTPUTDIR)/symbols META-INF $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) $(CP) $(LIBDIR)/ct.sym $(JDK_IMAGE_DIR)/lib/ct.sym @# @@ -1132,11 +1130,11 @@ endef COMPARE_FILTER = | $(EGREP) -v /fastdebug/ | $(EGREP) -v /demo/ | $(EGREP) -v /sample/ # If a previuous image is provided, no need to install it. -ifdef PREVIOUS_JDK_IMAGE +ifdef PREVIOUS_RELEASE_IMAGE # Just use the pre-installed images - PREV_JRE_IMAGE_DIR=$(PREVIOUS_JDK_IMAGE)/jre - PREV_JDK_IMAGE_DIR=$(PREVIOUS_JDK_IMAGE) + PREV_JRE_IMAGE_DIR=$(PREVIOUS_RELEASE_IMAGE)/jre + PREV_JDK_IMAGE_DIR=$(PREVIOUS_RELEASE_IMAGE) else diff --git a/make/common/Sanity.gmk b/make/common/Sanity.gmk index a4ae86f47bdf232b53bc5f649fe75d40ced6072b..3388be0403fbb6fc9878d4e9af2545edf4830362 100644 --- a/make/common/Sanity.gmk +++ b/make/common/Sanity.gmk @@ -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 @@ sanity-base: pre-sanity \ sane-compiler \ sane-cacerts \ sane-ant_version \ - sane-findbugs_version \ sane-zip_version \ sane-msvcrt_path diff --git a/make/common/internal/BinaryPlugs.gmk b/make/common/internal/BinaryPlugs.gmk index a52b61752862115c8ae1da4800abc7cdcc0b7f4e..bb2d64262edc75f2b68d3bc198cb032eaa81db1a 100644 --- a/make/common/internal/BinaryPlugs.gmk +++ b/make/common/internal/BinaryPlugs.gmk @@ -185,7 +185,8 @@ endef # import-binary-plug-file define import-binary-plug-classes @$(MKDIR) -p $(CLASSDESTDIR) @$(CAT) $1 | $(SED) -e 's/^/PLUG IMPORT: /' -($(CD) $(CLASSDESTDIR) && $(BOOT_JAR_CMD) xf $(PLUG_IMPORT_JARFILE) @$1) +($(CD) $(CLASSDESTDIR) && $(BOOT_JAR_CMD) xf $(PLUG_IMPORT_JARFILE) @$1 $(BOOT_JAR_JFLAGS) ) +($(CD) $(CLASSDESTDIR) && $(java-vm-cleanup) ) endef # import-binary-plug-classes # Import specific area classes (the classes are always created) @@ -275,7 +276,8 @@ $(PLUG_EXPORT_JARFILE): $(PLUG_TEMPDIR)/all.clist $(PLUG_TEMPDIR)/all.jargs @$(prep-target) @$(ECHO) "PLUG EXPORT: $(@F)" @$(CAT) $(PLUG_TEMPDIR)/all.clist | $(SED) -e 's/^/PLUG EXPORT: /' - $(BOOT_JAR_CMD) cf $@ @$(PLUG_TEMPDIR)/all.jargs + $(BOOT_JAR_CMD) cf $@ @$(PLUG_TEMPDIR)/all.jargs $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) export-binary-plugs-jar: $(PLUG_EXPORT_JARFILE) # Export native libraries diff --git a/make/common/internal/ImportComponents.gmk b/make/common/internal/ImportComponents.gmk index d089f230a4cee1b70aa46d067e7bfb8272326b42..743659407db5788d8b2093045784654eb558fecc 100644 --- a/make/common/internal/ImportComponents.gmk +++ b/make/common/internal/ImportComponents.gmk @@ -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 @@ -107,8 +107,9 @@ endef define Unjar ( \ $(MKDIR) -p $1; \ - $(ECHO) "( $(CD) $1 && $(BOOT_JAR_CMD) xfv $2 $3 )" ; \ - ( $(CD) $1 && $(BOOT_JAR_CMD) xfv $2 $3 ) \ + $(ECHO) "( $(CD) $1 && $(BOOT_JAR_CMD) xfv $2 $3 $(BOOT_JAR_JFLAGS) )" ; \ + ( $(CD) $1 && $(BOOT_JAR_CMD) xfv $2 $3 $(BOOT_JAR_JFLAGS) ) && \ + ( $(CD) $1 && $(java-vm-cleanup) ) \ ) endef diff --git a/make/common/shared/Compiler-sun.gmk b/make/common/shared/Compiler-sun.gmk index b4806bb4bc3619c9b66ac8c0e3663534c75086c8..b3c4e2a90b1611ba2283985b1ae8f441aa966b4e 100644 --- a/make/common/shared/Compiler-sun.gmk +++ b/make/common/shared/Compiler-sun.gmk @@ -31,11 +31,8 @@ COMPILER_NAME=Sun Studio # Sun Studio Compiler settings specific to Solaris ifeq ($(PLATFORM), solaris) - # FIXUP: Change to SS12 when validated - #COMPILER_VERSION=SS12 - #REQUIRED_CC_VER=5.9 - COMPILER_VERSION=SS11 - REQUIRED_CC_VER=5.8 + COMPILER_VERSION=SS12 + REQUIRED_CC_VER=5.9 CC = $(COMPILER_PATH)cc CPP = $(COMPILER_PATH)cc -E CXX = $(COMPILER_PATH)CC diff --git a/make/common/shared/Defs-java.gmk b/make/common/shared/Defs-java.gmk index 179e53a01a905b1466f08191a6954213b319d836..9bfb96da4537ebe9b8d22c92cde64ca6c689d2ee 100644 --- a/make/common/shared/Defs-java.gmk +++ b/make/common/shared/Defs-java.gmk @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -190,6 +190,7 @@ ifeq ($(JAVAC_WARNINGS_FATAL), true) BOOT_JAVACFLAGS += -Werror endif BOOT_JAVACFLAGS += -encoding ascii +BOOT_JAR_JFLAGS += $(JAR_JFLAGS) BOOT_JAVA_CMD = $(BOOTDIR)/bin/java $(JAVA_TOOLS_FLAGS) BOOT_JAVAC_CMD = $(BOOTDIR)/bin/javac $(JAVAC_JVM_FLAGS) $(BOOT_JAVACFLAGS) diff --git a/make/common/shared/Defs-windows.gmk b/make/common/shared/Defs-windows.gmk index 250604136bc3141a57fc737d75610d51b10dc64b..35fa8ce344fbf1b1529aea85b0fbc48c3b92b0d7 100644 --- a/make/common/shared/Defs-windows.gmk +++ b/make/common/shared/Defs-windows.gmk @@ -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 @@ -539,6 +539,8 @@ else WSCRIPT :=$(call FileExists,$(_WSCRIPT1),$(_WSCRIPT2)) endif WSCRIPT:=$(call AltCheckSpaces,WSCRIPT) +# batch mode no modal dialogs on errors, please. +WSCRIPT += -B # CSCRIPT: path to cscript.exe (used in creating install bundles) ifdef ALT_CSCRIPT @@ -561,6 +563,10 @@ else MSIVAL2 :=$(call FileExists,$(_MSIVAL2_1),$(_MSIVAL2_2)) endif MSIVAL2:=$(call AltCheckSpaces,MSIVAL2) +# suppress msival2 checks, as it hangs jprt builds +ifdef SKIP_MSIVAL2 + MSIVAL2 := $(ECHO) +endif # LOGOCUB: path to cub file for (used in validating install msi files) ifdef ALT_LOGOCUB diff --git a/make/common/shared/Defs.gmk b/make/common/shared/Defs.gmk index af86be8085d021c6888c6e5ae17c65f427eb6e86..638cd36369618b8d5bb96263f57f0c77c022d354 100644 --- a/make/common/shared/Defs.gmk +++ b/make/common/shared/Defs.gmk @@ -279,9 +279,6 @@ PROMOTED_BUILD_LATEST = latest PROMOTED_BUILD_BASEDIR = $(PROMOTED_RE_AREA)/$(PROMOTED_BUILD_LATEST) PROMOTED_BUILD_BINARIES = $(PROMOTED_BUILD_BASEDIR)/binaries -# OPT: Changes what the optimizations settings (in _OPT) -POPT = $(_OPT$(ALT_OPT))$(ALT_OPT) - # PARALLEL_COMPILE_JOBS: is the number of compiles done in parallel. # If the user sets ALT_PARALLEL_COMPILE_JOBS, then COMPILE_APPROACH is set # to parallel. @@ -355,30 +352,6 @@ else 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. @@ -392,19 +365,70 @@ export BOOTDIR 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 @@ -516,23 +540,17 @@ JDK_CUPS_HEADERS_PATH=$(JDK_DEVTOOLS_DIR)/share/cups/include 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 --git a/make/common/shared/Sanity-Settings.gmk b/make/common/shared/Sanity-Settings.gmk index d7ef8fe06949aa68f01a7f8896ad729e6aa4b085..911327f5a881fbc539f44678626d8273cedefef7 100644 --- a/make/common/shared/Sanity-Settings.gmk +++ b/make/common/shared/Sanity-Settings.gmk @@ -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 addAltSetting,SLASH_JAVA) 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 @@ ifeq ($(PLATFORM),windows) 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 --git a/make/common/shared/Sanity.gmk b/make/common/shared/Sanity.gmk index 3048281df91de647b1b69dfeefb645ae050014bc..b2cbab12b3f5cbffa7a3658b0d6a2014ad177b52 100644 --- a/make/common/shared/Sanity.gmk +++ b/make/common/shared/Sanity.gmk @@ -107,21 +107,9 @@ UNZIP_VER :=$(call GetVersion,"$(_UNZIP_VER)") 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 @@ include $(JDK_MAKE_SHARED_DIR)/Sanity-Settings.gmk sane-alsa-versioncheck \ sane-alsa-headers \ sane-ant_version \ - sane-findbugs_version \ sane-zip_version \ sane-unzip_version \ sane-msvcrt_path \ @@ -1216,19 +1203,6 @@ sane-ant_version: "" >> $(WARNING_FILE) ; \ 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 ###################################################### diff --git a/make/docs/CORE_PKGS.gmk b/make/docs/CORE_PKGS.gmk index c768e7023dbda711d6f4cc157864c814b183df52..4a41a2005bf6b361f6c223ae355cb07e085a36c2 100644 --- a/make/docs/CORE_PKGS.gmk +++ b/make/docs/CORE_PKGS.gmk @@ -155,8 +155,10 @@ CORE_PKGS = \ javax.lang.model.type \ javax.lang.model.util \ javax.management \ + javax.management.event \ javax.management.loading \ javax.management.monitor \ + javax.management.namespace \ javax.management.relation \ javax.management.openmbean \ javax.management.timer \ diff --git a/make/java/fdlibm/Makefile b/make/java/fdlibm/Makefile index ab7a411579c28cbb1317b37f5fb1774fca48b673..eeb5e744f4146b6d370963b3791060a948460d09 100644 --- a/make/java/fdlibm/Makefile +++ b/make/java/fdlibm/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 @@ -33,6 +33,7 @@ BUILDDIR = ../.. LIBRARY = fdlibm PRODUCT = java + include $(BUILDDIR)/common/Defs.gmk # @@ -40,14 +41,23 @@ include $(BUILDDIR)/common/Defs.gmk # FDLIBM_SRC = $(SHARE_SRC)/native/java/lang/fdlibm -# windows compiler flags +# Windows: compiler flags ifeq ($(PLATFORM),windows) # Turn all optimizations off - _OPT = $(CC_NO_OPT) + OPTIMIZATION_LEVEL = NONE OTHER_CFLAGS = CPPFLAGS_DBG += -DLOGGING endif +# +# Linux: Disable optimization to get correctly reproducible +# floating-point results. +# +ifeq ($(PLATFORM),linux) + # Turn all optimizations off + OPTIMIZATION_LEVEL = NONE +endif + # # Include path. # @@ -68,15 +78,6 @@ include FILES_c.gmk # include $(BUILDDIR)/common/Library.gmk -# -# Disable optimization to get correctly reproducible -# floating-point results. -# -ifeq ($(PLATFORM),linux) - # Turn all optimizations off - _OPT = $(CC_NO_OPT) -endif - # # Find fdlibm source files. # diff --git a/make/java/hpi/windows/Makefile b/make/java/hpi/windows/Makefile index fa04ec6a3628e21a83a2e73d914ae360146222bf..b82d8853ab2bc11443aebc81be1c8d5e7e6e5ed2 100644 --- a/make/java/hpi/windows/Makefile +++ b/make/java/hpi/windows/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1999-2005 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 diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk index 18b1d35115dd8addf348d5f3d75e0faf61813e3b..3117af8461f4a9560e1c28c251d6c4225924a8fa 100644 --- a/make/java/java/FILES_java.gmk +++ b/make/java/java/FILES_java.gmk @@ -1,5 +1,5 @@ # -# Copyright 1996-2007 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 @@ -450,6 +450,7 @@ JAVA_JAVA_java = \ 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 --git a/make/java/java/mapfile-vers b/make/java/java/mapfile-vers index ad0380979a94984fccef0db39553da27bfb8d6ad..77a78301af721f9aca72358a1b4ae554bbf2bc49 100644 --- a/make/java/java/mapfile-vers +++ b/make/java/java/mapfile-vers @@ -222,8 +222,6 @@ SUNWprivate_1.1 { 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 --git a/make/java/java_crw_demo/Makefile b/make/java/java_crw_demo/Makefile index c65a84df1e855b720b53adb0ae61681048bc0397..6c45bcbd499b896e14a481d2ed64255da72d6f7b 100644 --- a/make/java/java_crw_demo/Makefile +++ b/make/java/java_crw_demo/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-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 diff --git a/make/java/java_hprof_demo/Makefile b/make/java/java_hprof_demo/Makefile index 9c97a6a24e554945836339d029f80e3408b08a7f..4e1ef2a31a89f14dd4db7ed77b08b542241c4a67 100644 --- a/make/java/java_hprof_demo/Makefile +++ b/make/java/java_hprof_demo/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -28,14 +28,14 @@ LIBRARY = hprof PRODUCT = sun LIBRARY_OUTPUT = hprof_jvmti -# Configure the CFLAGS for this library. +# Use highest optimization +OPTIMIZATION_LEVEL = HIGHEST +# Configure the CFLAGS for this library. FILES_m = mapfile-vers include $(BUILDDIR)/common/Defs.gmk -_OPT=$(CC_HIGHEST_OPT) - SRCDIR=$(SHARE_SRC)/demo/jvmti/hprof PSRCDIR=$(PLATFORM_SRC)/demo/jvmti/hprof diff --git a/make/java/jli/Makefile b/make/java/jli/Makefile index 5a1c312d7abb07298a283e6afc5257c38e5b70b7..7a0c53f1ce2f72caa677630e274ebe77fa0ef88e 100644 --- a/make/java/jli/Makefile +++ b/make/java/jli/Makefile @@ -113,7 +113,11 @@ ifeq ($(PLATFORM), windows) 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 --git a/make/java/jli/mapfile-vers b/make/java/jli/mapfile-vers index a9e8198dea1e7b06a810053f26de00bf8bbf3ef1..e04e4f13db94dc582bb3a426b1b777be03fb747f 100644 --- a/make/java/jli/mapfile-vers +++ b/make/java/jli/mapfile-vers @@ -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 @@ SUNWprivate_1.1 { JLI_Launch; JLI_ManifestIterate; JLI_SetTraceLauncher; + JLI_ReportErrorMessage; + JLI_ReportErrorMessageSys; + JLI_ReportMessage; + JLI_ReportExceptionDescription; local: *; }; diff --git a/make/java/management/Makefile b/make/java/management/Makefile index 4d39d514e51f135ccb975be8aef4256bb290278c..466d2212afe0433258405ab6bde534a2f80ccabe 100644 --- a/make/java/management/Makefile +++ b/make/java/management/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,8 @@ endif include $(BUILDDIR)/common/Library.gmk $(AGENTJAR): $(LIBDIR) $(TEMPDIR)/manifest - $(BOOT_JAR_CMD) -cfm $(AGENTJAR) $(TEMPDIR)/manifest + $(BOOT_JAR_CMD) -cfm $(AGENTJAR) $(TEMPDIR)/manifest $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) $(TEMPDIR)/manifest: $(MANIFEST) $(install-file) diff --git a/make/java/net/Makefile b/make/java/net/Makefile index 4141294c02c0365383e436c65f186ba22ed58673..b9a3defdb8ccae2429ade7227b77a2816bf6ac2f 100644 --- a/make/java/net/Makefile +++ b/make/java/net/Makefile @@ -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 diff --git a/make/java/net/mapfile-vers b/make/java/net/mapfile-vers index 86cb351c9f935c9a60bf540146d400328f7ac62e..d9803f8f9446c5d5d891aeffaafb43e0c3b1f558 100644 --- a/make/java/net/mapfile-vers +++ b/make/java/net/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright 1997-2005 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 @@ -57,7 +57,7 @@ SUNWprivate_1.1 { Java_java_net_Inet6AddressImpl_isReachable0; Java_java_net_NetworkInterface_init; Java_java_net_NetworkInterface_getByName0; - Java_java_net_NetworkInterface_getByIndex; + Java_java_net_NetworkInterface_getByIndex0; Java_java_net_NetworkInterface_getByInetAddress0; Java_java_net_NetworkInterface_getAll; Java_java_net_NetworkInterface_isUp0; diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk index 5958812adfb55160c41b3319254debce3320e52b..0e8c70906aa6ce8ebc4e5d137ddb17defbffae13 100644 --- a/make/java/nio/FILES_java.gmk +++ b/make/java/nio/FILES_java.gmk @@ -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 @@ -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 @@ FILES_src = \ 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 @@ FILES_src = \ 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 @@ FILES_src = \ 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 @@ FILES_src = \ 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 @@ FILES_gen_ex = \ 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 @@ FILES_gen_ex = \ 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 --git a/make/java/nio/Makefile b/make/java/nio/Makefile index cff9ce5ceb29648f2bc50564199cf18c009f59c4..26c2f2fc68d0218fc30fad31bbaa39959878b1d6 100644 --- a/make/java/nio/Makefile +++ b/make/java/nio/Makefile @@ -56,18 +56,18 @@ FILES_java += \ 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_java += \ 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 @@ $(BUF_GEN)/%Exception.java: genExceptions.sh $(BUF_SRC)/exceptions @$(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 @@ $(SCS_GEN)/StandardCharsets.java: genCharsetProvider.sh \ 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 --git a/make/java/nio/genCoder.sh b/make/java/nio/genCoder.sh index 769b98cd5235f996e8f2afa621f9ded1709b9cc8..b5f4faaa71a54a9c1042447dc6eff3cb3aeceee3 100644 --- a/make/java/nio/genCoder.sh +++ b/make/java/nio/genCoder.sh @@ -1,7 +1,7 @@ #! /bin/sh # -# Copyright 2000-2001 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 diff --git a/make/java/nio/mapfile-linux b/make/java/nio/mapfile-linux index dc2044c9d7925ccbced446ad4654cebc307ddc79..3fb47b0eb7c0e42107f01113f529ee39b96726f9 100644 --- a/make/java/nio/mapfile-linux +++ b/make/java/nio/mapfile-linux @@ -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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 --git a/make/java/nio/mapfile-solaris b/make/java/nio/mapfile-solaris index 77ef8ea2ad9083b9d1cc08411a70facd251fe6f4..6e109e2fabaf9be9aed350acf55ece2eb833265f 100644 --- a/make/java/nio/mapfile-solaris +++ b/make/java/nio/mapfile-solaris @@ -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 @@ SUNWprivate_1.1 { 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 --git a/make/java/npt/Makefile b/make/java/npt/Makefile index fe9eb0ad4e3b509318dd3c15221290b7ce4eeccd..57e6a66380519d722ada4cebb4d61226faf299a0 100644 --- a/make/java/npt/Makefile +++ b/make/java/npt/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-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 diff --git a/make/java/verify/Makefile b/make/java/verify/Makefile index c647d5085693035387ecd17c4025a2fe4b215cb6..24bcc0f48d4aa17f70190b3b69c9997e610bd543 100644 --- a/make/java/verify/Makefile +++ b/make/java/verify/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1999-2005 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 @@ -52,12 +52,6 @@ FILES_c = \ check_code.c \ check_format.c -# -# libverify.so needs these 2 header files (opcodes.h opcodes.length) -# from the VM. -# -CPPFLAGS += -I$(SHARE_SRC)/javavm/include - # # Targets. # diff --git a/make/java/zip/Makefile b/make/java/zip/Makefile index 00b381d5085257751fc50ad40a1514ac62b1595e..48e8c3904e9e734ed82ac9205bfd048f2c6256c0 100644 --- a/make/java/zip/Makefile +++ b/make/java/zip/Makefile @@ -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 diff --git a/make/javax/crypto/Makefile b/make/javax/crypto/Makefile index 86588e855ef09f5706a79610c051dcacf3398ec3..216ff6e222d671d07852778162a5917d81b9f850 100644 --- a/make/javax/crypto/Makefile +++ b/make/javax/crypto/Makefile @@ -230,7 +230,7 @@ build-jar: $(UNSIGNED_DIR)/jce.jar $(UNSIGNED_DIR)/jce.jar: prebuild build $(JCE_MANIFEST_FILE) $(prep-target) $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) $(CP) -r $(CLASSDESTDIR)/* $(CLASSBINDIR) @$(java-vm-cleanup) @@ -268,7 +268,7 @@ $(UNSIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar: \ $(prep-target) $(BOOT_JAR_CMD) cmf policy/unlimited/UNLIMITED $@ \ -C policy/unlimited default_US_export.policy \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) $(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar: \ @@ -277,7 +277,7 @@ $(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar: \ $(prep-target) $(BOOT_JAR_CMD) cmf policy/unlimited/UNLIMITED $@ \ -C policy/unlimited default_local.policy \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) # @@ -302,7 +302,7 @@ $(UNSIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \ $(BOOT_JAR_CMD) cmf policy/limited/LIMITED $@ \ -C policy/limited default_local.policy \ -C policy/limited exempt_local.policy \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) UNSIGNED_POLICY_FILES = \ @@ -402,7 +402,7 @@ endif $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ -C $(OBFUS_DIR)/build javax \ -C $(OBFUS_DIR)/build sun \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) $(sign-target) @$(java-vm-cleanup) diff --git a/make/javax/swing/beaninfo/SwingBeans.gmk b/make/javax/swing/beaninfo/SwingBeans.gmk index daead86fd6c19b8b3afa2c5a66c19ae7eb3791e6..66f16aae1a196ee584e06bd1958ecd1b647af69a 100644 --- a/make/javax/swing/beaninfo/SwingBeans.gmk +++ b/make/javax/swing/beaninfo/SwingBeans.gmk @@ -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 @@ -170,7 +170,7 @@ mkpackaging: $(BOOT_JAR_CMD) cf $(TEMPDIR)/tmp.jar \ -C $(BEANCLASSDIR) javax \ -C $(BEANCLASSDIR) sun \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) $(MV) $(TEMPDIR)/tmp.jar $(JDK_IMAGE_DIR)/lib/dt.jar @$(java-vm-cleanup) diff --git a/make/jpda/back/Makefile b/make/jpda/back/Makefile index bd9818365e3cc84451217fb98d1b02269bf3d72d..5237d9c798ccb76afb1362076a7c9ffa84c4cb86 100644 --- a/make/jpda/back/Makefile +++ b/make/jpda/back/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 diff --git a/make/jpda/transport/shmem/Makefile b/make/jpda/transport/shmem/Makefile index a1e2382500a71452c777b15061c8ed7d1141ad8f..fcc8c632de47bff174055180642b2757d94da4ec 100644 --- a/make/jpda/transport/shmem/Makefile +++ b/make/jpda/transport/shmem/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1999-2005 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 diff --git a/make/jpda/transport/socket/Makefile b/make/jpda/transport/socket/Makefile index 828613d49ed706c2bf4f69dfc7296001ab46ba4a..65f8018477fd2f823f4b510b8fd5809f9e1c7dd4 100644 --- a/make/jpda/transport/socket/Makefile +++ b/make/jpda/transport/socket/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 diff --git a/make/jprt.config b/make/jprt.config index 99ee4c4e793cf829b08ab267af7bba49ce2eeb11..d720475cecd77b44ed890ee2eb7f9bebce0c10ab 100644 --- a/make/jprt.config +++ b/make/jprt.config @@ -100,20 +100,16 @@ 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 # Use the JDK import for now (FIXME: use the binary plugs?) if [ "${OPENJDK}" = true ] ; then @@ -137,15 +133,13 @@ if [ "${osname}" = SunOS ] ; then if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then compiler_name=${JPRT_SOLARIS_COMPILER_NAME} else - # FIXUP: Change to SS12 when validated - #compiler_name=SS12 - compiler_name=SS11 + compiler_name=SS12 fi compiler_path=${jdk_devtools}/${solaris_arch}/SUNWspro/${compiler_name}/bin 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 @@ -182,7 +176,7 @@ elif [ "${osname}" = Linux ] ; then 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 @@ -230,7 +224,7 @@ else 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}" @@ -248,7 +242,7 @@ else 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 --git a/make/jprt.properties b/make/jprt.properties index 06abef8c8e6a1bb4bf13b4d4b072f34a63a918b4..c909f36aa3c4c18411608528ffd952bc5e248b76 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright 2006 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 @@ -55,6 +55,5 @@ jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 jprt.test.targets=*-*-*-jvm98 # Directories needed to build -jprt.bundle.src.dirs=make src jprt.bundle.exclude.src.dirs=build diff --git a/make/mksample/nio/Makefile b/make/mksample/nio/Makefile index a6e8fc46d964f8d3ddd066164374ca867014bd17..e05106293bbc0764c6f564b00fc4be19f92959bd 100644 --- a/make/mksample/nio/Makefile +++ b/make/mksample/nio/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-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 @@ -31,7 +31,7 @@ BUILDDIR = ../.. PRODUCT = java include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = server +SUBDIRS = multicast server all build clean clobber:: $(SUBDIRS-loop) diff --git a/src/share/classes/sun/nio/ch/exceptions b/make/mksample/nio/multicast/Makefile similarity index 65% rename from src/share/classes/sun/nio/ch/exceptions rename to make/mksample/nio/multicast/Makefile index 55d295f871d4c5b03273f102d2c7d9188c975916..179d3d4a97c5895c7b05b0f2147aaf2f80b8ac49 100644 --- a/src/share/classes/sun/nio/ch/exceptions +++ b/make/mksample/nio/multicast/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,30 @@ # have any questions. # -# Generated exception classes for sun.nio.ch +# +# 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 -SINCE=1.4 -PACKAGE=sun.nio.ch -# This year should only change if the generated source is modified. -COPYRIGHT_YEARS=2000-2007 +all build: $(SAMPLE_FILES) +$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/% + $(install-file) -SUPER=IllegalStateException +clean clobber: + $(RM) -r $(SAMPLE_DST_DIR) -gen AlreadyBoundException " - * Unchecked exception thrown when an attempt is made to bind a {@link - * SocketChannel} that is already bound." \ - 9002280723481772026L +.PHONY: all build clean clobber diff --git a/make/netbeans/awt2d/README b/make/netbeans/awt2d/README index a990726b787c7d8b9d1aa1ad3c7b1c8275425d27..040c9e76919d4ad76f903542cf6a7e1905c3a091 100644 --- a/make/netbeans/awt2d/README +++ b/make/netbeans/awt2d/README @@ -145,7 +145,6 @@ Notes on using CND (C/C++ pack) with this project and NetBeans. (a somewhat complete list of awt and 2d native directories on windows): ../../src/share/javavm/export; - ../../src/share/javavm/include; ../../src/share/native/common; ../../src/share/native/sun/awt/debug; ../../src/share/native/sun/awt/image/cvutils; diff --git a/make/netbeans/jconsole/build.properties b/make/netbeans/jconsole/build.properties index ab2a0a1aef61ade7763efaf931802d760dcb3546..dd442d93d20d24bf876d81e43cf807d74ed32d06 100644 --- a/make/netbeans/jconsole/build.properties +++ b/make/netbeans/jconsole/build.properties @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# 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 @@ -44,3 +44,4 @@ build.jdk.version = 1.7.0 build.release = ${build.jdk.version}-opensource build.number = b00 jconsole.version = ${build.release}-${user.name}-${build.number} +jconsole.args = -debug diff --git a/make/netbeans/jconsole/build.xml b/make/netbeans/jconsole/build.xml index 0f51d1c3b5d2da1c0568cc30532387e95d32ba30..8d56df7c73d6c20eb17e8a0228de962bec89ff5d 100644 --- a/make/netbeans/jconsole/build.xml +++ b/make/netbeans/jconsole/build.xml @@ -1,5 +1,5 @@ - + - + - + - + + - + - + diff --git a/make/sun/awt/FILES_c_unix.gmk b/make/sun/awt/FILES_c_unix.gmk index c7ea9857da0b78f316418443320fbfb44a1282ba..f85635f00fb2df2fb851c43ff5322201337386f6 100644 --- a/make/sun/awt/FILES_c_unix.gmk +++ b/make/sun/awt/FILES_c_unix.gmk @@ -142,59 +142,59 @@ FILES_2D_c = \ # 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 --git a/make/sun/awt/FILES_export_unix.gmk b/make/sun/awt/FILES_export_unix.gmk index 3186785dcec9efd68227c04f6ef2aca59bccb640..43637e7c4cbbf66845d39c796998e768352a20be 100644 --- a/make/sun/awt/FILES_export_unix.gmk +++ b/make/sun/awt/FILES_export_unix.gmk @@ -60,48 +60,15 @@ FILES_export = \ 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 @@ FILES_export = \ 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 @@ FILES_export2 = \ 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 --git a/make/sun/awt/Makefile b/make/sun/awt/Makefile index e34d2f0901acd39dd096833eee3e078481eeac81..ed35dcd2bdfa452515a9fd8f4f88310d0bac30f4 100644 --- a/make/sun/awt/Makefile +++ b/make/sun/awt/Makefile @@ -28,17 +28,13 @@ PACKAGE = sun.awt LIBRARY = awt PRODUCT = sun -# # Tell Defs.gmk that VIS is needed -# VIS_NEEDED=true -include $(BUILDDIR)/common/Defs.gmk - -# # Use highest optimization level -# -_OPT = $(CC_HIGHEST_OPT) +OPTMIZATION_LEVEL = HIGHEST + +include $(BUILDDIR)/common/Defs.gmk OTHER_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES diff --git a/make/sun/awt/mapfile-mawt-vers b/make/sun/awt/mapfile-mawt-vers index a9a422927663d57a970da24a1e885a7492fa49b6..ca3b430c57bdf34c9985318563879749c23defd6 100644 --- a/make/sun/awt/mapfile-mawt-vers +++ b/make/sun/awt/mapfile-mawt-vers @@ -31,7 +31,7 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 --git a/make/sun/awt/mapfile-vers-linux b/make/sun/awt/mapfile-vers-linux index b9df2a164aa36fce2f13b1e468585aad8fff0d16..83afeebc7f26fc7c356f3adad68c5c5b6b74d251 100644 --- a/make/sun/awt/mapfile-vers-linux +++ b/make/sun/awt/mapfile-vers-linux @@ -170,7 +170,7 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 --git a/make/sun/awt/mawt.gmk b/make/sun/awt/mawt.gmk index ffe222c9a2ed9f2700b1848ac132621fa00f5d68..c7d1b41d02bab79e35b22c9a14d6a45bff03b3b7 100644 --- a/make/sun/awt/mawt.gmk +++ b/make/sun/awt/mawt.gmk @@ -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 @@ include $(BUILDDIR)/sun/awt/FILES_export_unix.gmk 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 @@ include $(BUILDDIR)/common/Library.gmk $(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 @@ CFLAGS += -DHEADLESS=$(HEADLESS) CPPFLAGS += -DHEADLESS=$(HEADLESS) OTHER_LDLIBS = else -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 +#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 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_OPT = 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 @@ endif 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 --git a/make/sun/cmm/kcms/Makefile b/make/sun/cmm/kcms/Makefile index 000f2527e5b5ff887377dcf3bb84e2c39676c005..10ff72b4f57638754b0eb448fcfa3545dd43c5ad 100644 --- a/make/sun/cmm/kcms/Makefile +++ b/make/sun/cmm/kcms/Makefile @@ -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 diff --git a/make/sun/font/Makefile b/make/sun/font/Makefile index ae06bbe822591f9af30faa7a0ede9c1fb6a4bb05..2663144a5f3e0747b3ac2c1b20746ad9c68ef0bd 100644 --- a/make/sun/font/Makefile +++ b/make/sun/font/Makefile @@ -35,6 +35,9 @@ PRODUCT = sun # Indicate we want the C++ compiler to do the linking. CPLUSPLUSLIBRARY=true +# Use higher optimization level +OPTIMIZATION_LEVEL = HIGHER + include $(BUILDDIR)/common/Defs.gmk # @@ -48,11 +51,6 @@ endif # Files # -# -# Use higher optimization level -# -_OPT = $(CC_HIGHER_OPT) - include FILES_c.gmk AUTO_FILES_JAVA_DIRS = sun/font diff --git a/make/sun/font/t2k/Makefile b/make/sun/font/t2k/Makefile index 65f7f99a4ddeb8a4ab97e88f3a766a7bb0f247e6..d01e825159b0ba730ae7463194ddaaf675157b84 100644 --- a/make/sun/font/t2k/Makefile +++ b/make/sun/font/t2k/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,12 +41,10 @@ CPLUSPLUSLIBRARY=true # for a few ones with native methods) so shouldn't clobber them. DONT_CLOBBER_CLASSES=true -include $(BUILDDIR)/common/Defs.gmk - -# # Use higher optimization level -# -_OPT = $(CC_HIGHER_OPT) +OPTIMIZATION_LEVEL = HIGHER + +include $(BUILDDIR)/common/Defs.gmk # # Files diff --git a/make/sun/image/generic/Makefile b/make/sun/image/generic/Makefile index 6157c79f59fd02725b58a5d57c06246459f6f304..5caedf6d7d0662488a873edd182a76178011e40d 100644 --- a/make/sun/image/generic/Makefile +++ b/make/sun/image/generic/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 @@ -31,12 +31,11 @@ BUILDDIR = ../../.. PACKAGE = sun.awt.medialib LIBRARY = mlib_image PRODUCT = sun -include $(BUILDDIR)/common/Defs.gmk -# # Use highest level of optimization on this library -# -_OPT = $(CC_HIGHEST_OPT) +OPTIMIZATION_LEVEL = HIGHEST + +include $(BUILDDIR)/common/Defs.gmk # # Use mapfile diff --git a/make/sun/image/vis/Makefile b/make/sun/image/vis/Makefile index 00c11c361b82a88777530302f793d87fd83bb105..b0e399b08787d49a38402ede7b26377580c8a0a4 100644 --- a/make/sun/image/vis/Makefile +++ b/make/sun/image/vis/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 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 @@ -31,17 +31,13 @@ PACKAGE = sun.awt.medialib LIBRARY = mlib_image_v PRODUCT = sun -# # Tell Defs.gmk we need VIS instructions -# VIS_NEEDED=true -include $(BUILDDIR)/common/Defs.gmk - -# # Select highest level of optimization for this library -# -_OPT = $(CC_HIGHEST_OPT) +OPTIMIZATION_LEVEL = HIGHEST + +include $(BUILDDIR)/common/Defs.gmk # # Use generic mapfile diff --git a/make/sun/jconsole/Makefile b/make/sun/jconsole/Makefile index bfbdccbfbd5f9eacfe91c6472c81ddc46a5d4970..ff27063bab8a3670b7870c08022ef3130a864fec 100644 --- a/make/sun/jconsole/Makefile +++ b/make/sun/jconsole/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2004-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 @@ -82,7 +82,7 @@ $(JARFILE): $(LIBDIR) $(FILES_class) $(FILES_png) $(FILES_gif) $(TEMPDIR)/manife $(BOOT_JAR_CMD) -cfm $(JARFILE) $(TEMPDIR)/manifest \ -C $(CLASSBINDIR) sun/tools/jconsole \ -C $(CLASSBINDIR) com/sun/tools/jconsole \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) clean clobber:: diff --git a/make/sun/jdbc/Makefile b/make/sun/jdbc/Makefile index 818a89d0e8bc0cb1ccbba195ce0fabd28ce7cb4c..d7e7eaf1530e434476cae9dbba1835ba320d23ea 100644 --- a/make/sun/jdbc/Makefile +++ b/make/sun/jdbc/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1996-2007 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 diff --git a/make/sun/jpeg/Makefile b/make/sun/jpeg/Makefile index e351376331691c45d67fe18f0b0b7fa77d9c7b27..f97e2cd08b850503f0b4b13d9865057c72282524 100644 --- a/make/sun/jpeg/Makefile +++ b/make/sun/jpeg/Makefile @@ -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 @@ -27,12 +27,11 @@ BUILDDIR = ../.. PACKAGE = sun.awt LIBRARY = jpeg PRODUCT = sun -include $(BUILDDIR)/common/Defs.gmk -# # Use highest optimization level -# -_OPT = $(CC_HIGHEST_OPT) +OPTIMIZATION_LEVEL = HIGHEST + +include $(BUILDDIR)/common/Defs.gmk # # Files diff --git a/make/sun/net/spi/nameservice/dns/Makefile b/make/sun/net/spi/nameservice/dns/Makefile index 0a7683f5dac144e7d2b058ada024980e9c99f24b..87d5e07f46474dd1415113fdca76c5045b86c872 100644 --- a/make/sun/net/spi/nameservice/dns/Makefile +++ b/make/sun/net/spi/nameservice/dns/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2006 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 @@ -67,7 +67,7 @@ $(JARFILE): $(CLASSDESTDIR)/META-INF/services/$(SERVICE_DESCRIPTION) \ $(BOOT_JAR_CMD) -cf $(JARFILE) \ -C $(CLASSDESTDIR) sun \ -C $(CLASSDESTDIR) META-INF \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) include $(BUILDDIR)/common/Classes.gmk diff --git a/make/sun/nio/Makefile b/make/sun/nio/Makefile index c8e8e37cbb4c88e872008c95fffef53749657cbc..8dd1f98ccfb9f30eb4d80765d18d1453611d074e 100644 --- a/make/sun/nio/Makefile +++ b/make/sun/nio/Makefile @@ -91,7 +91,7 @@ $(CHARSETS_JAR): $(FILES_class) $(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH) $(FI $(BOOT_JAR_CMD) cf $(CHARSETS_JAR) \ -C $(CLASSDESTDIR) sun \ -C $(CLASSDESTDIR) $(SERVICE_DESCRIPTION_PATH) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) clean:: diff --git a/make/sun/security/mscapi/Makefile b/make/sun/security/mscapi/Makefile index 8223b5367093be199222d89b696628e3c4df3079..08d6609e166173aacf2cd61bbf3bf1e06994d75b 100644 --- a/make/sun/security/mscapi/Makefile +++ b/make/sun/security/mscapi/Makefile @@ -210,7 +210,7 @@ build-jar: $(UNSIGNED_DIR)/sunmscapi.jar $(UNSIGNED_DIR)/sunmscapi.jar: build $(prep-target) $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/make/sun/security/pkcs11/Makefile b/make/sun/security/pkcs11/Makefile index 4508b20f843c57565082ee69b3a0563590b08163..f20910b7ed2add513d2c19c6cb02613f01e21226 100644 --- a/make/sun/security/pkcs11/Makefile +++ b/make/sun/security/pkcs11/Makefile @@ -210,7 +210,7 @@ build-jar: $(UNSIGNED_DIR)/sunpkcs11.jar $(UNSIGNED_DIR)/sunpkcs11.jar: build $(prep-target) $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/make/sun/text/Makefile b/make/sun/text/Makefile index d3d49355b58171d6aaba0b7aa4fca100d513465e..37b8522156af51236a9533960fecf1883b8eda84 100644 --- a/make/sun/text/Makefile +++ b/make/sun/text/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2001-2006 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 @@ -112,7 +112,7 @@ $(CLASSDESTDIR)/sun/text/resources/% : $(TEXT_SRCDIR)/% $(LOCALEDATA_JAR): $(EXTDIR) $(FILES_class) $(BIFILES) $(SPECIALFILES) $(prep-target) $(BOOT_JAR_CMD) -cf $@ -C $(CLASSDESTDIR) sun \ - $(JAR_JFLAGS) + $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) build: $(LOCALEDATA_JAR) diff --git a/make/tools/GenerateCharacter/check_class.c.template b/make/tools/GenerateCharacter/check_class.c.template index d9a880f09707a7e6a8376aed94dd036367a1698c..02307e02a6beed7efab207038488a3bd48af814c 100644 --- a/make/tools/GenerateCharacter/check_class.c.template +++ b/make/tools/GenerateCharacter/check_class.c.template @@ -1,5 +1,5 @@ /* - * Copyright 2002 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 @@ -37,7 +37,6 @@ #include "bool.h" #include "utf.h" #include "tree.h" -#include "sys_api.h" extern bool_t verify_class_codes(ClassClass *cb); diff --git a/src/share/back/ThreadReferenceImpl.c b/src/share/back/ThreadReferenceImpl.c index a85422863ba9d473980ba33a7a9598d9e4ed5d56..2b8e4782db13a4831cabbe812e6bb0629ab351e9 100644 --- a/src/share/back/ThreadReferenceImpl.c +++ b/src/share/back/ThreadReferenceImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/share/back/debugDispatch.c b/src/share/back/debugDispatch.c index 98a86fe588956e54b85244f852979091a79311ab..fa633799061d4db55119980f9b8890cfa2b5f47d 100644 --- a/src/share/back/debugDispatch.c +++ b/src/share/back/debugDispatch.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 @@ -41,7 +41,6 @@ #include "ArrayReferenceImpl.h" #include "EventRequestImpl.h" #include "StackFrameImpl.h" -#include "typedefs.h" static void **l1Array; diff --git a/src/share/back/error_messages.c b/src/share/back/error_messages.c index f40af69a335682f7779e8ccd92b96af89a44777d..30acacd4ef27966a80fa81da4670c993b5c593d3 100644 --- a/src/share/back/error_messages.c +++ b/src/share/back/error_messages.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,6 @@ #include "util.h" #include "proc_md.h" -#include "typedefs.h" /* Maximim length of a message */ #define MAX_MESSAGE_LEN MAXPATHLEN*2+512 diff --git a/src/share/back/eventFilter.c b/src/share/back/eventFilter.c index 955cf8813b47f45924217f33a16db304afd2ff38..5d135a78c316d0d0d74629850fd3e44c0e9e3b99 100644 --- a/src/share/back/eventFilter.c +++ b/src/share/back/eventFilter.c @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 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 diff --git a/src/share/back/inStream.c b/src/share/back/inStream.c index 45534fcdc546d4ccbe82e16db1712cff79ac84c5..1f5b685c5adf5cca5d6a762df2dff9353f52b332 100644 --- a/src/share/back/inStream.c +++ b/src/share/back/inStream.c @@ -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 @@ -30,7 +30,6 @@ #include "bag.h" #include "commonRef.h" #include "FrameID.h" -#include "typedefs.h" #define INITIAL_REF_ALLOC 50 #define SMALLEST(a, b) ((a) < (b)) ? (a) : (b) diff --git a/src/share/back/outStream.h b/src/share/back/outStream.h index a57cc47115175140f8bc2708e3ff8b6482a224c2..83d1eb10ffebdc4bfcf71373471ac131de118033 100644 --- a/src/share/back/outStream.h +++ b/src/share/back/outStream.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 @@ -26,8 +26,6 @@ #ifndef JDWP_OUTSTREAM_H #define JDWP_OUTSTREAM_H -#include "typedefs.h" - #include "transport.h" #include "FrameID.h" diff --git a/src/share/back/transport.c b/src/share/back/transport.c index f259a93eef3aa61eec9ff45c4af9edd25aa23d75..05c73941614ede78661303aa7efb20569b322376 100644 --- a/src/share/back/transport.c +++ b/src/share/back/transport.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/share/bin/emessages.h b/src/share/bin/emessages.h index 03824bba5d1570138953afcd333d194c5257f263..008cc1f906a6e93cb7894c92ae9bbba7d8b7c3e0 100644 --- a/src/share/bin/emessages.h +++ b/src/share/bin/emessages.h @@ -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 --git a/src/share/bin/java.c b/src/share/bin/java.c index f7cbcdc95bce46ab467dd1af347b882dd9ac5c95..89ae857b1366baadcd4ee0ba7c82b818b59e0db0 100644 --- a/src/share/bin/java.c +++ b/src/share/bin/java.c @@ -148,7 +148,7 @@ static void ShowSplashScreen(); 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 @@ JavaMain(void * _args) 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 @@ JavaMain(void * _args) 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 @@ JavaMain(void * _args) 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 @@ JavaMain(void * _args) "([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 @@ JavaMain(void * _args) 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 @@ JavaMain(void * _args) (*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 @@ JavaMain(void * _args) /* 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 @@ JavaMain(void * _args) * 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 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { if (loopCount > knownVMsCount) { if (!speculative) { - ReportErrorMessage(CFG_ERROR1); + JLI_ReportErrorMessage(CFG_ERROR1); exit(1); } else { return "ERROR"; @@ -645,7 +645,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { 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 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { 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 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { break; case VM_ERROR: if (!speculative) { - ReportErrorMessage(CFG_ERROR3, jvmtype); + JLI_ReportErrorMessage(CFG_ERROR3, jvmtype); exit(1); } else { return "ERROR"; @@ -879,9 +879,9 @@ SelectVersion(int argc, char **argv, char **main_class) 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 @@ SelectVersion(int argc, char **argv, char **main_class) * 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 @@ SelectVersion(int argc, char **argv, char **main_class) 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 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile, * 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 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile, 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 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) #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 @@ TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***parg 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 @@ AddApplicationOptions(int cpathc, const char **cpathv) } if (!GetApplicationHome(home, sizeof(home))) { - ReportErrorMessage(CFG_ERROR5); + JLI_ReportErrorMessage(CFG_ERROR5); return JNI_FALSE; } @@ -1691,7 +1691,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) 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 @@ RemovableOption(char * option) * 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 --git a/src/share/bin/java.h b/src/share/bin/java.h index e6a08f3cf009b00ea68a6282164d4e5585745ec0..23871b5d2a1a045285a52da918417349e846935a 100644 --- a/src/share/bin/java.h +++ b/src/share/bin/java.h @@ -121,24 +121,20 @@ void CreateExecutionEnvironment(int *_argc, 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, ...); -/* - * Report an error message only to stderr. - */ -void ReportMessage(const char * message, ...); +/* Reports an error message only to stderr. */ +void JLI_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 --git a/src/share/classes/com/sun/jmx/defaults/JmxProperties.java b/src/share/classes/com/sun/jmx/defaults/JmxProperties.java index 89cd5bf16bf0c814cc1bc4e70134fe070db5e99a..fcf769bf64335bd9a43969b53c2cc21ba9881ad9 100644 --- a/src/share/classes/com/sun/jmx/defaults/JmxProperties.java +++ b/src/share/classes/com/sun/jmx/defaults/JmxProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 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 @@ -176,6 +176,18 @@ public class JmxProperties { public static final String RELATION_LOGGER_NAME = "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. */ diff --git a/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java b/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ca2462b32ad9df58df7e2cf0f5a750245bf2dfe4 --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java @@ -0,0 +1,77 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class DaemonThreadFactory implements ThreadFactory { + public DaemonThreadFactory(String nameTemplate) { + this(nameTemplate, null); + } + + // nameTemplate should be a format with %d in it, which will be replaced + // by a sequence number of threads created by this factory. + public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) { + if (logger.debugOn()) { + logger.debug("DaemonThreadFactory", + "Construct a new daemon factory: "+nameTemplate); + } + + if (threadGroup == null) { + SecurityManager s = System.getSecurityManager(); + threadGroup = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + } + + this.nameTemplate = nameTemplate; + this.threadGroup = threadGroup; + } + + public Thread newThread(Runnable r) { + final String name = + String.format(nameTemplate, threadNumber.getAndIncrement()); + Thread t = new Thread(threadGroup, r, name, 0); + t.setDaemon(true); + if (t.getPriority() != Thread.NORM_PRIORITY) + t.setPriority(Thread.NORM_PRIORITY); + + if (logger.debugOn()) { + logger.debug("newThread", + "Create a new daemon thread with the name "+t.getName()); + } + + return t; + } + + private final String nameTemplate; + private final ThreadGroup threadGroup; + private final AtomicInteger threadNumber = new AtomicInteger(1); + + private static final ClassLogger logger = + new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory"); +} diff --git a/src/share/classes/com/sun/jmx/event/EventBuffer.java b/src/share/classes/com/sun/jmx/event/EventBuffer.java new file mode 100644 index 0000000000000000000000000000000000000000..ed804791097bbb90ec05908a970a7e76248f7dfc --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/EventBuffer.java @@ -0,0 +1,252 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; + +public class EventBuffer { + + public EventBuffer() { + this(Integer.MAX_VALUE, null); + } + + public EventBuffer(int capacity) { + this(capacity, new ArrayList()); + } + + public EventBuffer(int capacity, final List list) { + if (logger.traceOn()) { + logger.trace("EventBuffer", "New buffer with the capacity: " + +capacity); + } + if (capacity < 1) { + throw new IllegalArgumentException( + "The capacity must be bigger than 0"); + } + + if (list == null) { + throw new NullPointerException("Null list."); + } + + this.capacity = capacity; + this.list = list; + } + + public void add(TargetedNotification tn) { + if (logger.traceOn()) { + logger.trace("add", "Add one notif."); + } + + synchronized(lock) { + if (list.size() == capacity) { // have to throw one + passed++; + list.remove(0); + + if (logger.traceOn()) { + logger.trace("add", "Over, remove the oldest one."); + } + } + + list.add(tn); + lock.notify(); + } + } + + public void add(TargetedNotification[] tns) { + if (tns == null || tns.length == 0) { + return; + } + + if (logger.traceOn()) { + logger.trace("add", "Add notifs: "+tns.length); + } + + synchronized(lock) { + final int d = list.size() - capacity + tns.length; + if (d > 0) { // have to throw + passed += d; + if (logger.traceOn()) { + logger.trace("add", + "Over, remove the oldest: "+d); + } + if (tns.length <= capacity){ + list.subList(0, d).clear(); + } else { + list.clear(); + TargetedNotification[] tmp = + new TargetedNotification[capacity]; + System.arraycopy(tns, tns.length-capacity, tmp, 0, capacity); + tns = tmp; + } + } + + Collections.addAll(list,tns); + lock.notify(); + } + } + + public NotificationResult fetchNotifications(long startSequenceNumber, + long timeout, + int maxNotifications) { + if (logger.traceOn()) { + logger.trace("fetchNotifications", + "Being called: " + +startSequenceNumber+" " + +timeout+" "+maxNotifications); + } + if (startSequenceNumber < 0 || + timeout < 0 || + maxNotifications < 0) { + throw new IllegalArgumentException("Negative value."); + } + + TargetedNotification[] tns = new TargetedNotification[0]; + long earliest = startSequenceNumber < passed ? + passed : startSequenceNumber; + long next = earliest; + + final long startTime = System.currentTimeMillis(); + long toWait = timeout; + synchronized(lock) { + int toSkip = (int)(startSequenceNumber - passed); + + // skip those before startSequenceNumber. + while (!closed && toSkip > 0) { + toWait = timeout - (System.currentTimeMillis() - startTime); + if (list.size() == 0) { + if (toWait <= 0) { + // the notification of startSequenceNumber + // does not arrive yet. + return new NotificationResult(startSequenceNumber, + startSequenceNumber, + new TargetedNotification[0]); + } + + waiting(toWait); + continue; + } + + if (toSkip <= list.size()) { + list.subList(0, toSkip).clear(); + passed += toSkip; + + break; + } else { + passed += list.size(); + toSkip -= list.size(); + + list.clear(); + } + } + + earliest = passed; + + if (list.size() == 0) { + toWait = timeout - (System.currentTimeMillis() - startTime); + + waiting(toWait); + } + + if (list.size() == 0) { + tns = new TargetedNotification[0]; + } else if (list.size() <= maxNotifications) { + tns = list.toArray(new TargetedNotification[0]); + } else { + tns = new TargetedNotification[maxNotifications]; + for (int i=0; i 0) { + try { + lock.wait(toWait); + + toWait = timeout - (System.currentTimeMillis() - startTime); + } catch (InterruptedException ire) { + logger.trace("waiting", ire); + break; + } + } + } + } + + private final int capacity; + private final List list; + private boolean closed; + + private long passed = 0; + private final int[] lock = new int[0]; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventBuffer"); +} diff --git a/src/solaris/classes/sun/awt/motif/MInputMethodDescriptor.java b/src/share/classes/com/sun/jmx/event/EventClientFactory.java similarity index 63% rename from src/solaris/classes/sun/awt/motif/MInputMethodDescriptor.java rename to src/share/classes/com/sun/jmx/event/EventClientFactory.java index cbd9a73f63c7dc3bf5b80418cc87af1b454ceaae..3cab63ccdc686a5daf8003cd854e573539b88b7b 100644 --- a/src/solaris/classes/sun/awt/motif/MInputMethodDescriptor.java +++ b/src/share/classes/com/sun/jmx/event/EventClientFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,26 +23,24 @@ * have any questions. */ +package com.sun.jmx.event; -package sun.awt.motif; - -import java.awt.im.spi.InputMethod; -import sun.awt.X11InputMethodDescriptor; +import javax.management.event.*; /** - * 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. + * Implemented by objects which are using an {@link EventClient} to + * subscribe for Notifications. * - * @since JDK1.3 */ - -class MInputMethodDescriptor extends X11InputMethodDescriptor { - +public interface EventClientFactory { /** - * @see java.awt.im.spi.InputMethodDescriptor#createInputMethod - */ - public InputMethod createInputMethod() throws Exception { - return new MInputMethod(); - } + * Returns the {@code EventClient} that the object implementing this + * interface uses to subscribe for Notifications. This method returns + * {@code null} if no {@code EventClient} can be used - e.g. because + * the underlying server does not have any {@link EventDelegate}. + * + * @return an {@code EventClient} or {@code null}. + **/ + public EventClient getEventClient(); + } diff --git a/src/share/classes/com/sun/jmx/event/EventConnection.java b/src/share/classes/com/sun/jmx/event/EventConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..adadef1931dbef949b1408af6dc238cabc872564 --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/EventConnection.java @@ -0,0 +1,81 @@ +/* + * 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 com.sun.jmx.event; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import javax.management.MBeanServerConnection; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventConsumer; +import javax.management.event.NotificationManager; + +/** + * Override the methods related to the notification to use the + * Event service. + */ +public interface EventConnection extends MBeanServerConnection, EventConsumer { + public EventClient getEventClient(); + + public static class Factory { + public static EventConnection make( + final MBeanServerConnection mbsc, + final EventClient eventClient) + throws IOException { + if (!mbsc.isRegistered(EventClientDelegate.OBJECT_NAME)) { + throw new IOException( + "The server does not support the event service."); + } + InvocationHandler ih = new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + Class intf = method.getDeclaringClass(); + try { + if (intf.isInstance(eventClient)) + return method.invoke(eventClient, args); + else + return method.invoke(mbsc, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + }; + // It is important to declare NotificationManager.class first + // in the array below, so that the relevant addNL and removeNL + // methods will show up with method.getDeclaringClass() as + // being from that interface and not MBeanServerConnection. + return (EventConnection) Proxy.newProxyInstance( + NotificationManager.class.getClassLoader(), + new Class[] { + NotificationManager.class, EventConnection.class, + }, + ih); + } + } +} diff --git a/src/share/classes/com/sun/jmx/event/EventParams.java b/src/share/classes/com/sun/jmx/event/EventParams.java new file mode 100644 index 0000000000000000000000000000000000000000..7d875e1385b727a28f4cb1bec86d553de2f7203f --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/EventParams.java @@ -0,0 +1,65 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.mbeanserver.GetPropertyAction; +import com.sun.jmx.remote.util.ClassLogger; +import java.security.AccessController; +import javax.management.event.EventClient; + +/** + * + * @author sjiang + */ +public class EventParams { + public static final String DEFAULT_LEASE_TIMEOUT = + "com.sun.event.lease.time"; + + + @SuppressWarnings("cast") // cast for jdk 1.5 + public static long getLeaseTimeout() { + long timeout = EventClient.DEFAULT_LEASE_TIMEOUT; + try { + final GetPropertyAction act = + new GetPropertyAction(DEFAULT_LEASE_TIMEOUT); + final String s = (String)AccessController.doPrivileged(act); + if (s != null) { + timeout = Long.parseLong(s); + } + } catch (RuntimeException e) { + logger.fine("getLeaseTimeout", "exception getting property", e); + } + + return timeout; + } + + /** Creates a new instance of EventParams */ + private EventParams() { + } + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventParams"); +} diff --git a/src/share/classes/com/sun/jmx/event/LeaseManager.java b/src/share/classes/com/sun/jmx/event/LeaseManager.java new file mode 100644 index 0000000000000000000000000000000000000000..e1761011f0e0729e0d286534ce3021b948c4d292 --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/LeaseManager.java @@ -0,0 +1,153 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + *

Manage a renewable lease. The lease can be renewed indefinitely + * but if the lease runs to its current expiry date without being renewed + * then the expiry callback is invoked. If the lease has already expired + * when renewal is attempted then the lease method returns zero.

+ * @author sjiang + * @author emcmanus + */ +// The synchronization logic of this class is tricky to deal correctly with the +// case where the lease expires at the same time as the |lease| or |stop| method +// is called. If the lease is active then the field |scheduled| represents +// the expiry task; otherwise |scheduled| is null. Renewing or stopping the +// lease involves canceling this task and setting |scheduled| either to a new +// task (to renew) or to null (to stop). +// +// Suppose the expiry task runs at the same time as the |lease| method is called. +// If the task enters its synchronized block before the method starts, then +// it will set |scheduled| to null and the method will return 0. If the method +// starts before the task enters its synchronized block, then the method will +// cancel the task which will see that when it later enters the block. +// Similar reasoning applies to the |stop| method. It is not expected that +// different threads will call |lease| or |stop| simultaneously, although the +// logic should be correct then too. +public class LeaseManager { + public LeaseManager(Runnable callback) { + this(callback, EventParams.getLeaseTimeout()); + } + + public LeaseManager(Runnable callback, long timeout) { + if (logger.traceOn()) { + logger.trace("LeaseManager", "new manager with lease: "+timeout); + } + if (callback == null) { + throw new NullPointerException("Null callback."); + } + if (timeout <= 0) + throw new IllegalArgumentException("Timeout must be positive: " + timeout); + + this.callback = callback; + schedule(timeout); + } + + /** + *

Renew the lease for the given time. The new time can be shorter + * than the previous one, in which case the lease will expire earlier + * than it would have.

+ * + *

Calling this method after the lease has expired will return zero + * immediately and have no other effect.

+ * + * @param timeout the new lifetime. If zero, the lease + * will expire immediately. + */ + public synchronized long lease(long timeout) { + if (logger.traceOn()) { + logger.trace("lease", "new lease to: "+timeout); + } + + if (timeout < 0) + throw new IllegalArgumentException("Negative lease: " + timeout); + + if (scheduled == null) + return 0L; + + scheduled.cancel(false); + + if (logger.traceOn()) + logger.trace("lease", "start lease: "+timeout); + schedule(timeout); + + return timeout; + } + + private class Expire implements Runnable { + ScheduledFuture task; + + public void run() { + synchronized (LeaseManager.this) { + if (task.isCancelled()) + return; + scheduled = null; + } + callback.run(); + executor.shutdown(); + } + } + + private synchronized void schedule(long timeout) { + Expire expire = new Expire(); + scheduled = executor.schedule(expire, timeout, TimeUnit.MILLISECONDS); + expire.task = scheduled; + } + + /** + *

Cancel the lease without calling the expiry callback.

+ */ + public synchronized void stop() { + logger.trace("stop", "canceling lease"); + scheduled.cancel(false); + scheduled = null; + try { + executor.shutdown(); + } catch (SecurityException e) { + // OK: caller doesn't have RuntimePermission("modifyThread") + // which is unlikely in reality but triggers a test failure otherwise + logger.trace("stop", "exception from executor.shutdown", e); + } + } + + private final Runnable callback; + private ScheduledFuture scheduled; // If null, the lease has expired. + + private final ScheduledExecutorService executor + = Executors.newScheduledThreadPool(1, + new DaemonThreadFactory("JMX LeaseManager %d")); + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "LeaseManager"); + +} diff --git a/src/share/classes/com/sun/jmx/event/LeaseRenewer.java b/src/share/classes/com/sun/jmx/event/LeaseRenewer.java new file mode 100644 index 0000000000000000000000000000000000000000..b3f7c7fee07bb96b10e997df30affbf3a4019db6 --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/LeaseRenewer.java @@ -0,0 +1,143 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * + * @author sjiang + */ +public class LeaseRenewer { + public LeaseRenewer(ScheduledExecutorService scheduler, Callable doRenew) { + if (logger.traceOn()) { + logger.trace("LeaseRenewer", "New LeaseRenewer."); + } + + if (doRenew == null) { + throw new NullPointerException("Null job to call server."); + } + + this.doRenew = doRenew; + nextRenewTime = System.currentTimeMillis(); + + this.scheduler = scheduler; + future = this.scheduler.schedule(myRenew, 0, TimeUnit.MILLISECONDS); + } + + public void close() { + if (logger.traceOn()) { + logger.trace("close", "Close the lease."); + } + + synchronized(lock) { + if (closed) { + return; + } else { + closed = true; + } + } + + try { + future.cancel(false); // not interrupt if running + } catch (Exception e) { + // OK + if (logger.debugOn()) { + logger.debug("close", "Failed to cancel the leasing job.", e); + } + } + } + + public boolean closed() { + synchronized(lock) { + return closed; + } + } + + // ------------------------------ + // private + // ------------------------------ + private final Runnable myRenew = new Runnable() { + public void run() { + synchronized(lock) { + if (closed()) { + return; + } + } + + long next = nextRenewTime - System.currentTimeMillis(); + if (next < MIN_MILLIS) { + try { + if (logger.traceOn()) { + logger.trace("myRenew-run", ""); + } + next = doRenew.call().longValue(); + + } catch (Exception e) { + logger.fine("myRenew-run", "Failed to renew lease", e); + close(); + } + + if (next > 0 && next < Long.MAX_VALUE) { + next = next/2; + next = (next < MIN_MILLIS) ? MIN_MILLIS : next; + } else { + close(); + } + } + + nextRenewTime = System.currentTimeMillis() + next; + + if (logger.traceOn()) { + logger.trace("myRenew-run", "Next leasing: "+next); + } + + synchronized(lock) { + if (!closed) { + future = scheduler.schedule(this, next, TimeUnit.MILLISECONDS); + } + } + } + }; + + private final Callable doRenew; + private ScheduledFuture future; + private boolean closed = false; + private long nextRenewTime; + + private final int[] lock = new int[0]; + + private final ScheduledExecutorService scheduler; + + private static final long MIN_MILLIS = 50; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "LeaseRenewer"); +} diff --git a/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java b/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java new file mode 100644 index 0000000000000000000000000000000000000000..a87e2dfd6f55f2592b0a47404df6cff66cacdb9f --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java @@ -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. 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.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; + + +public class ReceiverBuffer { + public void addNotifs(NotificationResult nr) { + if (nr == null) { + return; + } + + TargetedNotification[] tns = nr.getTargetedNotifications(); + + if (logger.traceOn()) { + logger.trace("addNotifs", "" + tns.length); + } + + long impliedStart = nr.getEarliestSequenceNumber(); + final long missed = impliedStart - start; + start = nr.getNextSequenceNumber(); + + if (missed > 0) { + if (logger.traceOn()) { + logger.trace("addNotifs", + "lost: "+missed); + } + + lost += missed; + } + + Collections.addAll(notifList, nr.getTargetedNotifications()); + } + + public TargetedNotification[] removeNotifs() { + if (logger.traceOn()) { + logger.trace("removeNotifs", String.valueOf(notifList.size())); + } + + if (notifList.size() == 0) { + return null; + } + + TargetedNotification[] ret = notifList.toArray( + new TargetedNotification[]{}); + notifList.clear(); + + return ret; + } + + public int size() { + return notifList.size(); + } + + public int removeLost() { + int ret = lost; + lost = 0; + return ret; + } + + private List notifList + = new ArrayList(); + private long start = 0; + private int lost = 0; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "ReceiverBuffer"); +} diff --git a/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java new file mode 100644 index 0000000000000000000000000000000000000000..768ed6f30fa3b90f51a677ab6a515b8d5af86ace --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java @@ -0,0 +1,119 @@ +/* + * 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 com.sun.jmx.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + *

A task that is repeatedly run by an Executor. The task will be + * repeated as long as the {@link #isSuspended()} method returns true. Once + * that method returns false, the task is no longer executed until someone + * calls {@link #resume()}.

+ * @author sjiang + */ +public abstract class RepeatedSingletonJob implements Runnable { + public RepeatedSingletonJob(Executor executor) { + if (executor == null) { + throw new NullPointerException("Null executor!"); + } + + this.executor = executor; + } + + public boolean isWorking() { + return working; + } + + public void resume() { + + synchronized(this) { + if (!working) { + if (logger.traceOn()) { + logger.trace("resume", ""); + } + working = true; + execute(); + } + } + } + + public abstract void task(); + public abstract boolean isSuspended(); + + public void run() { + if (logger.traceOn()) { + logger.trace("run", "execute the task"); + } + try { + task(); + } catch (Exception e) { + // A correct task() implementation should not throw exceptions. + // It may cause isSuspended() to start returning true, though. + logger.trace("run", "failed to execute the task", e); + } + + synchronized(this) { + if (!isSuspended()) { + execute(); + } else { + if (logger.traceOn()) { + logger.trace("run", "suspend the task"); + } + working = false; + } + } + + } + + private void execute() { + try { + executor.execute(this); + } catch (RejectedExecutionException e) { + logger.warning( + "execute", + "Executor threw exception (" + this.getClass().getName() + ")", + e); + throw new RejectedExecutionException( + "Executor.execute threw exception -" + + "should not be possible", e); + // User-supplied Executor should not be configured in a way that + // might cause this exception, for example if it is shared between + // several client objects and doesn't have capacity for one job + // from each one. CR 6732037 will add text to the spec explaining + // the problem. The rethrown exception will propagate either out + // of resume() to user code, or out of run() to the Executor + // (which will probably ignore it). + } + } + + private boolean working = false; + private final Executor executor; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "RepeatedSingletonJob"); +} diff --git a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index 99b10ad1e8c8246eb642b28a0410c1efb371f535..7da3406b911e0a06c681c3afe6b61d55487258ba 100644 --- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -25,33 +25,49 @@ package com.sun.jmx.interceptor; -// java import + +// 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.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import java.util.logging.Level; +import java.util.Queue; import java.util.Set; -import java.util.HashSet; import java.util.WeakHashMap; -import java.lang.ref.WeakReference; -import java.security.AccessControlContext; -import java.security.Permission; -import java.security.ProtectionDomain; -import java.security.AccessController; -import java.security.PrivilegedAction; +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.MBeanTrustPermission; 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.ReflectionException; 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 @@ import javax.management.NotificationBroadcasterSupport; * * @since 1.5 */ -public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { +public class DefaultMBeanServerInterceptor + extends MBeanServerInterceptorSupport { /** The MBeanInstantiator object used by the * DefaultMBeanServerInterceptor */ @@ -123,7 +126,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { * 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { * @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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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); @@ -453,11 +463,12 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { final ResourceContext context = unregisterFromRepository(resource, instance, name); - - if (instance instanceof MBeanRegistration) - postDeregisterInvoke((MBeanRegistration) instance); - - context.done(); + try { + if (instance instanceof MBeanRegistration) + postDeregisterInvoke(name,(MBeanRegistration) instance); + } finally { + context.done(); + } } public ObjectInstance getObjectInstance(ObjectName name) @@ -466,7 +477,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "getObjectInstance"); + checkMBeanPermission(mbeanServerName, + instance, null, name, "getObjectInstance"); final String className = getClassName(instance); @@ -478,7 +490,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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". // @@ -491,7 +503,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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) { @@ -515,11 +527,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectInstancesFromFilteredNamedObjects(list, query)); } @@ -529,7 +536,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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". // @@ -542,7 +549,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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) { @@ -571,11 +578,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectNamesFromFilteredNamedObjects(list, query)); } @@ -588,8 +590,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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)); } @@ -599,7 +601,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 // @@ -611,8 +613,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 = ObjectName.valueOf(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 @@ -656,7 +658,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } final DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute, name, "getAttribute"); + checkMBeanPermission(mbeanServerName, instance, attribute, + name, "getAttribute"); try { return instance.getAttribute(attribute); @@ -701,7 +704,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // 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 @@ -710,14 +713,15 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 { @@ -755,7 +759,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute.getName(), + checkMBeanPermission(mbeanServerName, instance, attribute.getName(), name, "setAttribute"); try { @@ -798,7 +802,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // 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 @@ -807,7 +811,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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) { @@ -831,7 +835,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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) { @@ -933,8 +938,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { "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. @@ -960,16 +964,17 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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); @@ -986,32 +991,35 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // context = registerWithRepository(resource, mbean, logicalName); + registerFailed = false; registered = true; + } finally { - postRegister(mbean, registered, registerFailed); + try { + postRegister(logicalName, mbean, registered, registerFailed); + } finally { + if (registered && context!=null) context.done(); + } } - - context.done(); return new ObjectInstance(logicalName, classname); } 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( @@ -1051,7 +1059,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } private static void postRegister( - DynamicMBean mbean, boolean registrationDone, boolean registerFailed) { + ObjectName logicalName, DynamicMBean mbean, + boolean registrationDone, boolean registerFailed) { if (registerFailed && mbean instanceof DynamicMBean2) ((DynamicMBean2) mbean).registerFailed(); @@ -1059,11 +1068,19 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if (mbean instanceof MBeanRegistration) ((MBeanRegistration) mbean).postRegister(registrationDone); } catch (RuntimeException e) { + MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ + "]: " + "Exception thrown by postRegister: " + + "rethrowing <"+e+">, but keeping the MBean registered"); throw new RuntimeMBeanException(e, - "RuntimeException thrown in postRegister method"); + "RuntimeException thrown in postRegister method: "+ + "rethrowing <"+e+">, but keeping the MBean registered"); } catch (Error er) { + MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ + "]: " + "Error thrown by postRegister: " + + "rethrowing <"+er+">, but keeping the MBean registered"); throw new RuntimeErrorException(er, - "Error thrown in postRegister method"); + "Error thrown in postRegister method: "+ + "rethrowing <"+er+">, but keeping the MBean registered"); } } @@ -1076,15 +1093,28 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } } - private static void postDeregisterInvoke(MBeanRegistration moi) { + private static void postDeregisterInvoke(ObjectName mbean, + MBeanRegistration moi) { try { moi.postDeregister(); } catch (RuntimeException e) { + MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ + "]: " + "Exception thrown by postDeregister: " + + "rethrowing <"+e+">, although the MBean is succesfully " + + "unregistered"); throw new RuntimeMBeanException(e, - "RuntimeException thrown in postDeregister method"); + "RuntimeException thrown in postDeregister method: "+ + "rethrowing <"+e+ + ">, although the MBean is sucessfully unregistered"); } catch (Error er) { + MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ + "]: " + "Error thrown by postDeregister: " + + "rethrowing <"+er+">, although the MBean is succesfully " + + "unregistered"); throw new RuntimeErrorException(er, - "Error thrown in postDeregister method"); + "Error thrown in postDeregister method: "+ + "rethrowing <"+er+ + ">, although the MBean is sucessfully unregistered"); } } @@ -1139,7 +1169,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if one is supplied where it shouldn't be). */ final String completeName = domain + name; - return Util.newObjectName(completeName); + return ObjectName.valueOf(completeName); } public String getDefaultDomain() { @@ -1205,7 +1235,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "addNotificationListener"); + checkMBeanPermission(mbeanServerName, instance, null, + name, "addNotificationListener"); NotificationBroadcaster broadcaster = getNotificationBroadcaster(name, instance, @@ -1342,7 +1373,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, + checkMBeanPermission(mbeanServerName, instance, null, name, "removeNotificationListener"); /* We could simplify the code by assigning broadcaster after @@ -1413,7 +1444,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throw new JMRuntimeException("MBean " + name + "has no MBeanInfo"); - checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo"); + checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo"); return mbi; } @@ -1421,8 +1452,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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); @@ -1473,7 +1505,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceNotFoundException { DynamicMBean instance = getMBean(mbeanName); - checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); + checkMBeanPermission(mbeanServerName, instance, null, mbeanName, + "getClassLoaderFor"); return getResourceLoader(instance); } @@ -1488,12 +1521,13 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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); @@ -1543,7 +1577,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } } else { // Access the filter - MBeanServer oldServer = QueryEval.getMBeanServer(); + final MBeanServer oldServer = QueryEval.getMBeanServer(); query.setMBeanServer(server); try { for (NamedObject no : list) { @@ -1792,26 +1826,30 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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); @@ -1877,6 +1915,12 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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 = @@ -1942,6 +1986,57 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 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.addInterceptorFor(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.removeInterceptorFor(logicalName, namespace, postQueue); + } + /** * Registers a ClassLoader with the CLR. * This method is called by the ResourceContext from within the @@ -1995,6 +2090,52 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } } + + /** + * 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 @@ -2040,10 +2181,16 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { */ 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 --git a/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..4a79567fed14e7941bc69d16a24c041481a26a88 --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java @@ -0,0 +1,557 @@ +/* + * 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. + // + 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 addInterceptorFor(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 removeInterceptorFor(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 final ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).createMBean(className,name); + } + + // From MBeanServer + public final 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 final 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 final 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 final ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).registerMBean(object,name); + } + + // From MBeanServer + public final void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + getInterceptorForInstance(name).unregisterMBean(name); + } + + // From MBeanServer + public final ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).getObjectInstance(name); + } + + // From MBeanServer + public final Set queryMBeans(ObjectName name, + QueryExp query) { + final QueryInterceptor queryInvoker = + getInterceptorForQuery(name); + if (queryInvoker == null) return Collections.emptySet(); + else return queryInvoker.queryMBeans(name,query); + } + + // From MBeanServer + public final Set queryNames(ObjectName name, QueryExp query) { + final QueryInterceptor queryInvoker = + getInterceptorForQuery(name); + if (queryInvoker == null) return Collections.emptySet(); + else return queryInvoker.queryNames(name,query); + } + + // From MBeanServer + public final 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 final Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttribute(name,attribute); + } + + // From MBeanServer + public final AttributeList getAttributes(ObjectName name, + String[] attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttributes(name,attributes); + } + + // From MBeanServer + public final void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + getInterceptorForInstance(name).setAttribute(name,attribute); + } + + // From MBeanServer + public final AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).setAttributes(name,attributes); + } + + // From MBeanServer + public final 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 final void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name). + addNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public final void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name). + addNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public final MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + return getInterceptorForInstance(name).getMBeanInfo(name); + } + + + // From MBeanServer + public final boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).isInstanceOf(name,className); + } + + // From MBeanServer + public final ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return getInterceptorForInstance(mbeanName). + getClassLoaderFor(mbeanName); + } + + // From MBeanServer + public final ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + return getInterceptorForInstance(loaderName). + getClassLoader(loaderName); + } + +} diff --git a/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..9b9b1d6b19c72d5e78ea02c0b0430c1217cfd5fe --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java @@ -0,0 +1,356 @@ +/* + * 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.nextInterceptor); + 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); + + if (pattern == null) pattern = ObjectName.WILDCARD; + final boolean all = pattern.getDomain().equals("*"); + + 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 nextInterceptor; + 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) { + nextInterceptor = 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 = nextInterceptor.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 nextInterceptor; + } + + /** + * 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, nextInterceptor.getDomains() contains all domains. + // In addition, nextInterceptor will perform the necessary + // MBeanPermission checks for getDomains(). + // + return nextInterceptor.getDomains(); + } + + /** + * Returns the number of MBeans registered in the MBean server. + */ + @Override + public Integer getMBeanCount() { + int count = getNextInterceptor().getMBeanCount(); + final String[] keys = getKeys(); + for (String key:keys) { + final MBeanServer mbs = getInterceptor(key); + if (mbs == null) continue; + count += mbs.getMBeanCount(); + } + return count; + } +} diff --git a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java index c0a1844f0cc4be552da3bc886dee624b83a6dd57..7b2d836a621b457030f8b0dd997f0925dd41e80a 100644 --- a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java +++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java @@ -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 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.OperationsException; -import javax.management.MBeanNotificationInfo; -import javax.management.JMRuntimeException; +import java.io.ObjectInputStream; import javax.management.InstanceNotFoundException; -import javax.management.NotCompliantMBeanException; -import javax.management.MBeanRegistrationException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.MBeanServer; 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.OperationsException; +import javax.management.ReflectionException; import javax.management.loading.ClassLoaderRepository; /** @@ -85,618 +64,67 @@ import javax.management.loading.ClassLoaderRepository; * * @since 1.5 */ -public interface MBeanServerInterceptor extends MBeanServerConnection { - /** - * 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. - */ - public ObjectInstance createMBean(String className, ObjectName name, - Object params[], String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException; - - /** - * 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. - * - */ - public ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object params[], - String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, 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. - */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException; - - /** - * 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. - */ - 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; - - /** - * 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. - */ - 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; - - /** - * 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(); - +public interface MBeanServerInterceptor extends MBeanServer { /** - * Returns the list of domains in which any MBean is currently - * registered. + * This method should never be called. + * Usually hrows UnsupportedOperationException. */ - public String[] getDomains(); - + public Object instantiate(String className) + throws ReflectionException, MBeanException; /** - *

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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; - - + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + 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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void addNotificationListener(ObjectName name, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException; /** - * 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 throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - ObjectName listener) - throws InstanceNotFoundException, ListenerNotFoundException; + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException; /** - *

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, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; - + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException; /** - *

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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws 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 hrows UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException; /** - * 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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - 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 --git a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..8e1cf681e864caa3980b69f3faf62622a09c2069 --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java @@ -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 --git a/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..d86c787b8985f6bad3b2757e299e0fbea45de46a --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java @@ -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 nextInterceptor; + 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) { + nextInterceptor = 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. + **/ + static String getFirstNamespace(ObjectName name) { + if (name == null) return ""; + final String domain = name.getDomain(); + if (domain.equals("")) return ""; + + // skip leading separators + int first = 0; + while (domain.startsWith(NAMESPACE_SEPARATOR,first)) + first += NAMESPACE_SEPARATOR_LENGTH; + + // go to next separator + final int end = domain.indexOf(NAMESPACE_SEPARATOR,first); + if (end == -1) return ""; // no namespace + + // This is the first element in the namespace path. + 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 nextInterceptor; + } + 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(nextInterceptor); + } + 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 nextInterceptor; + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + @Override + public String[] getDomains() { + return nextInterceptor.getDomains(); + } + + @Override + public void addInterceptorFor(ObjectName name, JMXNamespace handler, + Queue postRegisterQueue) { + if (handler instanceof JMXDomain) + nextInterceptor.addInterceptorFor(name, + (JMXDomain)handler,postRegisterQueue); + else super.addInterceptorFor(name,handler,postRegisterQueue); + } + + @Override + public void removeInterceptorFor(ObjectName name, JMXNamespace handler, + Queue postDeregisterQueue) { + if (handler instanceof JMXDomain) + nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler, + postDeregisterQueue); + else super.removeInterceptorFor(name,handler,postDeregisterQueue); + } + + +} diff --git a/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..4a47d4ce3aafae60874c18aada3f193fda185fa6 --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java @@ -0,0 +1,416 @@ +/* + * 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.mbeanserver.Util; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +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.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.NotificationEmitter; +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.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; +import javax.management.remote.IdentityMBeanServerForwarder; + +public class SingleMBeanForwarder extends IdentityMBeanServerForwarder { + + private final ObjectName mbeanName; + private DynamicMBean mbean; + + private MBeanServer mbeanMBS = new MBeanServerSupport() { + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) { + return mbean; + } else { + throw new InstanceNotFoundException(name.toString()); + } + } + + @Override + protected Set getNames() { + return Collections.singleton(mbeanName); + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) { + if (mbean instanceof NotificationEmitter) + return (NotificationEmitter) mbean; + return null; + } + + }; + + public SingleMBeanForwarder(ObjectName mbeanName, DynamicMBean mbean) { + this.mbeanName = mbeanName; + setSingleMBean(mbean); + } + + protected void setSingleMBean(DynamicMBean mbean) { + this.mbean = mbean; + } + + @Override + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.addNotificationListener(name, listener, filter, handback); + else + super.addNotificationListener(name, listener, filter, handback); + } + + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.addNotificationListener(name, listener, filter, handback); + else + super.addNotificationListener(name, listener, filter, handback); + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, + String[] signature) + throws ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + if (mbeanName.equals(name)) + throw new InstanceAlreadyExistsException(mbeanName.toString()); + else + return super.createMBean(className, name, loaderName, params, signature); + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + if (mbeanName.equals(name)) + throw new InstanceAlreadyExistsException(mbeanName.toString()); + return super.createMBean(className, name, params, signature); + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + if (mbeanName.equals(name)) + throw new InstanceAlreadyExistsException(mbeanName.toString()); + return super.createMBean(className, name, loaderName); + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + if (mbeanName.equals(name)) + throw new InstanceAlreadyExistsException(mbeanName.toString()); + return super.createMBean(className, name); + } + + @Override + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException { + if (mbeanName.equals(name)) + return mbeanMBS.getAttribute(name, attribute); + else + return super.getAttribute(name, attribute); + } + + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + if (mbeanName.equals(name)) + return mbeanMBS.getAttributes(name, attributes); + else + return super.getAttributes(name, attributes); + } + + @Override + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + if (mbeanName.equals(loaderName)) + return mbeanMBS.getClassLoader(loaderName); + else + return super.getClassLoader(loaderName); + } + + @Override + public ClassLoader getClassLoaderFor(ObjectName name) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) + return mbeanMBS.getClassLoaderFor(name); + else + return super.getClassLoaderFor(name); + } + + @Override + public String[] getDomains() { + TreeSet domainSet = + new TreeSet(Arrays.asList(super.getDomains())); + domainSet.add(mbeanName.getDomain()); + return domainSet.toArray(new String[domainSet.size()]); + } + + @Override + public Integer getMBeanCount() { + Integer count = super.getMBeanCount(); + if (!super.isRegistered(mbeanName)) + count++; + return count; + } + + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, + IntrospectionException, + ReflectionException { + if (mbeanName.equals(name)) + return mbeanMBS.getMBeanInfo(name); + else + return super.getMBeanInfo(name); + } + + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) + return mbeanMBS.getObjectInstance(name); + else + return super.getObjectInstance(name); + } + + @Override + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, + MBeanException, + ReflectionException { + if (mbeanName.equals(name)) + return mbeanMBS.invoke(name, operationName, params, signature); + else + return super.invoke(name, operationName, params, signature); + } + + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + if (mbeanName.equals(name)) + return mbeanMBS.isInstanceOf(name, className); + else + return super.isInstanceOf(name, className); + } + + @Override + public boolean isRegistered(ObjectName name) { + if (mbeanName.equals(name)) + return true; + else + return super.isRegistered(name); + } + + /** + * This is a ugly hack. Although jmx.context//*:* matches jmx.context//:* + * queryNames(jmx.context//*:*,null) must not return jmx.context//:* + * @param pattern the pattern to match against. must not be null. + * @return true if mbeanName can be included, false if it must not. + */ + private boolean applies(ObjectName pattern) { + // we know pattern is not null. + 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); + } + + // should not come here, unless mbeanName contains a // in the + // middle of its domain, which would be weird. + // let query on mbeanMBS proceed and take care of that. + // + return true; + } + + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + Set names = super.queryMBeans(name, query); + if (name == null || applies(name) ) { + // Don't assume mbs.queryNames returns a writable set. + names = Util.cloneSet(names); + names.addAll(mbeanMBS.queryMBeans(name, query)); + } + return names; + } + + @Override + public Set queryNames(ObjectName name, QueryExp query) { + Set names = super.queryNames(name, query); + if (name == null || applies(name)) { + // Don't assume mbs.queryNames returns a writable set. + names = Util.cloneSet(names); + names.addAll(mbeanMBS.queryNames(name, query)); + } + return names; + } + + + @Override + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, + MBeanRegistrationException, + NotCompliantMBeanException { + if (mbeanName.equals(name)) + throw new InstanceAlreadyExistsException(mbeanName.toString()); + else + return super.registerMBean(object, name); + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, + ListenerNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.removeNotificationListener(name, listener, filter, handback); + else + super.removeNotificationListener(name, listener, filter, handback); + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.removeNotificationListener(name, listener); + else + super.removeNotificationListener(name, listener); + } + + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, + ListenerNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.removeNotificationListener(name, listener, filter, handback); + else + super.removeNotificationListener(name, listener, filter, handback); + } + + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + if (mbeanName.equals(name)) + mbeanMBS.removeNotificationListener(name, listener); + else + super.removeNotificationListener(name, listener); + } + + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, + AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException { + if (mbeanName.equals(name)) + mbeanMBS.setAttribute(name, attribute); + else + super.setAttribute(name, attribute); + } + + @Override + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + if (mbeanName.equals(name)) + return mbeanMBS.setAttributes(name, attributes); + else + return super.setAttributes(name, attributes); + } + + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, + MBeanRegistrationException { + if (mbeanName.equals(name)) + mbeanMBS.unregisterMBean(name); + else + super.unregisterMBean(name); + } +} diff --git a/src/share/classes/com/sun/jmx/interceptor/package.html b/src/share/classes/com/sun/jmx/interceptor/package.html index 854436a94040e20e694011ebe614c80b7971b85a..ad2163aa026268b045feffb9c254fab3fb006d12 100644 --- a/src/share/classes/com/sun/jmx/interceptor/package.html +++ b/src/share/classes/com/sun/jmx/interceptor/package.html @@ -29,5 +29,8 @@ have any questions. Provides specific classes to Sun JMX Reference Implementation. +

+ This API is a Sun internal API and is subject to changes without notice. +

diff --git a/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java b/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java index 2d97c97b94498f1c6b1eaf994de61e6064726989..b86b2e001283a55f9345d2e78350a4df96f8dfe4 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java @@ -825,7 +825,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { final TabularData table = (TabularData) openValue; final Collection rows = cast(table.values()); final Map valueMap = - sortedMap ? newSortedMap() : newMap(); + sortedMap ? newSortedMap() : newInsertionOrderMap(); for (CompositeData row : rows) { final Object key = keyMapping.fromOpenValue(row.get("key")); @@ -1172,10 +1172,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { final Class propertyNamesClass = ConstructorProperties.class; Class targetClass = getTargetClass(); - Constructor[] constrs = targetClass.getConstructors(); + Constructor[] constrs = targetClass.getConstructors(); // Applicable if and only if there are any annotated constructors - List annotatedConstrList = newList(); + List> annotatedConstrList = newList(); for (Constructor constr : constrs) { if (Modifier.isPublic(constr.getModifiers()) && constr.getAnnotation(propertyNamesClass) != null) @@ -1206,7 +1206,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { // Also remember the set of properties in that constructor // so we can test unambiguity. Set getterIndexSets = newSet(); - for (Constructor constr : annotatedConstrList) { + for (Constructor constr : annotatedConstrList) { String[] propertyNames = constr.getAnnotation(propertyNamesClass).value(); @@ -1363,10 +1363,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { } private static class Constr { - final Constructor constructor; + final Constructor constructor; final int[] paramIndexes; final BitSet presentParams; - Constr(Constructor constructor, int[] paramIndexes, + Constr(Constructor constructor, int[] paramIndexes, BitSet presentParams) { this.constructor = constructor; this.paramIndexes = paramIndexes; diff --git a/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java b/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java index 270f7ad77a6448d4783cbad963fe6b3fd7e5950e..d67b1660703e266fb6c752cfc66d8b6688fc40bd 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java index 1095897d99b4536f0121d2c4c687dd526fb48775..777cd1cce65461b641dc5ca217dd3bf5ca0a7b3f 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java @@ -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.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.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.MBeanPermission; 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.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 @@ public final class JmxMBeanServer /** true if interceptors are enabled **/ private final boolean interceptorsEnabled; - /** Revisit: transient ??? **/ - private final transient MBeanServer outerShell; + private final MBeanServer outerShell; - /** Revisit: transient ??? **/ - private transient MBeanServerInterceptor mbsInterceptor = null; + private volatile MBeanServer mbsInterceptor = null; - /** Revisit: transient ??? **/ /** The MBeanServerDelegate object representing the MBean Server */ - private final transient MBeanServerDelegate mBeanServerDelegateObject; + private final MBeanServerDelegate mBeanServerDelegateObject; + + private final String mbeanServerName; /** * Package: Creates an MBeanServer with the @@ -243,9 +240,10 @@ public final class JmxMBeanServer 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 @@ public final class JmxMBeanServer throws ReflectionException, MBeanException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, null, + "instantiate"); return instantiator.instantiate(className); } @@ -978,7 +977,8 @@ public final class JmxMBeanServer 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 @@ public final class JmxMBeanServer 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 @@ public final class JmxMBeanServer 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 @@ public final class JmxMBeanServer "Unexpected exception occurred", e); } throw new - IllegalStateException("Can't register delegate."); + IllegalStateException("Can't register delegate.",e); } @@ -1278,7 +1280,7 @@ public final class JmxMBeanServer * 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 @@ public final class JmxMBeanServer * @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 final class JmxMBeanServer **/ public ClassLoaderRepository getClassLoaderRepository() { /* Permission check */ - checkMBeanPermission(null, null, null, "getClassLoaderRepository"); + checkMBeanPermission(mbeanServerName, null, null, + null, "getClassLoaderRepository"); return secureClr; } @@ -1484,14 +1487,16 @@ public final class JmxMBeanServer // 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 --git a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java index 4831134f6af356d80807e14763d0c25be4bc4458..8ef296a1a4cd9f58ec51b39903d63c52284e3a80 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,7 +172,7 @@ public class MBeanInjector { * reference. * * So we accept a Field if it has a @Resource annotation and either - * (a) its type is ObjectName or a subclass and its @Resource type is + * (a) its type is exactly ObjectName and its @Resource type is * compatible with ObjectName (e.g. it is Object); or * (b) its type is compatible with ObjectName and its @Resource type * is exactly ObjectName. Fields that meet these criteria will not diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java b/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java index 725292bca36c05174c5b092c5e5373d84a734add..99aaa85466d9e30dcc178fe9377b15bef449afd7 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java @@ -623,7 +623,7 @@ abstract class MBeanIntrospector { } private static MBeanConstructorInfo[] findConstructors(Class c) { - Constructor[] cons = c.getConstructors(); + Constructor[] cons = c.getConstructors(); MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length]; for (int i = 0; i < cons.length; i++) { String descr = "Public constructor of the MBean"; diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java b/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java index d4f3123fbc5223bb844c6a9f2e1b5a35d5feec61..20a776534ce93169266269d534148405b91fc1c8 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java @@ -25,7 +25,6 @@ package com.sun.jmx.mbeanserver; -import static com.sun.jmx.mbeanserver.Util.*; import javax.management.Attribute; import javax.management.AttributeList; diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java index 41b3b98916078d59882f7a17961e740935354070..227c1eec9908f865c653d677594dde41b832ce86 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java @@ -224,7 +224,7 @@ public abstract class MXBeanLookup { 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 @@ public abstract class MXBeanLookup { "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 @@ public abstract class MXBeanLookup { 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 --git a/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java b/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java index 94227370ba2d9c72603a7b81b2f0989077dea78a..00fbb027352f139c4c1cfa6dbe77309860395d34 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java b/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java new file mode 100644 index 0000000000000000000000000000000000000000..2946f16fa124b45f7695c7f9477de38baf6156bb --- /dev/null +++ b/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java @@ -0,0 +1,71 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.jmx.mbeanserver; + +import java.lang.ref.WeakReference; +import java.util.concurrent.ThreadPoolExecutor; + +/** + *

A factory for ThreadPoolExecutor objects that allows the same object to + * be shared by all users of the factory that are in the same ThreadGroup.

+ */ +// We return a ThreadPoolExecutor rather than the more general ExecutorService +// because we need to be able to call allowCoreThreadTimeout so that threads in +// the pool will eventually be destroyed when the pool is no longer in use. +// Otherwise these threads would keep the ThreadGroup alive forever. +public class PerThreadGroupPool { + private final WeakIdentityHashMap> map = + WeakIdentityHashMap.make(); + + public static interface Create { + public T createThreadPool(ThreadGroup group); + } + + private PerThreadGroupPool() {} + + public static PerThreadGroupPool make() { + return new PerThreadGroupPool(); + } + + public synchronized T getThreadPoolExecutor(Create create) { + // Find out if there's already an existing executor for the calling + // thread and reuse it. Otherwise, create a new one and store it in + // the executors map. If there is a SecurityManager, the group of + // System.getSecurityManager() is used, else the group of the calling + // thread. + SecurityManager s = System.getSecurityManager(); + ThreadGroup group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + WeakReference wr = map.get(group); + T executor = (wr == null) ? null : wr.get(); + if (executor == null) { + executor = create.createThreadPool(group); + executor.allowCoreThreadTimeOut(true); + map.put(group, new WeakReference(executor)); + } + return executor; + } +} diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java index f41079912fb2a81a0e3a76d6ea9f86505c8c4e29..03f3e5277bd7ba8a9382fd7fdae44fdeb0c8b495 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java @@ -45,7 +45,6 @@ import javax.management.QueryExp; import javax.management.RuntimeOperationsException; /** - * The RepositorySupport implements the Repository interface. * This repository does not support persistency. * * @since 1.5 @@ -197,9 +196,9 @@ public class Repository { 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 @@ public class Repository { } } - /** 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 @@ public class Repository { 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) { @@ -477,10 +396,10 @@ public class Repository { // Set domain to default if domain is empty and not already set if (dom.length() == 0) - name = Util.newObjectName(domain + name.toString()); + name = ObjectName.valueOf(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 @@ public class Repository { } // 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 @@ public class Repository { // 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 --git a/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java b/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java index aca58c32f11260eda57861fe90057df2cf93501e..87aa9301d7aa469f4f4216fc6094f942366a3a00 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java b/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java index 6c338387d0e19dd57e83d9a292f81d01f2720c01..091ad7c66cb2b2fa06abed7ad56dabb1e5a712b2 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -28,17 +28,16 @@ package com.sun.jmx.mbeanserver; 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 @@ public interface SunJmxMBeanServer * are not enabled on this object. * @see #interceptorsEnabled **/ - public MBeanServerInterceptor getMBeanServerInterceptor(); + public MBeanServer getMBeanServerInterceptor(); /** * Set the MBeanServerInterceptor. @@ -77,7 +76,7 @@ public interface SunJmxMBeanServer * 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 --git a/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/src/share/classes/com/sun/jmx/mbeanserver/Util.java index af427da28870f89940f65ad646201007c1fd9076..6307adbf8d92442278539c4377a7fe6d3d386c67 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java @@ -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; @@ -38,12 +40,27 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; +import java.util.SortedSet; 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 char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?". + toCharArray(); + + static Map newMap() { return new HashMap(); } @@ -93,14 +110,6 @@ public class Util { return new ArrayList(c); } - public static ObjectName newObjectName(String s) { - try { - return new ObjectName(s); - } catch (MalformedObjectNameException e) { - throw new IllegalArgumentException(e); - } - } - /* This method can be used by code that is deliberately violating the * allowed checked casts. Rather than marking the whole method containing * the code with @SuppressWarnings, you can use a call to this method for @@ -142,4 +151,552 @@ public class Util { 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. + * + * @param pattern the pattern that the returned names must match. + * @param all the set of names to filter. + * @return a set of ObjectName from which non matching names + * have been removed. + */ + public static Set filterMatchingNames(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 (ObjectName n : all) if (pattern.apply(n)) res.add(n); + 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. + **/ + private final static class SingleClassLoaderRepository + implements ClassLoaderRepository { + private final ClassLoader singleLoader; + + SingleClassLoaderRepository(ClassLoader loader) { + this.singleLoader = loader; + } + + ClassLoader getSingleClassLoader() { + return singleLoader; + } + + private Class loadClass(String className, ClassLoader loader) + throws ClassNotFoundException { + return Class.forName(className, false, loader); + } + + public Class loadClass(String className) + throws ClassNotFoundException { + return loadClass(className, getSingleClassLoader()); + } + + public Class loadClassWithout(ClassLoader exclude, + String className) throws ClassNotFoundException { + final ClassLoader loader = getSingleClassLoader(); + if (exclude != null && exclude.equals(loader)) + throw new ClassNotFoundException(className); + return loadClass(className, loader); + } + + public Class loadClassBefore(ClassLoader stop, String className) + throws ClassNotFoundException { + return loadClassWithout(stop, className); + } + } + + /** + * Returns a ClassLoaderRepository that contains a single class loader. + * @param loader the class loader contained in the returned repository. + * @return a ClassLoaderRepository that contains the single loader. + */ + public static ClassLoaderRepository getSingleClassLoaderRepository( + final ClassLoader loader) { + 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 {@link #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) { + 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 usually 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); + do { + toprint.append("\nCaused By: ").append(String.valueOf(t)); + } while ((t=t.getCause())!=null); + JmxProperties.MISC_LOGGER.fine(toprint.toString()); + } + } + + public static Set cloneSet(Set set) { + if (set instanceof SortedSet) { + @SuppressWarnings("unchecked") + SortedSet sset = (SortedSet) set; + set = new TreeSet(sset.comparator()); + set.addAll(sset); + } else + set = new HashSet(set); + return set; + } + + public static Set equivalentEmptySet(Set set) { + if (set instanceof SortedSet) { + @SuppressWarnings("unchecked") + SortedSet sset = (SortedSet) set; + set = new TreeSet(sset.comparator()); + } 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 --git a/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..7b88087a81c6ddc8bf19a64e8fab63a671a62f9f --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java @@ -0,0 +1,468 @@ +/* + * 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==null?ObjectName.WILDCARD:pattern; + } + + public boolean isNotificationEnabled(Notification notification) { + if (!(notification instanceof MBeanServerNotification)) + return false; + final MBeanServerNotification mbsn = + (MBeanServerNotification) notification; + if (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; + ALL = ObjectName.valueOf(domainName+":*"); + } + + @Override + public String toString() { + return this.getClass().getName()+"(parent="+serverName+ + ", domain="+this.domainName+")"; + } + + final 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); + } + }; + } + } + + getHandlerInterceptorMBean(). + addMBeanServerNotificationListener(mbsListener, filter); + } + + final void disconnectDelegate() + throws InstanceNotFoundException, ListenerNotFoundException { + final NotificationListener l; + synchronized (this) { + l = mbsListener; + if (l == null) return; + mbsListener = null; + } + getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l); + } + + public final 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 final 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); + } + + // No name conversion for JMXDomains... + // 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; + } + + // No name conversion for JMXDomains... + @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); + return Collections.emptySet(); + } + } + + // Compute a new pattern which is a sub pattern of 'name' but only selects + // the MBeans in domain 'domainName' + // When we reach here, it has been verified that 'name' matches our domain + // name (done by DomainDispatchInterceptor) + private ObjectName getPatternFor(final ObjectName name) { + try { + 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); + return Collections.emptySet(); + } + } + + @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 getHandlerInterceptorMBean().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; + if("queryMBeans".equals(act) || "queryNames".equals(act)) { + // 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; + + final String act = (action==null)?"-":action; + if ("getDomains".equals(act)) { // 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 getHandlerInterceptorMBean().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; + } + + // + // The {@code source} connection is a connection to the MBeanServer + // that contains the actual MBeans. + // In the case of cascading, that would be a connection to the sub + // agent. Practically, this is JMXNamespace.getSourceServer(); + // + @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(); + } + + // The namespace or domain handler - this either a JMXNamespace or a + // a JMXDomain + T getHandlerInterceptorMBean() { + 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 MBeanServerConnection: catch & handles IOException + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + final String[] authorized = + checkAttributes(name,attributes,"getAttribute"); + final AttributeList attrList = + super.getAttributes(name,authorized); + return attrList; + } 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 MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name,listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name,listener); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public String getDefaultDomain() { + try { + return super.getDefaultDomain(); + } catch (IOException ex) { + throw handleIOException(ex,"getDefaultDomain"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public String[] getDomains() { + try { + check(null,null,"getDomains"); + final String[] domains = super.getDomains(); + return checkDomains(domains,"getDomains"); + } catch (IOException ex) { + throw handleIOException(ex,"getDomains"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Integer getMBeanCount() { + try { + return super.getMBeanCount(); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanCount"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + check(name, + (attribute==null?null:attribute.getName()), + "setAttribute"); + super.setAttribute(name,attribute); + } catch (IOException ex) { + throw handleIOException(ex,"setAttribute",name, attribute); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Set queryNames(ObjectName name, QueryExp query) { + if (name == null) name=ObjectName.WILDCARD; + try { + checkPattern(name,null,"queryNames"); + return super.queryNames(name,query); + } catch (IOException ex) { + throw handleIOException(ex,"queryNames",name, query); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + if (name == null) name=ObjectName.WILDCARD; + try { + checkPattern(name,null,"queryMBeans"); + return super.queryMBeans(name,query); + } catch (IOException ex) { + throw handleIOException(ex,"queryMBeans",name, query); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + check(name, null, "isInstanceOf"); + return super.isInstanceOf(name, className); + } catch (IOException ex) { + throw handleIOException(ex,"isInstanceOf",name, className); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, loaderName); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, loaderName); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + try { + check(name, attribute, "getAttribute"); + return super.getAttribute(name, attribute); + } catch (IOException ex) { + throw handleIOException(ex,"getAttribute",name, attribute); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException { + try { + check(name,null,"addNotificationListener"); + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + try { + check(name,null,"addNotificationListener"); + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public boolean isRegistered(ObjectName name) { + try { + return super.isRegistered(name); + } catch (IOException ex) { + throw handleIOException(ex,"isRegistered",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + check(name, null, "unregisterMBean"); + super.unregisterMBean(name); + } catch (IOException ex) { + throw handleIOException(ex,"unregisterMBean",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + try { + check(name, null, "getMBeanInfo"); + return super.getMBeanInfo(name); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanInfo",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + check(name, null, "getObjectInstance"); + return super.getObjectInstance(name); + } catch (IOException ex) { + throw handleIOException(ex,"getObjectInstance",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, params, signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, + params, signature); + } + } + + // From MBeanServerConnection: 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 { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, loaderName, params, + signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name,loaderName, + params, signature); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public AttributeList setAttributes(ObjectName name,AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + final AttributeList authorized = + checkAttributes(name, attributes, "setAttribute"); + return super.setAttributes(name, authorized); + } catch (IOException ex) { + throw handleIOException(ex,"setAttributes",name, attributes); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException { + try { + check(name, operationName, "invoke"); + 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)); + } + + /** + * A result might be excluded for security reasons. + */ + @Override + boolean excludesFromResult(ObjectName targetName, String queryMethod) { + return !checkQuery(targetName, queryMethod); + } + + + //---------------------------------------------------------------------- + // Hooks for checking permissions + //---------------------------------------------------------------------- + + /** + * This method is a hook to implement permission checking in subclasses. + * 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. + * @throws SecurityException if the caller doesn't have the permission + * to perform the given action on the MBean pointed to + * by routingName. + */ + abstract void check(ObjectName routingName, + String member, String action); + + // called in createMBean and registerMBean + abstract void checkCreate(ObjectName routingName, String className, + String action); + + /** + * 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}. + * + * 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. + */ + abstract boolean checkQuery(ObjectName routingName, String action); + + /** + * This method is a hook to implement permission checking in subclasses. + * + * @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}. + * @throws SecurityException if the caller doesn't have the permission + * to perform {@code action} on the MBean pointed to by routingName. + */ + abstract String[] checkAttributes(ObjectName routingName, + String[] attributes, String action); + + /** + * This method is a hook to implement permission checking in subclasses. + * + * @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}. + * @throws SecurityException if the caller doesn't have the permission + * to perform {@code action} on the MBean pointed to by routingName. + */ + abstract AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action); + + /** + * 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; + } + + // A priori check for queryNames/queryMBeans/ + 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. + // We only check that we have the permission requested for 'action'. + check(null,null,action); + } + + + +} diff --git a/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..49f875144f2751604094023018b1c2678ba3dd06 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java @@ -0,0 +1,354 @@ +/* + * 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.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.event.EventClientDelegateMBean; +import javax.management.namespace.JMXNamespace; +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(); + } + + /** There are no instances of this class */ + private JMXNamespaceUtils() { + } + + // 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 --git a/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..6862066d2bcd523eaae6e47ff3e462564eb5f828 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java @@ -0,0 +1,225 @@ +/* + * 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.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +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 { + + + // The target name space in which the NamepsaceHandler is mounted. + private final String targetNs; + + private final String serverName; + + private final ObjectNameRouter proc; + + /** + * 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+")"; + } + + /** + * 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() { + final MBeanServer c = super.source(); + if (c != null) return c; + // should not come here + 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(); + } + + @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 --git a/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java new file mode 100644 index 0000000000000000000000000000000000000000..3c7065c478e323ad4f6262e8960424450e17851d --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..443c80f2ae56ad118e4d065d368ff72ac955746e --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java @@ -0,0 +1,123 @@ +/* + * 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 + */ +// See class hierarchy and detailled explanations in RoutingProxy in this +// package. +// +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+")"; + } + + static final RoutingProxyFactory + + FACTORY = new RoutingProxyFactory + () { + + public RoutingConnectionProxy newInstance(MBeanServerConnection source, + String sourcePath, String targetPath, + boolean forwardsContext) { + return new RoutingConnectionProxy(source,sourcePath, + targetPath,forwardsContext); + } + + public RoutingConnectionProxy newInstance( + MBeanServerConnection source, String sourcePath) { + return new RoutingConnectionProxy(source,sourcePath); + } + }; + + public static MBeanServerConnection cd(MBeanServerConnection source, + String sourcePath) { + return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY, + source, sourcePath); + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..7022e7e297371a93b67530f23c791d870b3e3a47 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java @@ -0,0 +1,567 @@ +/* + * 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. The {@code source} connection + * is a connection to the MBeanServer that contains the actual MBean. + * In the case of cascading, that would be a connection to the sub + * agent. + **/ + protected abstract T source() throws IOException; + + /** + * Converts a target ObjectName to a source ObjectName. + * The target ObjectName is the name of the MBean in the mount point + * target. In the case of cascading, that would be the name of the + * MBean in the master agent. So if a subagent S containing an MBean + * named "X" is mounted in the target namespace "foo//" of a master agent M, + * the source is S, the target is "foo//" in M, the source name is "X", and + * the target name is "foo//X". + * In the case of cascading - such as in NamespaceInterceptor, this method + * will convert "foo//X" (the targetName) into "X", the source name. + **/ + protected abstract ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException; + + /** + * Converts a source ObjectName to a target ObjectName. + * (see description of toSource above for explanations) + * In the case of cascading - such as in NamespaceInterceptor, this method + * will convert "X" (the sourceName) into "foo//X", the target name. + **/ + 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); + } + + // from MBeanServerConnection + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().getAttributes(sourceName, attributes); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + return source(). + setAttributes(sourceName,attributes); + } 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 (excludesFromResult(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; + } + + + // 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 (excludesFromResult(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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + return source().getDomains(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public String getDefaultDomain() throws IOException { + try { + return source().getDefaultDomain(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + /** + * Returns true if the given targetName must be excluded from the + * query result. + * In this base class, always return {@code false}. + * By default all object names returned by the sources are + * transmitted to the caller - there is no filtering. + * + * @param name A target object name expressed in the caller's + * context. In the case of cascading, where the source + * is a sub agent mounted on e.g. namespace "foo", + * that would be a name prefixed by "foo//"... + * @param queryMethod either "queryNames" or "queryMBeans". + * @return true if the name must be excluded. + */ + boolean excludesFromResult(ObjectName targetName, String queryMethod) { + return false; + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..aa35c5bdaed56754d2591ed463b6632dc3a6f533 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java @@ -0,0 +1,413 @@ +/* + * 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.MBeanException; +import javax.management.MBeanRegistrationException; + +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; + + +/** + * A 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 narrow down into an + * MBeanServerConnection.

+ *

{@link RoutingServerProxy}: to narrow down into an MBeanServer.

+ * + *

This class can also be used to "broaden" from a namespace. The same + * class is used for both purposes because in both cases all that happens + * is that ObjectNames are rewritten in one way on the way in (e.g. the + * parameter of getMBeanInfo) and another way on the way out (e.g. the + * return value of queryNames).

+ * + *

Specifically, if you narrow into "a//" then you want to add the + * "a//" prefix to ObjectNames on the way in and subtract it on the way + * out. But ClientContext uses this class to subtract the + * "jmx.context//foo=bar//" prefix on the way in and add it back on the + * way out.

+ * + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// +// RoutingProxies are client side objects which are used to narrow down +// into a namespace. They are used to perform ObjectName translation, +// adding the namespace to the routing ObjectName before sending it over +// to the source connection, and removing that prefix from results of +// queries, createMBean, registerMBean, and getObjectInstance. +// This translation is the opposite to that which is performed by +// NamespaceInterceptors. +// +// There is however a special case where routing proxies are used on the +// 'server' side to remove a namespace - rather than to add it: +// This the case of ClientContext. +// When an ObjectName like "jmx.context//c1=v1,c2=v2//D:k=v" reaches the +// jmx.context namespace, a routing proxy is used to remove the prefix +// c1=v1,c2=v2// from the routing objectname. +// +// For a RoutingProxy used in a narrowDownToNamespace operation, we have: +// targetNs="" // targetNS is the namespace 'to remove' +// sourceNS= // namespace 'to add' +// +// For a RoutingProxy used in a ClientContext operation, we have: +// targetNs= // context must be removed from object name +// sourceNs="" // nothing to add... +// +// RoutingProxies can also be used on the client side to implement +// "withClientContext" operations. In that case, the boolean parameter +// 'forwards context' is set to true, targetNs is "", and sourceNS may +// also be "". When forwardsContext is true, the RoutingProxy dynamically +// creates an ObjectNameRouter for each operation - in order to dynamically add +// the context attached to the thread to the routing ObjectName. This is +// performed in the getObjectNameRouter() method. +// +// Finally, in order to avoid too many layers of wrapping, +// RoutingConnectionProxy and RoutingServerProxy can be created through a +// factory method that can concatenate namespace pathes in order to +// return a single RoutingProxy - rather than wrapping a RoutingProxy inside +// another RoutingProxy. See RoutingConnectionProxy.cd and +// RoutingServerProxy.cd +// +// The class hierarchy is as follows: +// +// RoutingMBeanServerConnection +// [abstract class for all routing interceptors, +// such as RoutingProxies and HandlerInterceptors] +// / \ +// / \ +// RoutingProxy HandlerInterceptor +// [base class for [base class for server side +// client-side objects used objects, created by +// in narrowDownTo] DispatchInterceptors] +// / \ | \ +// RoutingConnectionProxy \ | NamespaceInterceptor +// [wraps MBeanServerConnection \ | [used to remove +// objects] \ | namespace prefix and +// RoutingServerProxy | wrap JMXNamespace] +// [wraps MBeanServer | +// Objects] | +// DomainInterceptor +// [used to wrap JMXDomain] +// +// RoutingProxies also differ from HandlerInterceptors in that they transform +// calls to MBeanServerConnection operations that do not have any parameters +// into a call to the underlying JMXNamespace MBean. +// So for instance a call to: +// JMXNamespaces.narrowDownToNamespace(conn,"foo").getDomains() +// is transformed into +// conn.getAttribute("foo//type=JMXNamespace","Domains"); +// +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.getCause(), + ex.getCause()); + } catch (Exception ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex,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)); + } + + // Creates an instance of a subclass 'R' of RoutingProxy + // RoutingServerProxy and RoutingConnectionProxy have their own factory + // instance. + static interface RoutingProxyFactory> { + R newInstance(T source, + String sourcePath, String targetPath, + boolean forwardsContext); + R newInstance(T source, + String sourcePath); + } + + // Performs a narrowDownToNamespace operation. + // This method will attempt to merge two RoutingProxies in a single + // one if they are of the same class. + // + // This method is never called directly - it should be called only by + // subclasses of RoutingProxy. + // + // As for now it is called by: + // RoutingServerProxy.cd and RoutingConnectionProxy.cd. + // + static > + R cd(Class routingProxyClass, + RoutingProxyFactory factory, + T source, String sourcePath) { + if (source == null) throw new IllegalArgumentException("null"); + if (source.getClass().equals(routingProxyClass)) { + // cast is OK here, but findbugs complains unless we use class.cast + final R other = routingProxyClass.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 + // RoutingServerProxy. + // + if (target == null || target.equals("")) { + final String path = + JMXNamespaces.concat(other.getSourceNamespace(), + sourcePath); + return factory.newInstance(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 factory.newInstance(source,sourcePath); + } +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..f58e39816d34d61acf4a83026b81bc3fda1f2296 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java @@ -0,0 +1,590 @@ +/* + * 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 + */ +// See class hierarchy and detailled explanations in RoutingProxy in this +// package. +// +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"); + } + } + + static final RoutingProxyFactory + FACTORY = new RoutingProxyFactory() { + + public RoutingServerProxy newInstance(MBeanServer source, + String sourcePath, String targetPath, + boolean forwardsContext) { + return new RoutingServerProxy(source,sourcePath, + targetPath,forwardsContext); + } + + public RoutingServerProxy newInstance( + MBeanServer source, String sourcePath) { + return new RoutingServerProxy(source,sourcePath); + } + }; + + public static MBeanServer cd(MBeanServer source, String sourcePath) { + return RoutingProxy.cd(RoutingServerProxy.class, FACTORY, + source, sourcePath); + } +} diff --git a/src/share/classes/com/sun/jmx/namespace/package.html b/src/share/classes/com/sun/jmx/namespace/package.html new file mode 100644 index 0000000000000000000000000000000000000000..6677288ca8848f26169bea168ca08fa2a3564568 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/package.html @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..f458378cbccb188cc1c6a4febca9859c3a10c469 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java @@ -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 --git a/src/solaris/native/sun/awt/awt_motif.c b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java similarity index 50% rename from src/solaris/native/sun/awt/awt_motif.c rename to src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java index 818e3e17fcc936e7f9a594d5d04e1476c4601d17..32cca2d2dc429c001118bba8f9ede81db06e5d5f 100644 --- a/src/solaris/native/sun/awt/awt_motif.c +++ b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -23,36 +23,52 @@ * have any questions. */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif +package com.sun.jmx.namespace.serial; -#include "awt_motif.h" -#include +import javax.management.ObjectInstance; +import javax.management.ObjectName; -/* 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 +/** + * 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 */ -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; - } +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 --git a/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java b/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java new file mode 100644 index 0000000000000000000000000000000000000000..6416bfb9644de69a7e30c2dd4b06116b3b398ddd --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..2c81be934c5a719a28df121fcec06e2dcf8029d0 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..1df2e26a9c87201994db787ae1924fb5ff94f78e --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e879822e379247c98122411432177df91d8fe1 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/package.html b/src/share/classes/com/sun/jmx/namespace/serial/package.html new file mode 100644 index 0000000000000000000000000000000000000000..fe2e8c64b9407d3eba97d0aa18c11c7cc9c9b174 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/package.html @@ -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 --git a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java index a6635aad8bd4f298bec3a4d2c2227caa8640a8c8..9bc5cc7e8feb96f59f4210ca84e93d05b62dc004 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,13 +32,15 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; public abstract class ClientCommunicatorAdmin { + private static volatile long threadNo = 1; + public ClientCommunicatorAdmin(long period) { this.period = period; if (period > 0) { checker = new Checker(); - Thread t = new Thread(checker); + Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo); t.setDaemon(true); t.start(); } else diff --git a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java index a37b75395f81a568b9caeabb2a91328de871bb7d..ab6bd60caf8e5b1cd499cfb7cc410ee310b46cd3 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java @@ -290,28 +290,6 @@ public abstract class ClientNotifForwarder { infoList.clear(); - if (currentFetchThread == Thread.currentThread()) { - /* we do not need to stop the fetching thread, because this thread is - used to do restarting and it will not be used to do fetching during - the re-registering the listeners.*/ - return tmp; - } - - while (state == STARTING) { - try { - wait(); - } catch (InterruptedException ire) { - IOException ioe = new IOException(ire.toString()); - EnvHelp.initCause(ioe, ire); - - throw ioe; - } - } - - if (state == STARTED) { - setState(STOPPING); - } - return tmp; } @@ -353,8 +331,9 @@ public abstract class ClientNotifForwarder { beingReconnected = false; notifyAll(); - if (currentFetchThread == Thread.currentThread()) { - // no need to init, simply get the id + if (currentFetchThread == Thread.currentThread() || + state == STARTING || state == STARTED) { // doing or waiting reconnection + // only update mbeanRemovedNotifID try { mbeanRemovedNotifID = addListenerForMBeanRemovedNotif(); } catch (Exception e) { @@ -366,12 +345,23 @@ public abstract class ClientNotifForwarder { logger.trace("init", msg, e); } } - } else if (listenerInfos.length > 0) { // old listeners re-registered - init(true); - } else if (infoList.size() > 0) { - // but new listeners registered during reconnection - init(false); - } + } else { + while (state == STOPPING) { + try { + wait(); + } catch (InterruptedException ire) { + IOException ioe = new IOException(ire.toString()); + EnvHelp.initCause(ioe, ire); + throw ioe; + } + } + + if (listenerInfos.length > 0) { // old listeners are re-added + init(true); // not update clientSequenceNumber + } else if (infoList.size() > 0) { // only new listeners added during reconnection + init(false); // need update clientSequenceNumber + } + } } public synchronized void terminate() { @@ -486,6 +476,15 @@ public abstract class ClientNotifForwarder { if (nr == null || shouldStop()) { // tell that the thread is REALLY stopped setState(STOPPED); + + try { + removeListenerForMBeanRemovedNotif(mbeanRemovedNotifID); + } catch (Exception e) { + if (logger.traceOn()) { + logger.trace("NotifFetcher-run", + "removeListenerForMBeanRemovedNotif", e); + } + } } else { executor.execute(this); } @@ -576,6 +575,7 @@ public abstract class ClientNotifForwarder { int notFoundCount = 0; NotificationResult result = null; + long firstEarliest = -1; while (result == null && !shouldStop()) { NotificationResult nr; @@ -598,6 +598,8 @@ public abstract class ClientNotifForwarder { return null; startSequenceNumber = nr.getNextSequenceNumber(); + if (firstEarliest < 0) + firstEarliest = nr.getEarliestSequenceNumber(); try { // 1 notif to skip possible missing class @@ -628,6 +630,17 @@ public abstract class ClientNotifForwarder { (notFoundCount == 1 ? "" : "s") + " because classes were missing locally"; lostNotifs(msg, notFoundCount); + // Even if result.getEarliestSequenceNumber() is now greater than + // it was initially, meaning some notifs have been dropped + // from the buffer, we don't want the caller to see that + // because it is then likely to renotify about the lost notifs. + // So we put back the first value of earliestSequenceNumber + // that we saw. + if (result != null) { + result = new NotificationResult( + firstEarliest, result.getNextSequenceNumber(), + result.getTargetedNotifications()); + } } return result; diff --git a/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java b/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java index cdcdd6159b7385a65b294ebce6f650642f5d779b..8d57b8f92a6da87361a404fa2c024804d81ed568 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,8 @@ import org.omg.CORBA.Any; import org.omg.CORBA.Context; import org.omg.CORBA.NO_IMPLEMENT; import org.omg.CORBA.ORB; -import org.omg.CORBA.Principal; import org.omg.CORBA.TypeCode; import org.omg.CORBA.portable.BoxedValueHelper; -import org.omg.CORBA_2_3.portable.InputStream; @SuppressWarnings("deprecation") public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream { @@ -160,54 +158,71 @@ public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream { return in.read_any(); } - public Principal read_Principal() { + /** + * @deprecated + */ + @Override + @Deprecated + public org.omg.CORBA.Principal read_Principal() { return in.read_Principal(); } + @Override public int read() throws IOException { return in.read(); } + @Override public BigDecimal read_fixed() { return in.read_fixed(); } + @Override public Context read_Context() { return in.read_Context(); } + @Override public org.omg.CORBA.Object read_Object(java.lang.Class clz) { return in.read_Object(clz); } + @Override public ORB orb() { return in.orb(); } + @Override public Serializable read_value() { return narrow().read_value(); } + @Override public Serializable read_value(Class clz) { return narrow().read_value(clz); } + @Override public Serializable read_value(BoxedValueHelper factory) { return narrow().read_value(factory); } + @Override public Serializable read_value(String rep_id) { return narrow().read_value(rep_id); } + @Override public Serializable read_value(Serializable value) { return narrow().read_value(value); } + @Override public Object read_abstract_interface() { return narrow().read_abstract_interface(); } + @Override public Object read_abstract_interface(Class clz) { return narrow().read_abstract_interface(clz); } diff --git a/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java b/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java index 3c16e9e7f4de5384536ea0094397bb88fdaa211e..e1593266ac4c4bc220e4953b7ace9e18c6af43a1 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,6 @@ import java.io.ObjectOutput; import java.lang.reflect.Method; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.server.Operation; -import java.rmi.server.RemoteCall; import java.rmi.server.RemoteObject; import java.rmi.server.RemoteRef; @@ -54,7 +52,11 @@ public class ProxyRef implements RemoteRef { ref.writeExternal(out); } - public void invoke(RemoteCall call) throws Exception { + /** + * @deprecated + */ + @Deprecated + public void invoke(java.rmi.server.RemoteCall call) throws Exception { ref.invoke(call); } @@ -63,7 +65,11 @@ public class ProxyRef implements RemoteRef { return ref.invoke(obj, method, params, opnum); } - public void done(RemoteCall call) throws RemoteException { + /** + * @deprecated + */ + @Deprecated + public void done(java.rmi.server.RemoteCall call) throws RemoteException { ref.done(call); } @@ -71,7 +77,12 @@ public class ProxyRef implements RemoteRef { return ref.getRefClass(out); } - public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, + /** + * @deprecated + */ + @Deprecated + public java.rmi.server.RemoteCall newCall(RemoteObject obj, + java.rmi.server.Operation[] op, int opnum, long hash) throws RemoteException { return ref.newCall(obj, op, opnum, hash); } diff --git a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java index ae84f4b9d2e3385029c769b82ae8482402d668cf..c3542cc1d8a676448928f9661525389940f860ad 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java @@ -25,16 +25,16 @@ package com.sun.jmx.remote.internal; +import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.remote.security.NotificationAccessController; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.io.IOException; import java.security.AccessControlContext; import java.security.AccessController; +import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -57,6 +57,7 @@ import javax.security.auth.Subject; public class ServerNotifForwarder { + public ServerNotifForwarder(MBeanServer mbeanServer, Map env, NotificationBuffer notifBuffer, @@ -67,9 +68,9 @@ public class ServerNotifForwarder { connectionTimeout = EnvHelp.getServerConnectionTimeout(env); checkNotificationEmission = EnvHelp.computeBooleanFromString( env, - "jmx.remote.x.check.notification.emission"); - notificationAccessController = (NotificationAccessController) - env.get("com.sun.jmx.remote.notification.access.controller"); + "jmx.remote.x.check.notification.emission",false); + notificationAccessController = + EnvHelp.getNotificationAccessController(env); } public Integer addNotificationListener(final ObjectName name, @@ -85,12 +86,11 @@ public class ServerNotifForwarder { // Explicitly check MBeanPermission for addNotificationListener // - checkMBeanPermission(name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); if (notificationAccessController != null) { notificationAccessController.addNotificationListener( - connectionId, - name, - Subject.getSubject(AccessController.getContext())); + connectionId, name, getSubject()); } try { boolean instanceOf = @@ -157,12 +157,11 @@ public class ServerNotifForwarder { // Explicitly check MBeanPermission for removeNotificationListener // - checkMBeanPermission(name, "removeNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "removeNotificationListener"); if (notificationAccessController != null) { notificationAccessController.removeNotificationListener( - connectionId, - name, - Subject.getSubject(AccessController.getContext())); + connectionId, name, getSubject()); } Exception re = null; @@ -312,6 +311,10 @@ public class ServerNotifForwarder { // PRIVATE METHODS //---------------- + private Subject getSubject() { + return Subject.getSubject(AccessController.getContext()); + } + private void checkState() throws IOException { synchronized(terminationLock) { if (terminated) { @@ -330,9 +333,9 @@ public class ServerNotifForwarder { * Explicitly check the MBeanPermission for * the current access control context. */ - private void checkMBeanPermission(final ObjectName name, - final String actions) - throws InstanceNotFoundException, SecurityException { + public static void checkMBeanPermission(String serverName, + final MBeanServer mbs, final ObjectName name, final String actions) + throws InstanceNotFoundException, SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { AccessControlContext acc = AccessController.getContext(); @@ -342,14 +345,16 @@ public class ServerNotifForwarder { new PrivilegedExceptionAction() { public ObjectInstance run() throws InstanceNotFoundException { - return mbeanServer.getObjectInstance(name); + return mbs.getObjectInstance(name); } }); } catch (PrivilegedActionException e) { throw (InstanceNotFoundException) extractException(e); } String classname = oi.getClassName(); - MBeanPermission perm = new MBeanPermission(classname, + MBeanPermission perm = new MBeanPermission( + serverName, + classname, null, name, actions); @@ -364,14 +369,12 @@ public class ServerNotifForwarder { TargetedNotification tn) { try { if (checkNotificationEmission) { - checkMBeanPermission(name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); } if (notificationAccessController != null) { notificationAccessController.fetchNotification( - connectionId, - name, - tn.getNotification(), - Subject.getSubject(AccessController.getContext())); + connectionId, name, tn.getNotification(), getSubject()); } return true; } catch (SecurityException e) { @@ -429,11 +432,27 @@ public class ServerNotifForwarder { } } + 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 --git a/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java b/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java index 47f3e07ab075631fc9fa6da62d7ee58774cfacca..a901a19c8f82cf5511e0e293ab771d14fe572ab4 100644 --- a/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java +++ b/src/share/classes/com/sun/jmx/remote/security/FileLoginModule.java @@ -25,6 +25,7 @@ package com.sun.jmx.remote.security; +import com.sun.jmx.mbeanserver.GetPropertyAction; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -47,8 +48,6 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import sun.management.jmxremote.ConnectorBootstrap; -import sun.security.action.GetPropertyAction; - /** * This {@link LoginModule} performs file-based authentication. * @@ -479,7 +478,7 @@ public class FileLoginModule implements LoginModule { if (userSuppliedPasswordFile || hasJavaHomePermission) { throw e; } else { - FilePermission fp = + final FilePermission fp = new FilePermission(passwordFileDisplayName, "read"); AccessControlException ace = new AccessControlException( "access denied " + fp.toString()); @@ -488,10 +487,13 @@ public class FileLoginModule implements LoginModule { } } try { - BufferedInputStream bis = new BufferedInputStream(fis); - userCredentials = new Properties(); - userCredentials.load(bis); - bis.close(); + final BufferedInputStream bis = new BufferedInputStream(fis); + try { + userCredentials = new Properties(); + userCredentials.load(bis); + } finally { + bis.close(); + } } finally { fis.close(); } diff --git a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java index 219559ea5316d089295e2227a3f20e6fc6607acb..67b9ea59561d6dfb75c5af4e771acf72f43ff091 100644 --- a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java +++ b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,6 @@ import java.util.TreeMap; import java.util.TreeSet; import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import javax.management.ObjectName; import javax.management.MBeanServer; @@ -50,6 +47,9 @@ import javax.management.InstanceNotFoundException; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorServerFactory; import com.sun.jmx.mbeanserver.GetPropertyAction; +import com.sun.jmx.remote.security.NotificationAccessController; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorServer; public class EnvHelp { @@ -346,7 +346,24 @@ public class EnvHelp { */ public static long getFetchTimeout(Map env) { return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0, - Long.MAX_VALUE); + Long.MAX_VALUE); + } + + /** + *

Name of the attribute that specifies an object that will check + * accesses to add/removeNotificationListener and also attempts to + * receive notifications. The value associated with this attribute + * should be a NotificationAccessController object. + * The default value is null.

+ * This field is not public because of its com.sun dependency. + */ + public static final String NOTIF_ACCESS_CONTROLLER = + "com.sun.jmx.remote.notification.access.controller"; + + public static NotificationAccessController getNotificationAccessController( + Map env) { + return (env == null) ? null : + (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER); } /** @@ -470,24 +487,24 @@ public class EnvHelp { } /** - The value of this attribute, if present, is a string specifying - what other attributes should not appear in - JMXConnectorServer.getAttributes(). It is a space-separated - list of attribute patterns, where each pattern is either an - attribute name, or an attribute prefix followed by a "*" - character. The "*" has no special significance anywhere except - at the end of a pattern. By default, this list is added to the - list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which - uses the same format). If the value of this attribute begins - with an "=", then the remainder of the string defines the - complete list of attribute patterns. + * The value of this attribute, if present, is a string specifying + * what other attributes should not appear in + * JMXConnectorServer.getAttributes(). It is a space-separated + * list of attribute patterns, where each pattern is either an + * attribute name, or an attribute prefix followed by a "*" + * character. The "*" has no special significance anywhere except + * at the end of a pattern. By default, this list is added to the + * list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which + * uses the same format). If the value of this attribute begins + * with an "=", then the remainder of the string defines the + * complete list of attribute patterns. */ public static final String HIDDEN_ATTRIBUTES = "jmx.remote.x.hidden.attributes"; /** - Default list of attributes not to show. - @see #HIDDEN_ATTRIBUTES + * Default list of attributes not to show. + * @see #HIDDEN_ATTRIBUTES */ /* This list is copied directly from the spec, plus java.naming.security.*. Most of the attributes here would have @@ -651,6 +668,8 @@ public class EnvHelp { * @param env the environment map. * @param prop the name of the property in the environment map whose * returned string value must be converted into a boolean value. + * @param systemProperty if true, consult a system property of the + * same name if there is no entry in the environment map. * * @return *
    @@ -671,16 +690,73 @@ public class EnvHelp { * @throws ClassCastException if {@code env.get(prop)} cannot be cast * to {@code String}. */ - public static boolean computeBooleanFromString(Map env, String prop) - throws IllegalArgumentException, ClassCastException { + public static boolean computeBooleanFromString( + Map env, String prop, boolean systemProperty) { + + if (env == null) + throw new IllegalArgumentException("env map cannot be null"); + + // returns a default value of 'false' if no property is found... + return computeBooleanFromString(env,prop,systemProperty,false); + } + + /** + * Computes a boolean value from a string value retrieved from a + * property in the given map. + * + * @param env the environment map. + * @param prop the name of the property in the environment map whose + * returned string value must be converted into a boolean value. + * @param systemProperty if true, consult a system property of the + * same name if there is no entry in the environment map. + * @param defaultValue a default value to return in case no property + * was defined. + * + * @return + *
      + *
    • {@code defaultValue} if {@code env.get(prop)} is {@code null} + * and {@code systemProperty} is {@code false}
    • + *
    • {@code defaultValue} if {@code env.get(prop)} is {@code null} + * and {@code systemProperty} is {@code true} and + * {@code System.getProperty(prop)} is {@code null}
    • + *
    • {@code false} if {@code env.get(prop)} is {@code null} + * and {@code systemProperty} is {@code true} and + * {@code System.getProperty(prop).equalsIgnoreCase("false")} + * is {@code true}
    • + *
    • {@code true} if {@code env.get(prop)} is {@code null} + * and {@code systemProperty} is {@code true} and + * {@code System.getProperty(prop).equalsIgnoreCase("true")} + * is {@code true}
    • + *
    • {@code false} if + * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} + * is {@code true}
    • + *
    • {@code true} if + * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} + * is {@code true}
    • + *
    + * + * @throws IllegalArgumentException if {@code env} is {@code null} or + * {@code env.get(prop)} is not {@code null} and + * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and + * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are + * {@code false}. + * @throws ClassCastException if {@code env.get(prop)} cannot be cast + * to {@code String}. + */ + public static boolean computeBooleanFromString( + Map env, String prop, boolean systemProperty, boolean defaultValue) { if (env == null) throw new IllegalArgumentException("env map cannot be null"); String stringBoolean = (String) env.get(prop); + if (stringBoolean == null && systemProperty) { + stringBoolean = + AccessController.doPrivileged(new GetPropertyAction(prop)); + } if (stringBoolean == null) - return false; + return defaultValue; else if (stringBoolean.equalsIgnoreCase("true")) return true; else if (stringBoolean.equalsIgnoreCase("false")) @@ -703,6 +779,65 @@ public class EnvHelp { return new Hashtable(m); } + /** + * Returns true if the parameter JMXConnector.USE_EVENT_SERVICE is set to a + * String equals "true" by ignoring case in the map or in the System. + */ + public static boolean eventServiceEnabled(Map env) { + return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true); + } + + /** + * Returns true if the parameter JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE + * is set to a String equals "true" (ignores case). + * If the property DELEGATE_TO_EVENT_SERVICE is not set, returns + * a default value of "true". + */ + public static boolean delegateToEventService(Map env) { + return computeBooleanFromString(env, + JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true); + } + +// /** +// *

    Name of the attribute that specifies an EventRelay object to use. +// */ +// public static final String EVENT_RELAY = +// "jmx.remote.x.event.relay"; +// +// +// /** +// * Returns an EventRelay object. The default one is FetchingEventRelay. +// * If {@code EVENT_RELAY} is specified in {@code env} as a key, +// * its value will be returned as an EventRelay object, if the value is +// * not of type {@code EventRelay}, the default {@code FetchingEventRelay} +// * will be returned. +// * If {@code EVENT_RELAY} is not specified but {@code ENABLE_EVENT_RELAY} +// * is specified as a key and its value is , the default {@code FetchingEventRelay} +// * will be returned. +// */ +// public static EventRelay getEventRelay(Map env) { +// Map info = env == null ? +// Collections.EMPTY_MAP : env; +// +// Object o = env.get(EVENT_RELAY); +// if (o instanceof EventRelay) { +// return (EventRelay)o; +// } else if (o != null) { +// logger.warning("getEventRelay", +// "The user specified object is not an EventRelay object, " + +// "using the default class FetchingEventRelay."); +// +// return new FetchingEventRelay(); +// } +// +// if (enableEventRelay(env)) { +// return new FetchingEventRelay(); +// } +// +// return null; +// } + + private static final class SinkOutputStream extends OutputStream { public void write(byte[] b, int off, int len) {} public void write(int b) {} diff --git a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..6281b68a574b1e2c1a4450c2206493e106f7b631 --- /dev/null +++ b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java @@ -0,0 +1,471 @@ +/* + * 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 com.sun.jmx.remote.util; + +import com.sun.jmx.defaults.JmxProperties; +import com.sun.jmx.event.EventClientFactory; + +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.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServerConnection; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +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 + * {@link MBeanServerConnection} and an {@link EventClient}. + * All methods are routed to the underlying {@code MBeanServerConnection}, + * except add/remove notification listeners which are routed to the + * {@code EventClient}. + * The caller only sees an {@code MBeanServerConnection} which uses an + * {@code EventClient} behind the scenes. + * + * @author Sun Microsystems, Inc. + */ +public class EventClientConnection implements InvocationHandler, + EventClientFactory { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NOTIFICATION_LOGGER; + + private static final int NAMESPACE_SEPARATOR_LENGTH = + JMXNamespaces.NAMESPACE_SEPARATOR.length(); + + /** + * Creates a new {@code EventClientConnection}. + * @param connection The underlying MBeanServerConnection. + */ + public EventClientConnection(MBeanServerConnection connection) { + this(connection,null); + } + + /** + * Creates a new {@code EventClientConnection}. + * @param connection The underlying MBeanServerConnection. + * @param eventClientFactory a factory object that will be invoked + * to create an {@link EventClient} when needed. + * The {@code EventClient} is created lazily, when it is needed + * for the first time. If null, a default factory will be used + * (see {@link #createEventClient}). + */ + public EventClientConnection(MBeanServerConnection connection, + Callable eventClientFactory) { + + if (connection == null) { + throw new IllegalArgumentException("Null connection"); + } + this.connection = connection; + if (eventClientFactory == null) { + eventClientFactory = new Callable() { + public final EventClient call() throws Exception { + return createEventClient(EventClientConnection.this.connection); + } + }; + } + this.eventClientFactory = eventClientFactory; + this.lock = new ReentrantLock(); + } + + /** + *

    The MBean server connection through which the methods of + * a proxy using this handler are forwarded.

    + * + * @return the MBean server connection. + * + * @since 1.6 + */ + public MBeanServerConnection getMBeanServerConnection() { + return connection; + } + + + + + /** + * Creates a new EventClientConnection proxy instance. + * + * @param The underlying {@code MBeanServerConnection} - which should + * not be using the Event Service itself. + * @param interfaceClass {@code MBeanServerConnection.class}, or a subclass. + * @param eventClientFactory a factory used to create the EventClient. + * If null, a default factory is used (see {@link + * #createEventClient}). + * @return the new proxy instance, which will route add/remove notification + * listener calls through an {@code EventClient}. + * + */ + private static T + newProxyInstance(T connection, + Class interfaceClass, Callable eventClientFactory) { + final InvocationHandler handler = + new EventClientConnection(connection,eventClientFactory); + final Class[] interfaces = + new Class[] {interfaceClass, EventClientFactory.class}; + + Object proxy = + Proxy.newProxyInstance(interfaceClass.getClassLoader(), + interfaces, + handler); + return interfaceClass.cast(proxy); + } + + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + final String methodName = method.getName(); + + // add/remove notification listener are routed to the EventClient + if (methodName.equals("addNotificationListener") + || methodName.equals("removeNotificationListener")) { + final Class[] sig = method.getParameterTypes(); + if (sig.length>1 && + NotificationListener.class.isAssignableFrom(sig[1])) { + return invokeBroadcasterMethod(proxy,method,args); + } + } + + // subscribe/unsubscribe are also routed to the EventClient. + final Class clazz = method.getDeclaringClass(); + if (clazz.equals(EventClientFactory.class)) { + return invokeEventClientSubscriberMethod(proxy,method,args); + } + + // local or not: equals, toString, hashCode + if (shouldDoLocally(proxy, method)) + return doLocally(proxy, method, args); + + return call(connection,method,args); + } + + // The purpose of this method is to unwrap InvocationTargetException, + // in order to avoid throwing UndeclaredThrowableException for + // declared exceptions. + // + // When calling method.invoke(), any exception thrown by the invoked + // method will be wrapped in InvocationTargetException. If we don't + // unwrap this exception, the proxy will always throw + // UndeclaredThrowableException, even for runtime exceptions. + // + private Object call(final Object obj, final Method m, + final Object[] args) + throws Throwable { + try { + return m.invoke(obj,args); + } catch (InvocationTargetException x) { + final Throwable xx = x.getTargetException(); + if (xx == null) throw x; + else throw xx; + } + } + + /** + * Route add/remove notification listener to the event client. + **/ + private Object invokeBroadcasterMethod(Object proxy, Method method, + Object[] args) throws Exception { + final String methodName = method.getName(); + final int nargs = (args == null) ? 0 : args.length; + + if (nargs < 1) { + final String msg = + "Bad arg count: " + nargs; + throw new IllegalArgumentException(msg); + } + + final ObjectName mbean = (ObjectName) args[0]; + final EventClient evtClient = getEventClient(); + + // 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. + // + // Note that if the wrapped MBeanServerConnection points to a an + // 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 evtClient indicates that the remote VM is of + // an earlier version, in which case it shouldn't contain any namespace. + // + // So having a null evtClient AND an MBean contained in a namespace is + // clearly an error case. + // + if (evtClient == null) { + final String domain = mbean.getDomain(); + final int index = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); + if (index > -1 && index < + (domain.length()-NAMESPACE_SEPARATOR_LENGTH)) { + throw new UnsupportedOperationException(method.getName()+ + " on namespace "+domain.substring(0,index+ + NAMESPACE_SEPARATOR_LENGTH)); + } + } + + if (methodName.equals("addNotificationListener")) { + /* The various throws of IllegalArgumentException here + should not happen, since we know what the methods in + NotificationBroadcaster and NotificationEmitter + are. */ + if (nargs != 4) { + final String msg = + "Bad arg count to addNotificationListener: " + nargs; + throw new IllegalArgumentException(msg); + } + /* Other inconsistencies will produce ClassCastException + below. */ + + final NotificationListener listener = (NotificationListener) args[1]; + final NotificationFilter filter = (NotificationFilter) args[2]; + final Object handback = args[3]; + + if (evtClient != null) { + // general case + evtClient.addNotificationListener(mbean,listener,filter,handback); + } else { + // deprecated case. Only works for mbean in local namespace. + connection.addNotificationListener(mbean,listener,filter, + handback); + } + return null; + + } else if (methodName.equals("removeNotificationListener")) { + + /* NullPointerException if method with no args, but that + shouldn't happen because removeNL does have args. */ + NotificationListener listener = (NotificationListener) args[1]; + + switch (nargs) { + case 2: + if (evtClient != null) { + // general case + evtClient.removeNotificationListener(mbean,listener); + } else { + // deprecated case. Only works for mbean in local namespace. + connection.removeNotificationListener(mbean, listener); + } + return null; + + case 4: + NotificationFilter filter = (NotificationFilter) args[2]; + Object handback = args[3]; + if (evtClient != null) { + evtClient.removeNotificationListener(mbean, + listener, + filter, + handback); + } else { + connection.removeNotificationListener(mbean, + listener, + filter, + handback); + } + return null; + + default: + final String msg = + "Bad arg count to removeNotificationListener: " + nargs; + throw new IllegalArgumentException(msg); + } + + } else { + throw new IllegalArgumentException("Bad method name: " + + methodName); + } + } + + private boolean shouldDoLocally(Object proxy, Method method) { + final String methodName = method.getName(); + if ((methodName.equals("hashCode") || methodName.equals("toString")) + && method.getParameterTypes().length == 0 + && isLocal(proxy, method)) + return true; + if (methodName.equals("equals") + && Arrays.equals(method.getParameterTypes(), + new Class[] {Object.class}) + && isLocal(proxy, method)) + return true; + return false; + } + + private Object doLocally(Object proxy, Method method, Object[] args) { + final String methodName = method.getName(); + + if (methodName.equals("equals")) { + + if (this == args[0]) { + return true; + } + + if (!(args[0] instanceof Proxy)) { + return false; + } + + final InvocationHandler ihandler = + Proxy.getInvocationHandler(args[0]); + + if (ihandler == null || + !(ihandler instanceof EventClientConnection)) { + return false; + } + + final EventClientConnection handler = + (EventClientConnection)ihandler; + + return connection.equals(handler.connection) && + proxy.getClass().equals(args[0].getClass()); + } else if (methodName.equals("hashCode")) { + return connection.hashCode(); + } + + throw new RuntimeException("Unexpected method name: " + methodName); + } + + private static boolean isLocal(Object proxy, Method method) { + final Class[] interfaces = proxy.getClass().getInterfaces(); + if(interfaces == null) { + return true; + } + + final String methodName = method.getName(); + final Class[] params = method.getParameterTypes(); + for (Class intf : interfaces) { + try { + intf.getMethod(methodName, params); + return false; // found method in one of our interfaces + } catch (NoSuchMethodException nsme) { + // OK. + } + } + + return true; // did not find in any interface + } + + /** + * Return the EventClient used by this object. Can be null if the + * remote VM is of an earlier JDK version which doesn't have the + * event service.
    + * This method will invoke the event client factory the first time + * it is called. + **/ + public final EventClient getEventClient() { + if (initialized) return client; + try { + if (!lock.tryLock(TRYLOCK_TIMEOUT,TimeUnit.SECONDS)) + throw new IllegalStateException("can't acquire lock"); + try { + client = eventClientFactory.call(); + initialized = true; + } finally { + lock.unlock(); + } + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new IllegalStateException("Can't create EventClient: "+x,x); + } + return client; + } + + /** + * Returns an event client for the wrapped {@code MBeanServerConnection}. + * This is the method invoked by the default event client factory. + * @param connection the wrapped {@code MBeanServerConnection}. + **/ + protected EventClient createEventClient(MBeanServerConnection connection) + throws Exception { + final ObjectName name = + EventClientDelegate.OBJECT_NAME; + if (connection.isRegistered(name)) { + return new EventClient(connection); + } + return null; + } + + /** + * Creates a new {@link MBeanServerConnection} that goes through an + * {@link EventClient} to receive/subscribe to notifications. + * @param connection the underlying {@link MBeanServerConnection}. + * The given connection shouldn't be already + * using an {@code EventClient}. + * @param eventClientFactory a factory object that will be invoked + * to create an {@link EventClient} when needed. + * The {@code EventClient} is created lazily, when it is needed + * for the first time. If null, a default factory will be used + * (see {@link #createEventClient}). + * @return the + **/ + public static MBeanServerConnection getEventConnectionFor( + MBeanServerConnection connection, + Callable eventClientFactory) { + // if c already uses an EventClient no need to create a new one. + // + if (connection instanceof EventClientFactory + && eventClientFactory != null) + throw new IllegalArgumentException("connection already uses EventClient"); + + if (connection instanceof EventClientFactory) + return connection; + + // create a new proxy using an event client. + // + if (LOG.isLoggable(Level.FINE)) + LOG.fine("Creating EventClient for: "+connection); + return newProxyInstance(connection, + MBeanServerConnection.class, + eventClientFactory); + } + + private Object invokeEventClientSubscriberMethod(Object proxy, + Method method, Object[] args) throws Throwable { + return call(this,method,args); + } + + // Maximum lock timeout in seconds. Obviously arbitrary. + // + private final static short TRYLOCK_TIMEOUT = 3; + + private final MBeanServerConnection connection; + private final Callable eventClientFactory; + private final Lock lock; + private volatile EventClient client = null; + private volatile boolean initialized = false; + +} diff --git a/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java b/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java index 95090412ad4d7fdfc25aeddbf5b468b68f55fd46..452500d52aa8cfab05066026f76308d6f5f5017e 100644 --- a/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java +++ b/src/share/classes/com/sun/jmx/snmp/tasks/ThreadService.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 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 @@ -45,15 +45,9 @@ public class ThreadService implements TaskServer { minThreads = threadNumber; threadList = new ExecutorThread[threadNumber]; -// for (int i=0; i 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 + 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 return true; } @@ -307,11 +307,10 @@ public class ExtCheck { } /** - * 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 @@ public class ExtCheck { } 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 --git a/src/share/classes/com/sun/tools/extcheck/Main.java b/src/share/classes/com/sun/tools/extcheck/Main.java index 893af063f46a90130c91e87fcb70a028b2330025..022346efc13cfaec7bdd4e255e30254c010f67e5 100644 --- a/src/share/classes/com/sun/tools/extcheck/Main.java +++ b/src/share/classes/com/sun/tools/extcheck/Main.java @@ -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 @@ import java.io.*; */ 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 @@ public final class Main { * 0 No newer jar file was found * -1 An internal error occurred */ - public static void main(String args[]){ - - if (args.length < 1){ - System.err.println("Usage: extcheck [-verbose] "); + public static void main(String args[]) { + try { + realMain(args); + } catch (Exception ex) { + System.err.println(ex.getMessage()); 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 @@ public final class Main { } else { System.exit(1); } - } + private static void usage(String msg) throws Exception { + throw new Exception(msg + "\nUsage: extcheck [-verbose] "); + } } + diff --git a/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java b/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java index df09dd5c5b67d3fa304c69c2b2a0b51321003dc5..1bbac940f8908e5374d891295a633ee417a07fde 100644 --- a/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java +++ b/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java @@ -120,7 +120,7 @@ public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes 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 @@ public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes 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 @@ public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes 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 @@ public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes 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 @@ public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes 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 --git a/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java b/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java index ea2f49da5aa54065446698c33434eab234ab587d..6653199d7915f3d9c03de5ef1a416c3d7a38b7f9 100644 --- a/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java +++ b/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java index 7af01561e9b2b0cb36fa062b95a2b995282b365f..ec8ddaf0e5638081b46909856cad82e0303254b8 100644 --- a/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java +++ b/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/share/classes/com/sun/tools/jdi/VMAction.java b/src/share/classes/com/sun/tools/jdi/VMAction.java index 7a5628e0acdb7877130a21a9902eb5707f27d617..238824c88b43375de949eb287bc20787d62456aa 100644 --- a/src/share/classes/com/sun/tools/jdi/VMAction.java +++ b/src/share/classes/com/sun/tools/jdi/VMAction.java @@ -1,5 +1,5 @@ /* - * Copyright 1999 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 diff --git a/src/share/classes/com/sun/tools/jdi/VMState.java b/src/share/classes/com/sun/tools/jdi/VMState.java index 789e5acdb73c25f884688923a30cc5effbe88f1d..762419797f94bc4ba6661663fe471db38cacd28b 100644 --- a/src/share/classes/com/sun/tools/jdi/VMState.java +++ b/src/share/classes/com/sun/tools/jdi/VMState.java @@ -1,5 +1,5 @@ /* - * Copyright 1999 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 diff --git a/src/share/classes/java/awt/Button.java b/src/share/classes/java/awt/Button.java index 5b751ce345e167895568e5cd6c6f430831f71d08..8982a60cc8321f36e123e85468f95adc8a057576 100644 --- a/src/share/classes/java/awt/Button.java +++ b/src/share/classes/java/awt/Button.java @@ -213,8 +213,8 @@ public class Button extends Component implements Accessible { } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff --git a/src/share/classes/java/awt/Checkbox.java b/src/share/classes/java/awt/Checkbox.java index e366e54f6cdeedbb58b47b43376a9fa59acadd4e..7e5599d5ef95c0169a51b383c41409d4a88fccff 100644 --- a/src/share/classes/java/awt/Checkbox.java +++ b/src/share/classes/java/awt/Checkbox.java @@ -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 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff --git a/src/share/classes/java/awt/Choice.java b/src/share/classes/java/awt/Choice.java index 9edb8ac7d8c33a817604ee905d37e381d6d8afef..ea46b8d772e8424b31709fcd90e63577a0d60798 100644 --- a/src/share/classes/java/awt/Choice.java +++ b/src/share/classes/java/awt/Choice.java @@ -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 @@ public class Choice extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -269,9 +267,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -299,9 +295,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -323,9 +317,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -367,9 +359,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { } // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** diff --git a/src/share/classes/java/awt/Component.java b/src/share/classes/java/awt/Component.java index c3e0769837d991e8c0132ee1d56a1d2ba41f2209..8896ec248b4a65b52c16ae0ff96734f79c4cfd2b 100644 --- a/src/share/classes/java/awt/Component.java +++ b/src/share/classes/java/awt/Component.java @@ -350,7 +350,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @see #validate * @see #invalidate */ - volatile boolean valid = false; + private volatile boolean valid = false; /** * The DropTarget associated with this component. @@ -639,11 +639,21 @@ public abstract class Component implements ImageObserver, MenuContainer, */ 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 abstract class Component implements ImageObserver, MenuContainer, */ public String getName() { if (name == null && !nameExplicitlySet) { - synchronized(this) { + synchronized(getObjectLock()) { if (name == null && !nameExplicitlySet) name = constructComponentName(); } @@ -833,7 +843,7 @@ public abstract class Component implements ImageObserver, MenuContainer, */ public void setName(String name) { String oldName; - synchronized(this) { + synchronized(getObjectLock()) { oldName = this.name; this.name = name; nameExplicitlySet = true; @@ -1708,9 +1718,9 @@ public abstract class Component implements ImageObserver, MenuContainer, // 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 @@ public abstract class Component implements ImageObserver, MenuContainer, firePropertyChange("locale", oldValue, l); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -2078,8 +2086,8 @@ public abstract class Component implements ImageObserver, MenuContainer, if (resized) { invalidate(); } - if (parent != null && parent.valid) { - parent.invalidate(); + if (parent != null) { + parent.invalidateIfValid(); } } if (needNotify) { @@ -2135,7 +2143,7 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, peer.layout(); } valid = true; + if (!wasValid) { + mixOnValidating(); + } } } @@ -2687,12 +2699,20 @@ public abstract class Component implements ImageObserver, MenuContainer, 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(); + } + } + /** * Creates a graphics context for this component. This method will * return null if this component is currently not @@ -5794,7 +5814,7 @@ public abstract class Component implements ImageObserver, MenuContainer, } } - transient EventQueueItem[] eventCache; + transient sun.awt.EventQueueItem[] eventCache; /** * @see #isCoalescingEnabled @@ -7545,9 +7565,7 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 abstract class Component implements ImageObserver, MenuContainer, */ public void addPropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -7931,7 +7947,7 @@ public abstract class Component implements ImageObserver, MenuContainer, */ public void removePropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -7954,7 +7970,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners() { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -7996,7 +8012,7 @@ public abstract class Component implements ImageObserver, MenuContainer, public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -8026,7 +8042,7 @@ public abstract class Component implements ImageObserver, MenuContainer, public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -8050,7 +8066,7 @@ public abstract class Component implements ImageObserver, MenuContainer, */ public PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -8071,7 +8087,7 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - changeSupportLock = new Object(); + objectLock = new Object(); s.defaultReadObject(); @@ -8537,9 +8553,7 @@ public abstract class Component implements ImageObserver, MenuContainer, firePropertyChange("componentOrientation", oldValue, o); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -8575,6 +8589,14 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, * 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 @@ public abstract class Component implements ImageObserver, MenuContainer, */ 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 @@ public abstract class Component implements ImageObserver, MenuContainer, } } + 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 --git a/src/share/classes/java/awt/Container.java b/src/share/classes/java/awt/Container.java index 2a24ac62656a1b92778c52859b882f2bdf78002e..c302e4b0edc94042a4f9643c05bb020cc2f273a8 100644 --- a/src/share/classes/java/awt/Container.java +++ b/src/share/classes/java/awt/Container.java @@ -44,8 +44,6 @@ import java.io.PrintWriter; 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { */ @Deprecated public int countComponents() { - return ncomponents; + synchronized (getTreeLock()) { + return component.size(); + } } /** @@ -302,10 +295,10 @@ public class Container extends Component { */ 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 @@ public class Container extends Component { // 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() @@ -421,6 +414,29 @@ public class Container extends Component { return comp; } + /** + * 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, @@ -437,26 +453,18 @@ public class Container extends Component { 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"); - } - } + checkAddToSelf(comp); + checkNotAWindow(comp); - if (comp instanceof Window) { - throw new IllegalArgumentException("adding a window to a container"); - } - } Window thisTopLevel = getContainingWindow(); Window compTopLevel = comp.getContainingWindow(); if (thisTopLevel != compTopLevel) { @@ -495,25 +503,17 @@ public class Container extends Component { adjustDescendants(-(comp.countHierarchyMembers())); comp.parent = null; - System.arraycopy(component, index + 1, - component, index, - ncomponents - index - 1); - component[--ncomponents] = null; + component.remove(index); - if (valid) { - invalidate(); - } + 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 @@ public class Container extends Component { // 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { // 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { */ 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 @@ public class Container extends Component { /* 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 @@ public class Container extends Component { comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); adjustDescendants(comp.countHierarchyMembers()); - if (valid) { - invalidate(); - } + invalidateIfValid(); if (peer != null) { comp.addNotify(); } @@ -1129,11 +1097,9 @@ public class Container extends Component { * 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 class Container extends Component { */ 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 @@ public class Container extends Component { adjustDescendants(-(comp.countHierarchyMembers())); comp.parent = null; - System.arraycopy(component, index + 1, - component, index, - ncomponents - index - 1); - component[--ncomponents] = null; + component.remove(index); - if (valid) { - invalidate(); - } + invalidateIfValid(); if (containerListener != null || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { @@ -1229,14 +1190,9 @@ public class Container extends Component { 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 @@ public class Container extends Component { -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 @@ public class Container extends Component { if (peer != null && layoutMgr == null && isVisible()) { updateCursorImmediately(); } - if (valid) { - invalidate(); - } + invalidateIfValid(); } } @@ -1300,8 +1253,8 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 class Container extends Component { */ public void setLayout(LayoutManager mgr) { layoutMgr = mgr; - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** @@ -1522,10 +1473,10 @@ public class Container extends Component { */ 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 @@ public class Container extends Component { p.beginValidate(); } validateTree(); - valid = true; if (p != null) { p.endValidate(); updateCur = isVisible(); @@ -1557,17 +1507,16 @@ public class Container extends Component { * @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 @@ public class Container extends Component { ((ContainerPeer)peer).endLayout(); } } - valid = true; + super.validate(); } /** @@ -1586,20 +1535,16 @@ public class Container extends Component { */ 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 @@ public class Container extends Component { // 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 @@ public class Container extends Component { } GraphicsCallback.PrintCallback.getInstance(). - runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS); + runComponents(component.toArray(EMPTY_ARRAY), g, GraphicsCallback.LIGHTWEIGHTS); } } @@ -1906,7 +1851,7 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { } 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 @@ public class Container extends 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.peer instanceof LightweightPeer) { if (comp.contains(x - comp.x, y - comp.y)) { @@ -2544,43 +2487,43 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 class Container extends Component { */ 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 @@ public class Container extends Component { } if ( dispatcher != null ) { dispatcher.dispose(); - dispatcher = null; + dispatcher = null; } super.removeNotify(); } @@ -2873,12 +2824,12 @@ public class Container extends Component { */ 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 class Container extends Component { */ 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 class Container extends Component { */ 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 @@ public class Container extends Component { */ 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { 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 @@ public class Container extends Component { } } + @Override + void mixOnValidating() { + synchronized (getTreeLock()) { + if (mixingLog.isLoggable(Level.FINE)) { + mixingLog.fine("this = " + this); + } + + if (hasHeavyweightDescendants()) { + recursiveApplyCurrentShape(); + } + + super.mixOnValidating(); + } + } + // ****************** END OF MIXING CODE ******************************** } diff --git a/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java b/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java index 5e75cdaf763c6f2e294f3649574c17eacd2bfe63..187ddc54931452bcfd9b4681bff4b7c99002ff10 100644 --- a/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/src/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -556,8 +556,7 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy * 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 --git a/src/share/classes/java/awt/DefaultKeyboardFocusManager.java b/src/share/classes/java/awt/DefaultKeyboardFocusManager.java index a061184139fd8b3f8a660f7a57f5dbd4c7585608..5dd0d9061ff0ef2dfbfd42fa7a99ed0383624db0 100644 --- a/src/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/src/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -154,7 +154,7 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { 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 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { } } - 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 class DefaultKeyboardFocusManager extends KeyboardFocusManager { 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 --git a/src/share/classes/java/awt/Dialog.java b/src/share/classes/java/awt/Dialog.java index f236f2677d402f7fbf58af42cb6611fbcd1c0b83..2104a64b742f8d980f37a8441e359387ed17b79b 100644 --- a/src/share/classes/java/awt/Dialog.java +++ b/src/share/classes/java/awt/Dialog.java @@ -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 @@ public class Dialog extends Window { // 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 --git a/src/share/classes/java/awt/EventQueue.java b/src/share/classes/java/awt/EventQueue.java index 8620c2880f5d6dcc5e7b37e36ad3c649909a1d9e..9697ad5e9f500abd9e40d84046d76757d146f83b 100644 --- a/src/share/classes/java/awt/EventQueue.java +++ b/src/share/classes/java/awt/EventQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 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 @@ -42,6 +42,7 @@ import sun.awt.AppContext; 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 @@ public class EventQueue { 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 @@ public class EventQueue { 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 @@ public class EventQueue { 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 @@ class Queue { EventQueueItem head; EventQueueItem tail; } - -class EventQueueItem { - AWTEvent event; - int id; - EventQueueItem next; - - EventQueueItem(AWTEvent evt) { - event = evt; - id = evt.getID(); - } -} diff --git a/src/share/classes/java/awt/Frame.java b/src/share/classes/java/awt/Frame.java index 0e897d433097d3191d7d560468e8f010ddb12205..290f7f9bb3d2e64fe7b58ffcf68aa7d5b4ea4235 100644 --- a/src/share/classes/java/awt/Frame.java +++ b/src/share/classes/java/awt/Frame.java @@ -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 @@ public class Frame extends Window implements MenuContainer { if (peer != null) { mbManagement = true; menuBar.addNotify(); - if (valid) { - invalidate(); - } + invalidateIfValid(); peer.setMenuBar(menuBar); } } @@ -633,8 +631,8 @@ public class Frame extends Window implements MenuContainer { // 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 @@ public class Frame extends Window implements MenuContainer { FramePeer peer = (FramePeer)this.peer; if (peer != null) { mbManagement = true; - if (valid) { - invalidate(); - } + invalidateIfValid(); peer.setMenuBar(null); m.removeNotify(); } diff --git a/src/share/classes/java/awt/Label.java b/src/share/classes/java/awt/Label.java index 5daf2b88b6fbe3337156d6be4687314042ce6497..80f167358c4751eaee39da65e5bdc21ffbe7a665 100644 --- a/src/share/classes/java/awt/Label.java +++ b/src/share/classes/java/awt/Label.java @@ -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 @@ public class Label extends Component implements Accessible { } // This could change the preferred size of the Component. - if (testvalid && valid) { - invalidate(); + if (testvalid) { + invalidateIfValid(); } } diff --git a/src/share/classes/java/awt/ScrollPane.java b/src/share/classes/java/awt/ScrollPane.java index b34c978474fa814c244119da2949dc4edc5c14cd..99997dba20f9a373f0432227c33a5788b3fd42ea 100644 --- a/src/share/classes/java/awt/ScrollPane.java +++ b/src/share/classes/java/awt/ScrollPane.java @@ -357,7 +357,7 @@ public class ScrollPane extends Container implements Accessible { */ 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 @@ public class ScrollPane extends Container implements Accessible { */ @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 @@ public class ScrollPane extends Container implements Accessible { */ @Deprecated public void layout() { - if (ncomponents > 0) { - 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); - } + if (getComponentCount()==0) { + return; + } + Component c = getComponent(0); + Point p = getScrollPosition(); + Dimension cs = calculateChildSize(); + Dimension vs = getViewportSize(); + Insets i = getInsets(); - // 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); + 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); } /** @@ -515,20 +518,21 @@ public class ScrollPane extends Container implements Accessible { * @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(); - - 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(); - } + 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(); } } @@ -589,7 +593,7 @@ public class ScrollPane extends Container implements Accessible { 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 --git a/src/share/classes/java/awt/SystemTray.java b/src/share/classes/java/awt/SystemTray.java index 650821e726e092393ca425048af4cc83409dc51c..2aa172108b1c71c5940d9369ffa396afe5c2bd1e 100644 --- a/src/share/classes/java/awt/SystemTray.java +++ b/src/share/classes/java/awt/SystemTray.java @@ -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 @@ public class SystemTray { transient private SystemTrayPeer peer; + private static final TrayIcon[] EMPTY_TRAY_ARRAY = new TrayIcon[0]; + /** * Private SystemTray constructor. * @@ -201,17 +203,18 @@ public class SystemTray { * 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 @@ public class SystemTray { if (icons != null) { return (TrayIcon[])icons.toArray(new TrayIcon[icons.size()]); } - return new TrayIcon[0]; + return EMPTY_TRAY_ARRAY; } /** @@ -475,7 +478,12 @@ public class SystemTray { 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 --git a/src/share/classes/java/awt/TextField.java b/src/share/classes/java/awt/TextField.java index fb95d91b8949046583d1b401bafc0e2e91f5d44b..b2659aa99f0d12e0f61f4fa487d9a2f103e8abcb 100644 --- a/src/share/classes/java/awt/TextField.java +++ b/src/share/classes/java/awt/TextField.java @@ -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 @@ public class TextField extends TextComponent { super.setText(t); // This could change the preferred size of the Component. - if (valid) { - invalidate(); - } + invalidateIfValid(); } /** diff --git a/src/share/classes/java/awt/TrayIcon.java b/src/share/classes/java/awt/TrayIcon.java index 32ee66c25ba6db6f5992cdbafdaf95e1a86ed0cf..9fcdd2a6af1db64aab63d6229a17232337cb5f92 100644 --- a/src/share/classes/java/awt/TrayIcon.java +++ b/src/share/classes/java/awt/TrayIcon.java @@ -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.util.EventListener; 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 class TrayIcon { */ public TrayIcon(Image image) { this(); - if (image == null) { - throw new IllegalArgumentException("creating TrayIcon with null Image"); - } setImage(image); } @@ -433,7 +431,7 @@ public class TrayIcon { * @see java.awt.event.MouseListener */ public synchronized MouseListener[] getMouseListeners() { - return (MouseListener[])(getListeners(MouseListener.class)); + return AWTEventMulticaster.getListeners(mouseListener, MouseListener.class); } /** @@ -494,7 +492,7 @@ public class TrayIcon { * @see java.awt.event.MouseMotionListener */ public synchronized MouseMotionListener[] getMouseMotionListeners() { - return (MouseMotionListener[]) (getListeners(MouseMotionListener.class)); + return AWTEventMulticaster.getListeners(mouseMotionListener, MouseMotionListener.class); } /** @@ -581,7 +579,7 @@ public class TrayIcon { * @see java.awt.event.ActionListener */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[])(getListeners(ActionListener.class)); + return AWTEventMulticaster.getListeners(actionListener, ActionListener.class); } /** @@ -635,7 +633,7 @@ public class TrayIcon { TrayIconPeer peer = this.peer; if (peer != null) { - peer.displayMessage(caption, text, messageType.toString()); + peer.displayMessage(caption, text, messageType.name()); } } @@ -657,24 +655,17 @@ public class TrayIcon { // **************************************************************** // **************************************************************** - 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 --git a/src/share/classes/java/awt/Window.java b/src/share/classes/java/awt/Window.java index 3ebeee0063971a045aa1293e61d90704b1eff155..94a8ff2ed5bd42aaca5fcfd5fd1b3fc59945bdbd 100644 --- a/src/share/classes/java/awt/Window.java +++ b/src/share/classes/java/awt/Window.java @@ -3145,9 +3145,7 @@ public class Window extends Container implements Accessible { 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 --git a/src/share/classes/java/awt/dnd/DragSourceContext.java b/src/share/classes/java/awt/dnd/DragSourceContext.java index 89d0619b063c41bd70596ead8a02be389d2e126f..07768598fd51d309dea73716ea995aa1b4c88b2c 100644 --- a/src/share/classes/java/awt/dnd/DragSourceContext.java +++ b/src/share/classes/java/awt/dnd/DragSourceContext.java @@ -486,6 +486,8 @@ public class DragSourceContext Cursor c = null; switch (status) { + default: + targetAct = DnDConstants.ACTION_NONE; case ENTER: case OVER: case CHANGED: @@ -506,10 +508,6 @@ public class DragSourceContext else c = DragSource.DefaultCopyDrop; } - break; - default: - targetAct = DnDConstants.ACTION_NONE; - } setCursorImpl(c); diff --git a/src/share/classes/java/lang/AbstractStringBuilder.java b/src/share/classes/java/lang/AbstractStringBuilder.java index 4ba130b498913e7bbb2df578c6da6d6c850ea6d9..973e0854d618aa1f3035584d0c3357fa193c81a5 100644 --- a/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */ - char value[]; + char[] value; /** * The count is the number of characters used. @@ -333,8 +333,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * dst.length *
*/ - public void getChars(int srcBegin, int srcEnd, char dst[], - int dstBegin) + public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { if (srcBegin < 0) throw new StringIndexOutOfBoundsException(srcBegin); @@ -366,14 +365,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the Object - * argument. + * Appends the string representation of the {@code Object} argument. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(Object)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param obj an Object. + * @param obj an {@code Object}. * @return a reference to this object. */ public AbstractStringBuilder append(Object obj) { @@ -383,17 +382,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Appends the specified string to this character sequence. *

- * The characters of the String argument are appended, in + * The characters of the {@code String} argument are appended, in * order, increasing the length of this sequence by the length of the - * argument. If str is null, then the four - * characters "null" are appended. + * argument. If {@code str} is {@code null}, then the four + * characters {@code "null"} are appended. *

* Let n be the length of this character sequence just prior to - * execution of the append method. Then the character at + * execution of the {@code append} method. Then the character at * index k in the new character sequence is equal to the character * at index k in the old character sequence, if k is less * than n; otherwise, it is equal to the character at index - * k-n in the argument str. + * k-n in the argument {@code str}. * * @param str a string. * @return a reference to this object. @@ -435,33 +434,33 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends a subsequence of the specified CharSequence to this + * Appends a subsequence of the specified {@code CharSequence} to this * sequence. *

- * Characters of the argument s, starting at - * index start, are appended, in order, to the contents of - * this sequence up to the (exclusive) index end. The length - * of this sequence is increased by the value of end - start. + * Characters of the argument {@code s}, starting at + * index {@code start}, are appended, in order, to the contents of + * this sequence up to the (exclusive) index {@code end}. The length + * of this sequence is increased by the value of {@code end - start}. *

* Let n be the length of this character sequence just prior to - * execution of the append method. Then the character at + * execution of the {@code append} method. Then the character at * index k in this character sequence becomes equal to the * character at index k in this sequence, if k is less than * n; otherwise, it is equal to the character at index - * k+start-n in the argument s. + * k+start-n in the argument {@code s}. *

- * If s is null, then this method appends + * If {@code s} is {@code null}, then this method appends * characters as if the s parameter was a sequence containing the four - * characters "null". + * characters {@code "null"}. * * @param s the sequence to append. * @param start the starting index of the subsequence to be appended. * @param end the end index of the subsequence to be appended. * @return a reference to this object. * @throws IndexOutOfBoundsException if - * start or end are negative, or - * start is greater than end or - * end is greater than s.length() + * {@code start} is negative, or + * {@code start} is greater than {@code end} or + * {@code end} is greater than {@code s.length()} */ public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) @@ -483,22 +482,22 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the char array + * Appends the string representation of the {@code char} array * argument to this sequence. *

* The characters of the array argument are appended, in order, to * the contents of this sequence. The length of this sequence * increases by the length of the argument. *

- * The overall effect is exactly as if the argument were converted to - * a string by the method {@link String#valueOf(char[])} and the - * characters of that string were then {@link #append(String) appended} - * to this character sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(char[])}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * * @param str the characters to be appended. * @return a reference to this object. */ - public AbstractStringBuilder append(char str[]) { + public AbstractStringBuilder append(char[] str) { int newCount = count + str.length; if (newCount > value.length) expandCapacity(newCount); @@ -509,22 +508,25 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Appends the string representation of a subarray of the - * char array argument to this sequence. + * {@code char} array argument to this sequence. *

- * Characters of the char array str, starting at - * index offset, are appended, in order, to the contents + * Characters of the {@code char} array {@code str}, starting at + * index {@code offset}, are appended, in order, to the contents * of this sequence. The length of this sequence increases - * by the value of len. + * by the value of {@code len}. *

- * The overall effect is exactly as if the arguments were converted to - * a string by the method {@link String#valueOf(char[],int,int)} and the - * characters of that string were then {@link #append(String) appended} - * to this character sequence. + * The overall effect is exactly as if the arguments were converted + * to a string by the method {@link String#valueOf(char[],int,int)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * * @param str the characters to be appended. - * @param offset the index of the first char to append. - * @param len the number of chars to append. + * @param offset the index of the first {@code char} to append. + * @param len the number of {@code char}s to append. * @return a reference to this object. + * @throws IndexOutOfBoundsException + * if {@code offset < 0} or {@code len < 0} + * or {@code offset+len > str.length} */ public AbstractStringBuilder append(char str[], int offset, int len) { int newCount = count + len; @@ -536,14 +538,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the boolean + * Appends the string representation of the {@code boolean} * argument to the sequence. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(boolean)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param b a boolean. + * @param b a {@code boolean}. * @return a reference to this object. */ public AbstractStringBuilder append(boolean b) { @@ -569,18 +572,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the char + * Appends the string representation of the {@code char} * argument to this sequence. *

* The argument is appended to the contents of this sequence. - * The length of this sequence increases by 1. + * The length of this sequence increases by {@code 1}. *

- * The overall effect is exactly as if the argument were converted to - * a string by the method {@link String#valueOf(char)} and the character - * in that string were then {@link #append(String) appended} to this - * character sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(char)}, + * and the character in that string were then + * {@link #append(String) appended} to this character sequence. * - * @param c a char. + * @param c a {@code char}. * @return a reference to this object. */ public AbstractStringBuilder append(char c) { @@ -592,14 +595,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the int + * Appends the string representation of the {@code int} * argument to this sequence. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(int)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param i an int. + * @param i an {@code int}. * @return a reference to this object. */ public AbstractStringBuilder append(int i) { @@ -618,14 +622,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the long + * Appends the string representation of the {@code long} * argument to this sequence. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(long)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param l a long. + * @param l a {@code long}. * @return a reference to this object. */ public AbstractStringBuilder append(long l) { @@ -644,14 +649,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the float + * Appends the string representation of the {@code float} * argument to this sequence. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this string sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(float)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param f a float. + * @param f a {@code float}. * @return a reference to this object. */ public AbstractStringBuilder append(float f) { @@ -660,14 +666,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the double + * Appends the string representation of the {@code double} * argument to this sequence. *

- * The argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then appended to this sequence. + * The overall effect is exactly as if the argument were converted + * to a string by the method {@link String#valueOf(double)}, + * and the characters of that string were then + * {@link #append(String) appended} to this character sequence. * - * @param d a double. + * @param d a {@code double}. * @return a reference to this object. */ public AbstractStringBuilder append(double d) { @@ -677,17 +684,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Removes the characters in a substring of this sequence. - * The substring begins at the specified start and extends to - * the character at index end - 1 or to the end of the + * The substring begins at the specified {@code start} and extends to + * the character at index {@code end - 1} or to the end of the * sequence if no such character exists. If - * start is equal to end, no changes are made. + * {@code start} is equal to {@code end}, no changes are made. * * @param start The beginning index, inclusive. * @param end The ending index, exclusive. * @return This object. - * @throws StringIndexOutOfBoundsException if start - * is negative, greater than length(), or - * greater than end. + * @throws StringIndexOutOfBoundsException if {@code start} + * is negative, greater than {@code length()}, or + * greater than {@code end}. */ public AbstractStringBuilder delete(int start, int end) { if (start < 0) @@ -705,7 +712,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Appends the string representation of the codePoint + * Appends the string representation of the {@code codePoint} * argument to this sequence. * *

The argument is appended to the contents of this sequence. @@ -713,15 +720,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * {@link Character#charCount(int) Character.charCount(codePoint)}. * *

The overall effect is exactly as if the argument were - * converted to a char array by the method {@link - * Character#toChars(int)} and the character in that array were - * then {@link #append(char[]) appended} to this character + * converted to a {@code char} array by the method + * {@link Character#toChars(int)} and the character in that array + * were then {@link #append(char[]) appended} to this character * sequence. * * @param codePoint a Unicode code point * @return a reference to this object. * @exception IllegalArgumentException if the specified - * codePoint isn't a valid Unicode code point + * {@code codePoint} isn't a valid Unicode code point */ public AbstractStringBuilder appendCodePoint(int codePoint) { if (!Character.isValidCodePoint(codePoint)) { @@ -879,27 +886,27 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of a subarray of the str + * Inserts the string representation of a subarray of the {@code str} * array argument into this sequence. The subarray begins at the - * specified offset and extends len chars. + * specified {@code offset} and extends {@code len} {@code char}s. * The characters of the subarray are inserted into this sequence at - * the position indicated by index. The length of this - * sequence increases by len chars. + * the position indicated by {@code index}. The length of this + * sequence increases by {@code len} {@code char}s. * * @param index position at which to insert subarray. - * @param str A char array. - * @param offset the index of the first char in subarray to + * @param str A {@code char} array. + * @param offset the index of the first {@code char} in subarray to * be inserted. - * @param len the number of chars in the subarray to + * @param len the number of {@code char}s in the subarray to * be inserted. * @return This object - * @throws StringIndexOutOfBoundsException if index - * is negative or greater than length(), or - * offset or len are negative, or - * (offset+len) is greater than - * str.length. + * @throws StringIndexOutOfBoundsException if {@code index} + * is negative or greater than {@code length()}, or + * {@code offset} or {@code len} are negative, or + * {@code (offset+len)} is greater than + * {@code str.length}. */ - public AbstractStringBuilder insert(int index, char str[], int offset, + public AbstractStringBuilder insert(int index, char[] str, int offset, int len) { if ((index < 0) || (index > length())) @@ -918,20 +925,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the Object + * Inserts the string representation of the {@code Object} * argument into this character sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(Object)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param obj an Object. + * @param obj an {@code Object}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ @@ -942,28 +950,28 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Inserts the string into this character sequence. *

- * The characters of the String argument are inserted, in + * The characters of the {@code String} argument are inserted, in * order, into this sequence at the indicated offset, moving up any * characters originally above that position and increasing the length * of this sequence by the length of the argument. If - * str is null, then the four characters - * "null" are inserted into this sequence. + * {@code str} is {@code null}, then the four characters + * {@code "null"} are inserted into this sequence. *

* The character at index k in the new character sequence is * equal to: *

    *
  • the character at index k in the old character sequence, if - * k is less than offset - *
  • the character at index k-offset in the - * argument str, if k is not less than - * offset but is less than offset+str.length() - *
  • the character at index k-str.length() in the + * k is less than {@code offset} + *
  • the character at index k{@code -offset} in the + * argument {@code str}, if k is not less than + * {@code offset} but is less than {@code offset+str.length()} + *
  • the character at index k{@code -str.length()} in the * old character sequence, if k is not less than - * offset+str.length() + * {@code offset+str.length()} *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. * @param str a string. @@ -986,27 +994,30 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the char array + * Inserts the string representation of the {@code char} array * argument into this sequence. *

* The characters of the array argument are inserted into the * contents of this sequence at the position indicated by - * offset. The length of this sequence increases by + * {@code offset}. The length of this sequence increases by * the length of the argument. *

- * The overall effect is exactly as if the argument were converted to - * a string by the method {@link String#valueOf(char[])} and the - * characters of that string were then - * {@link #insert(int,String) inserted} into this - * character sequence at the position indicated by - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(char[])}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. + *

+ * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. * @param str a character array. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ - public AbstractStringBuilder insert(int offset, char str[]) { + public AbstractStringBuilder insert(int offset, char[] str) { if ((offset < 0) || (offset > length())) throw new StringIndexOutOfBoundsException(offset); int len = str.length; @@ -1020,18 +1031,20 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the specified CharSequence into this sequence. + * Inserts the specified {@code CharSequence} into this sequence. *

- * The characters of the CharSequence argument are inserted, + * The characters of the {@code CharSequence} argument are inserted, * in order, into this sequence at the indicated offset, moving up * any characters originally above that position and increasing the length * of this sequence by the length of the argument s. *

* The result of this method is exactly the same as if it were an - * invocation of this object's insert(dstOffset, s, 0, s.length()) method. + * invocation of this object's + * {@link #insert(int,CharSequence,int,int) insert}(dstOffset, s, 0, s.length()) + * method. * - *

If s is null, then the four characters - * "null" are inserted into this sequence. + *

If {@code s} is {@code null}, then the four characters + * {@code "null"} are inserted into this sequence. * * @param dstOffset the offset. * @param s the sequence to be inserted @@ -1047,51 +1060,51 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts a subsequence of the specified CharSequence into + * Inserts a subsequence of the specified {@code CharSequence} into * this sequence. *

- * The subsequence of the argument s specified by - * start and end are inserted, + * The subsequence of the argument {@code s} specified by + * {@code start} and {@code end} are inserted, * in order, into this sequence at the specified destination offset, moving * up any characters originally above that position. The length of this - * sequence is increased by end - start. + * sequence is increased by {@code end - start}. *

* The character at index k in this sequence becomes equal to: *

    *
  • the character at index k in this sequence, if - * k is less than dstOffset - *
  • the character at index k+start-dstOffset in - * the argument s, if k is greater than or equal to - * dstOffset but is less than dstOffset+end-start - *
  • the character at index k-(end-start) in this + * k is less than {@code dstOffset} + *
  • the character at index k{@code +start-dstOffset} in + * the argument {@code s}, if k is greater than or equal to + * {@code dstOffset} but is less than {@code dstOffset+end-start} + *
  • the character at index k{@code -(end-start)} in this * sequence, if k is greater than or equal to - * dstOffset+end-start + * {@code dstOffset+end-start} *

- * The dstOffset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code dstOffset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. *

The start argument must be nonnegative, and not greater than - * end. + * {@code end}. *

The end argument must be greater than or equal to - * start, and less than or equal to the length of s. + * {@code start}, and less than or equal to the length of s. * - *

If s is null, then this method inserts + *

If {@code s} is {@code null}, then this method inserts * characters as if the s parameter was a sequence containing the four - * characters "null". + * characters {@code "null"}. * * @param dstOffset the offset in this sequence. * @param s the sequence to be inserted. * @param start the starting index of the subsequence to be inserted. * @param end the end index of the subsequence to be inserted. * @return a reference to this object. - * @throws IndexOutOfBoundsException if dstOffset - * is negative or greater than this.length(), or - * start or end are negative, or - * start is greater than end or - * end is greater than s.length() + * @throws IndexOutOfBoundsException if {@code dstOffset} + * is negative or greater than {@code this.length()}, or + * {@code start} or {@code end} are negative, or + * {@code start} is greater than {@code end} or + * {@code end} is greater than {@code s.length()} */ public AbstractStringBuilder insert(int dstOffset, CharSequence s, - int start, int end) { + int start, int end) { if (s == null) s = "null"; if ((dstOffset < 0) || (dstOffset > this.length())) @@ -1115,20 +1128,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the boolean + * Inserts the string representation of the {@code boolean} * argument into this sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(boolean)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param b a boolean. + * @param b a {@code boolean}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ @@ -1137,25 +1151,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the char + * Inserts the string representation of the {@code char} * argument into this sequence. *

- * The second argument is inserted into the contents of this sequence - * at the position indicated by offset. The length - * of this sequence increases by one. - *

- * The overall effect is exactly as if the argument were converted to - * a string by the method {@link String#valueOf(char)} and the character - * in that string were then {@link #insert(int, String) inserted} into - * this character sequence at the position indicated by - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(char)}, + * and the character in that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param c a char. + * @param c a {@code char}. * @return a reference to this object. * @throws IndexOutOfBoundsException if the offset is invalid. */ @@ -1170,20 +1180,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the second int + * Inserts the string representation of the second {@code int} * argument into this sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(int)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param i an int. + * @param i an {@code int}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ @@ -1192,20 +1203,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the long + * Inserts the string representation of the {@code long} * argument into this sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the position - * indicated by offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(long)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param l a long. + * @param l a {@code long}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ @@ -1214,20 +1226,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the float + * Inserts the string representation of the {@code float} * argument into this sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(float)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param f a float. + * @param f a {@code float}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ @@ -1236,20 +1249,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } /** - * Inserts the string representation of the double + * Inserts the string representation of the {@code double} * argument into this sequence. *

- * The second argument is converted to a string as if by the method - * String.valueOf, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. + * The overall effect is exactly as if the second argument were + * converted to a string by the method {@link String#valueOf(double)}, + * and the characters of that string were then + * {@link #insert(int,String) inserted} into this character + * sequence at the indicated offset. *

- * The offset argument must be greater than or equal to - * 0, and less than or equal to the length of this - * sequence. + * The {@code offset} argument must be greater than or equal to + * {@code 0}, and less than or equal to the {@linkplain #length() length} + * of this sequence. * * @param offset the offset. - * @param d a double. + * @param d a {@code double}. * @return a reference to this object. * @throws StringIndexOutOfBoundsException if the offset is invalid. */ diff --git a/src/share/classes/java/lang/StringBuffer.java b/src/share/classes/java/lang/StringBuffer.java index e0ecbef0ebee2833d071bfe658d17a3790e9aade..c8cb51da81a5b9ca6e712dd4731c49bed0655fa1 100644 --- a/src/share/classes/java/lang/StringBuffer.java +++ b/src/share/classes/java/lang/StringBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2004 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 @@ -212,7 +212,7 @@ package java.lang; * @throws NullPointerException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ - public synchronized void getChars(int srcBegin, int srcEnd, char dst[], + public synchronized void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { super.getChars(srcBegin, srcEnd, dst, dstBegin); @@ -228,10 +228,6 @@ package java.lang; value[index] = ch; } - /** - * @see java.lang.String#valueOf(java.lang.Object) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(Object obj) { super.append(String.valueOf(obj)); return this; @@ -314,20 +310,19 @@ package java.lang; return this; } - public synchronized StringBuffer append(char str[]) { + public synchronized StringBuffer append(char[] str) { super.append(str); return this; } - public synchronized StringBuffer append(char str[], int offset, int len) { + /** + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public synchronized StringBuffer append(char[] str, int offset, int len) { super.append(str, offset, len); return this; } - /** - * @see java.lang.String#valueOf(boolean) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(boolean b) { super.append(b); return this; @@ -338,10 +333,6 @@ package java.lang; return this; } - /** - * @see java.lang.String#valueOf(int) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(int i) { super.append(i); return this; @@ -355,28 +346,16 @@ package java.lang; return this; } - /** - * @see java.lang.String#valueOf(long) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(long lng) { super.append(lng); return this; } - /** - * @see java.lang.String#valueOf(float) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(float f) { super.append(f); return this; } - /** - * @see java.lang.String#valueOf(double) - * @see #append(java.lang.String) - */ public synchronized StringBuffer append(double d) { super.append(d); return this; @@ -437,7 +416,7 @@ package java.lang; * @throws StringIndexOutOfBoundsException {@inheritDoc} * @since 1.2 */ - public synchronized StringBuffer insert(int index, char str[], int offset, + public synchronized StringBuffer insert(int index, char[] str, int offset, int len) { super.insert(index, str, offset, len); @@ -446,9 +425,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(java.lang.Object) - * @see #insert(int, java.lang.String) - * @see #length() */ public synchronized StringBuffer insert(int offset, Object obj) { super.insert(offset, String.valueOf(obj)); @@ -457,7 +433,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see #length() */ public synchronized StringBuffer insert(int offset, String str) { super.insert(offset, str); @@ -467,7 +442,7 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} */ - public synchronized StringBuffer insert(int offset, char str[]) { + public synchronized StringBuffer insert(int offset, char[] str) { super.insert(offset, str); return this; } @@ -498,9 +473,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(boolean) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuffer insert(int offset, boolean b) { return insert(offset, String.valueOf(b)); @@ -508,7 +480,6 @@ package java.lang; /** * @throws IndexOutOfBoundsException {@inheritDoc} - * @see #length() */ public synchronized StringBuffer insert(int offset, char c) { super.insert(offset, c); @@ -517,9 +488,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(int) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuffer insert(int offset, int i) { return insert(offset, String.valueOf(i)); @@ -527,9 +495,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(long) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuffer insert(int offset, long l) { return insert(offset, String.valueOf(l)); @@ -537,9 +502,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(float) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuffer insert(int offset, float f) { return insert(offset, String.valueOf(f)); @@ -547,9 +509,6 @@ package java.lang; /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(double) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuffer insert(int offset, double d) { return insert(offset, String.valueOf(d)); diff --git a/src/share/classes/java/lang/StringBuilder.java b/src/share/classes/java/lang/StringBuilder.java index 99f19768d62190d774f015d4c0ae0e7d59543112..803d70e39e83fcd425ab514f98c4637f0b3f047e 100644 --- a/src/share/classes/java/lang/StringBuilder.java +++ b/src/share/classes/java/lang/StringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,10 +124,6 @@ public final class StringBuilder append(seq); } - /** - * @see java.lang.String#valueOf(java.lang.Object) - * @see #append(java.lang.String) - */ public StringBuilder append(Object obj) { return append(String.valueOf(obj)); } @@ -175,7 +171,6 @@ public final class StringBuilder } /** - * @throws IndexOutOfBoundsException {@inheritDoc} */ public StringBuilder append(CharSequence s) { if (s == null) @@ -197,20 +192,19 @@ public final class StringBuilder return this; } - public StringBuilder append(char str[]) { + public StringBuilder append(char[] str) { super.append(str); return this; } - public StringBuilder append(char str[], int offset, int len) { + /** + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public StringBuilder append(char[] str, int offset, int len) { super.append(str, offset, len); return this; } - /** - * @see java.lang.String#valueOf(boolean) - * @see #append(java.lang.String) - */ public StringBuilder append(boolean b) { super.append(b); return this; @@ -221,37 +215,21 @@ public final class StringBuilder return this; } - /** - * @see java.lang.String#valueOf(int) - * @see #append(java.lang.String) - */ public StringBuilder append(int i) { super.append(i); return this; } - /** - * @see java.lang.String#valueOf(long) - * @see #append(java.lang.String) - */ public StringBuilder append(long lng) { super.append(lng); return this; } - /** - * @see java.lang.String#valueOf(float) - * @see #append(java.lang.String) - */ public StringBuilder append(float f) { super.append(f); return this; } - /** - * @see java.lang.String#valueOf(double) - * @see #append(java.lang.String) - */ public StringBuilder append(double d) { super.append(d); return this; @@ -292,7 +270,7 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} */ - public StringBuilder insert(int index, char str[], int offset, + public StringBuilder insert(int index, char[] str, int offset, int len) { super.insert(index, str, offset, len); @@ -301,9 +279,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(java.lang.Object) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, Object obj) { return insert(offset, String.valueOf(obj)); @@ -311,7 +286,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see #length() */ public StringBuilder insert(int offset, String str) { super.insert(offset, str); @@ -321,7 +295,7 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} */ - public StringBuilder insert(int offset, char str[]) { + public StringBuilder insert(int offset, char[] str) { super.insert(offset, str); return this; } @@ -349,9 +323,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(boolean) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, boolean b) { super.insert(offset, b); @@ -360,7 +331,6 @@ public final class StringBuilder /** * @throws IndexOutOfBoundsException {@inheritDoc} - * @see #length() */ public StringBuilder insert(int offset, char c) { super.insert(offset, c); @@ -369,9 +339,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(int) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, int i) { return insert(offset, String.valueOf(i)); @@ -379,9 +346,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(long) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, long l) { return insert(offset, String.valueOf(l)); @@ -389,9 +353,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(float) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, float f) { return insert(offset, String.valueOf(f)); @@ -399,9 +360,6 @@ public final class StringBuilder /** * @throws StringIndexOutOfBoundsException {@inheritDoc} - * @see java.lang.String#valueOf(double) - * @see #insert(int, java.lang.String) - * @see #length() */ public StringBuilder insert(int offset, double d) { return insert(offset, String.valueOf(d)); diff --git a/src/share/classes/java/lang/Thread.java b/src/share/classes/java/lang/Thread.java index e6dd655b366518ea2fb373e237e29c7a3327e1d6..60300ebc911b8eceaa96911ff8d180c8cbf9e3d1 100644 --- a/src/share/classes/java/lang/Thread.java +++ b/src/share/classes/java/lang/Thread.java @@ -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.AccessControlContext; 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 @@ import sun.security.util.SecurityConstants; * 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 @@ class Thread implements Runnable { */ 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 @@ class Thread implements Runnable { } } - g.addUnstarted(); this.group = g; @@ -403,160 +409,175 @@ class Thread implements Runnable { 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. - * - * @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) + * 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. 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. 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 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 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. - * - *

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") + * 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 + * {@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. - * - * @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 + * 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. 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 @@ class Thread implements Runnable { * 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 @@ class Thread implements Runnable { * 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 @@ class Thread implements Runnable { * *

Implementation note: Java platform implementers are encouraged to * document their implementation's behavior with respect to the - * stackSize parameter. - * - * @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. + * {@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 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 @@ class Thread implements Runnable { * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ + @Override public void run() { if (target != null) { target.run(); @@ -1386,28 +1425,25 @@ class Thread implements Runnable { * 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. - * - *

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

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, or {@code null} + * indicating the system class loader (or, failing that, the + * bootstrap class loader) * - * @return the context ClassLoader for this Thread - * - * @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 @@ class Thread implements Runnable { /** * 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. + * 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. * - *

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

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. * - * @param cl the context ClassLoader for this Thread + * @param cl + * the context ClassLoader for this Thread, or null indicating the + * system class loader (or, failing that, the bootstrap class loader) * - * @exception SecurityException if the current thread cannot set the - * context ClassLoader. - * @see #getContextClassLoader - * @see SecurityManager#checkPermission - * @see RuntimePermission + * @throws SecurityException + * if the current thread cannot set the context ClassLoader * * @since 1.2 */ diff --git a/src/share/classes/java/lang/management/PlatformComponent.java b/src/share/classes/java/lang/management/PlatformComponent.java index 3cd5d369da4ec63e2ad3670a4152aee96ae858b6..77c01161c9108ea728bd1d19cf9c05f46703a8d1 100644 --- a/src/share/classes/java/lang/management/PlatformComponent.java +++ b/src/share/classes/java/lang/management/PlatformComponent.java @@ -32,6 +32,7 @@ import java.util.HashSet; 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 @@ enum PlatformComponent { } }), + + /** + * 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 /** @@ -370,7 +388,7 @@ enum PlatformComponent { // if there are more than 1 key properties (i.e. other than "type") domainAndType += ",*"; } - ObjectName on = com.sun.jmx.mbeanserver.Util.newObjectName(domainAndType); + ObjectName on = ObjectName.valueOf(domainAndType); Set set = mbs.queryNames(on, null); for (PlatformComponent pc : subComponents) { set.addAll(pc.getObjectNames(mbs)); diff --git a/src/share/classes/java/net/HttpCookie.java b/src/share/classes/java/net/HttpCookie.java index 6e495e060bbe504343b4eb17de951c1916a34c8e..1fcdd6c51daa135b2243366a918f4e53095cef27 100644 --- a/src/share/classes/java/net/HttpCookie.java +++ b/src/share/classes/java/net/HttpCookie.java @@ -75,6 +75,7 @@ public final class HttpCookie implements Cloneable { private String path; // Path=VALUE ... URLs that see the cookie private String portlist; // Port[="portlist"] ... the port cookie may be returned to private boolean secure; // Secure ... e.g. use SSL + private boolean httpOnly; // HttpOnly ... i.e. not accessible to scripts private int version = 1; // Version=1 ... RFC 2965 style // @@ -656,6 +657,32 @@ public final class HttpCookie implements Cloneable { version = v; } + /** + * Returns {@code true} if this cookie contains the HttpOnly + * attribute. This means that the cookie should not be accessible to + * scripting engines, like javascript. + * + * @return {@code true} if this cookie should be considered http only. + * @see #setHttpOnly(boolean) + */ + public boolean isHttpOnly() + { + return httpOnly; + } + + /** + * Indicates whether the cookie should be considered HTTP Only. If set to + * {@code true} it means the cookie should not be accessible to scripting + * engines like javascript. + * + * @param httpOnly if {@code true} make the cookie HTTP only, i.e. + * only visible as part of an HTTP request. + * @see #isHttpOnly() + */ + public void setHttpOnly(boolean httpOnly) + { + this.httpOnly = httpOnly; + } /** * The utility method to check whether a host name is in a domain @@ -877,6 +904,7 @@ public final class HttpCookie implements Cloneable { || name.equalsIgnoreCase("Port") // rfc2965 only || name.equalsIgnoreCase("Secure") || name.equalsIgnoreCase("Version") + || name.equalsIgnoreCase("HttpOnly") || name.charAt(0) == '$') { return true; @@ -996,6 +1024,11 @@ public final class HttpCookie implements Cloneable { cookie.setSecure(true); } }); + assignors.put("httponly", new CookieAttributeAssignor(){ + public void assign(HttpCookie cookie, String attrName, String attrValue) { + cookie.setHttpOnly(true); + } + }); assignors.put("version", new CookieAttributeAssignor(){ public void assign(HttpCookie cookie, String attrName, String attrValue) { try { diff --git a/src/share/classes/java/net/Inet6Address.java b/src/share/classes/java/net/Inet6Address.java index 0778f5a02fef2433ea7117a6f0a51d87ff85b847..9441fed940597a6cfc957e28f06818fc27c885b0 100644 --- a/src/share/classes/java/net/Inet6Address.java +++ b/src/share/classes/java/net/Inet6Address.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 diff --git a/src/share/classes/java/net/NetworkInterface.java b/src/share/classes/java/net/NetworkInterface.java index 7852fa363cb744b677bb74eff4ee2fc63b753e3e..da9503d573b1f786c85a51b262791747a3bca069 100644 --- a/src/share/classes/java/net/NetworkInterface.java +++ b/src/share/classes/java/net/NetworkInterface.java @@ -25,7 +25,6 @@ package java.net; -import java.net.SocketException; import java.util.Enumeration; import java.util.NoSuchElementException; import sun.security.action.*; @@ -203,11 +202,17 @@ public final class NetworkInterface { } /** - * Get the index of this network interface. + * Returns the index of this network interface. The index is an integer greater + * or equal to zero, or {@code -1} for unknown. This is a system specific value + * and interfaces with the same name can have different indexes on different + * machines. * - * @return the index of this network interface + * @return the index of this network interface or {@code -1} if the index is + * unknown + * @see #getByIndex(int) + * @since 1.7 */ - int getIndex() { + public int getIndex() { return index; } @@ -249,11 +254,18 @@ public final class NetworkInterface { * Get a network interface given its index. * * @param index an integer, the index of the interface - * @return the NetworkInterface obtained from its index - * @exception SocketException if an I/O error occurs. + * @return the NetworkInterface obtained from its index, or {@code null} if + * there is no interface with such an index on the system + * @throws SocketException if an I/O error occurs. + * @throws IllegalArgumentException if index has a negative value + * @see #getIndex() + * @since 1.7 */ - native static NetworkInterface getByIndex(int index) - throws SocketException; + public static NetworkInterface getByIndex(int index) throws SocketException { + if (index < 0) + throw new IllegalArgumentException("Interface index can't be negative"); + return getByIndex0(index); + } /** * Convenience method to search for a network interface that @@ -325,6 +337,9 @@ public final class NetworkInterface { private native static NetworkInterface getByName0(String name) throws SocketException; + private native static NetworkInterface getByIndex0(int index) + throws SocketException; + private native static NetworkInterface getByInetAddress0(InetAddress addr) throws SocketException; diff --git a/src/solaris/classes/sun/awt/motif/X11SelectionHolder.java b/src/share/classes/java/net/ProtocolFamily.java similarity index 80% rename from src/solaris/classes/sun/awt/motif/X11SelectionHolder.java rename to src/share/classes/java/net/ProtocolFamily.java index 523efc32ae6b483f75d80a36b8f93fe19c1e86c6..b997c7bb0a69ab3fc96c2543148923a035c52ae5 100644 --- a/src/solaris/classes/sun/awt/motif/X11SelectionHolder.java +++ b/src/share/classes/java/net/ProtocolFamily.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1998 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,17 @@ * have any questions. */ -package sun.awt.motif; +package java.net; -interface X11SelectionHolder { +/** + * Represents a family of communication protocols. + * + * @since 1.7 + */ - // NOTE: This method may be called by privileged threads. - // DO NOT INVOKE CLIENT CODE ON THIS THREAD! - public void lostSelectionOwnership(); +public interface ProtocolFamily { + /** + * Returns the name of the protocol family. + */ + String name(); } diff --git a/src/share/classes/java/net/ServerSocket.java b/src/share/classes/java/net/ServerSocket.java index d28d874b2c088a263f5d3b9c0bea0747b1444142..983c737c3b7e21110d8d0305f405d841a09c9ac9 100644 --- a/src/share/classes/java/net/ServerSocket.java +++ b/src/share/classes/java/net/ServerSocket.java @@ -142,14 +142,18 @@ class ServerSocket implements java.io.Closeable { * as its argument to ensure the operation is allowed. * This could result in a SecurityException. * - *

The backlog argument must be a positive - * value greater than 0. If the value passed is equal or less - * than 0, then the default value will be assumed. + * The backlog argument is the requested 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. The value provided + * should be greater than 0. If it is less than or equal to + * 0, then an implementation specific default will be used. *

* * @param port the port number, or 0 to use a port * number that is automatically allocated. - * @param backlog the maximum length of the queue. + * @param backlog requested maximum length of the queue of incoming + * connections. * * @exception IOException if an I/O error occurs when opening the socket. * @exception SecurityException @@ -187,13 +191,17 @@ class ServerSocket implements java.io.Closeable { * as its argument to ensure the operation is allowed. * This could result in a SecurityException. * - *

The backlog argument must be a positive - * value greater than 0. If the value passed is equal or less - * than 0, then the default value will be assumed. + * The backlog argument is the requested 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. The value provided + * should be greater than 0. If it is less than or equal to + * 0, then an implementation specific default will be used. *

* @param port the port number, or 0 to use a port * number that is automatically allocated. - * @param backlog the listen backlog + * @param backlog requested maximum length of the queue of incoming + * connections. * @param bindAddr the local InetAddress the server will bind to * * @throws SecurityException if a security manager exists and @@ -321,11 +329,15 @@ class ServerSocket implements java.io.Closeable { * If the address is null, then the system will pick up * an ephemeral port and a valid local address to bind the socket. *

- * The backlog argument must be a positive - * value greater than 0. If the value passed is equal or less - * than 0, then the default value will be assumed. + * The backlog argument is the requested 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. The value provided + * should be greater than 0. If it is less than or equal to + * 0, then an implementation specific default will be used. * @param endpoint The IP address & port number to bind to. - * @param backlog The listen backlog length. + * @param backlog requested maximum length of the queue of + * incoming connections. * @throws IOException if the bind operation fails, or if the socket * is already bound. * @throws SecurityException if a SecurityManager is present and diff --git a/src/solaris/native/sun/awt/awt_MenuComponent.c b/src/share/classes/java/net/SocketOption.java similarity index 58% rename from src/solaris/native/sun/awt/awt_MenuComponent.c rename to src/share/classes/java/net/SocketOption.java index b63123f26e7f5dcf980c9d55fe4f88579a5d06d4..afc9714b5ab95f5c615820b12daa78209c959b02 100644 --- a/src/solaris/native/sun/awt/awt_MenuComponent.c +++ b/src/share/classes/java/net/SocketOption.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,26 +23,33 @@ * have any questions. */ -#ifdef HEADLESS - #error This file should not be included in headless library -#endif +package java.net; -#include "java_awt_MenuComponent.h" -#include "jni_util.h" - -#include "awt_MenuComponent.h" +/** + * 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 + */ -struct MenuComponentIDs menuComponentIDs; +public interface SocketOption { + /** + * Returns the name of the socket option. + */ + String name(); -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;"); + /** + * Returns the type of the socket option value. + */ + Class type(); } diff --git a/src/solaris/native/sun/awt/awt_XmDnD.h b/src/share/classes/java/net/StandardProtocolFamily.java similarity index 75% rename from src/solaris/native/sun/awt/awt_XmDnD.h rename to src/share/classes/java/net/StandardProtocolFamily.java index c2650e34086fe9702b2ffe39886b96cddc8fc45c..7c11b32f59fc61f741978eca32191a6cd1fa952b 100644 --- a/src/solaris/native/sun/awt/awt_XmDnD.h +++ b/src/share/classes/java/net/StandardProtocolFamily.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2001 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,19 +23,23 @@ * have any questions. */ -#include -#include -#include -#include +package java.net; /** + * Defines the standard family of communication protocols. * + * @since 1.7 */ -typedef struct DropSiteInfo { - Widget tlw; +public enum StandardProtocolFamily implements ProtocolFamily { - jobject component; - Boolean isComposite; - uint32_t dsCnt; -} DropSiteInfo; + /** + * Internet Protocol Version 4 (IPv4) + */ + INET, + + /** + * Internet Protocol Version 6 (IPv6) + */ + INET6 +} diff --git a/src/share/classes/java/net/StandardSocketOption.java b/src/share/classes/java/net/StandardSocketOption.java new file mode 100644 index 0000000000000000000000000000000000000000..405038cc1c21cd213e1565949d15fd2eecf73659 --- /dev/null +++ b/src/share/classes/java/net/StandardSocketOption.java @@ -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 --git a/src/share/classes/java/nio/Bits.java b/src/share/classes/java/nio/Bits.java index 603ee11bb2a00043d711e0f2c3a63094670ab8a3..8627103a5318ae14112161a89407ca0ee17fc2d2 100644 --- a/src/share/classes/java/nio/Bits.java +++ b/src/share/classes/java/nio/Bits.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -29,6 +29,8 @@ import java.security.AccessController; 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 @@ class Bits { // package-private // 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 @@ class Bits { // package-private } if (size <= maxMemory - reservedMemory) { reservedMemory += size; + usedMemory += cap; + count++; return; } } @@ -655,17 +661,71 @@ class Bits { // package-private 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 @@ class Bits { // package-private 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 --git a/src/share/classes/java/nio/BufferPoolMXBean.java b/src/share/classes/java/nio/BufferPoolMXBean.java new file mode 100644 index 0000000000000000000000000000000000000000..0a7fe303f241836b8f8b8c7618daa663f41692e3 --- /dev/null +++ b/src/share/classes/java/nio/BufferPoolMXBean.java @@ -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 --git a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java index 5761fd867a468c4ee6ad0f0f284323a8fff508e4..54deb4c8f3e0e8a8e59655a659c745ad9837d7f7 100644 --- a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java +++ b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2004 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 @@ -186,7 +186,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private // --- Methods to support CharSequence --- - public CharSequence subSequence(int start, int end) { + public CharBuffer subSequence(int start, int end) { int pos = position(); int lim = limit(); assert (pos <= lim); diff --git a/src/share/classes/java/nio/Direct-X-Buffer.java b/src/share/classes/java/nio/Direct-X-Buffer.java index 092ac0e83edd24b6995ba659ab3683313f2bff94..26b31956a31dcbf8003732567f3e4ec49d6ece86 100644 --- a/src/share/classes/java/nio/Direct-X-Buffer.java +++ b/src/share/classes/java/nio/Direct-X-Buffer.java @@ -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 @@ -47,6 +47,9 @@ class Direct$Type$Buffer$RW$$BO$ // 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 @@ class Direct$Type$Buffer$RW$$BO$ 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 @@ class Direct$Type$Buffer$RW$$BO$ } unsafe.freeMemory(address); address = 0; - Bits.unreserveMemory(capacity); + Bits.unreserveMemory(size, capacity); } } @@ -110,23 +115,25 @@ class Direct$Type$Buffer$RW$$BO$ 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 @@ class Direct$Type$Buffer$RW$$BO$ 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 @@ class Direct$Type$Buffer$RW$$BO$ 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); @@ -391,7 +402,7 @@ class Direct$Type$Buffer$RW$$BO$ // --- Methods to support CharSequence --- - public CharSequence subSequence(int start, int end) { + public CharBuffer subSequence(int start, int end) { int pos = position(); int lim = limit(); assert (pos <= lim); diff --git a/src/share/classes/java/nio/Heap-X-Buffer.java b/src/share/classes/java/nio/Heap-X-Buffer.java index 0c19ca5549e71d3e7b23508db1e5f3b11e7e789f..28f1ca8abe1710f4a40db21e07a5d086df84b8ac 100644 --- a/src/share/classes/java/nio/Heap-X-Buffer.java +++ b/src/share/classes/java/nio/Heap-X-Buffer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 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 @@ -566,7 +566,7 @@ class Heap$Type$Buffer$RW$ // --- Methods to support CharSequence --- - public CharSequence subSequence(int start, int end) { + public CharBuffer subSequence(int start, int end) { if ((start < 0) || (end > length()) || (start > end)) diff --git a/src/share/classes/java/nio/StringCharBuffer.java b/src/share/classes/java/nio/StringCharBuffer.java index 3f49ae1eb1227c2a8dfb1bb38cda3a2be35d53a6..648b1986fca36c0c5ff63246810567c76d0c0a2e 100644 --- a/src/share/classes/java/nio/StringCharBuffer.java +++ b/src/share/classes/java/nio/StringCharBuffer.java @@ -99,7 +99,7 @@ class StringCharBuffer // package-private return str.toString().substring(start + offset, end + offset); } - public final CharSequence subSequence(int start, int end) { + public final CharBuffer subSequence(int start, int end) { try { int pos = position(); return new StringCharBuffer(str, -1, diff --git a/src/share/classes/java/nio/X-Buffer.java b/src/share/classes/java/nio/X-Buffer.java index 99a7468fff8cd250b5a82a1fd174b2018053771d..9fc8185b646ef0387d26889e548ba1bf99cab1f7 100644 --- a/src/share/classes/java/nio/X-Buffer.java +++ b/src/share/classes/java/nio/X-Buffer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -1239,13 +1239,13 @@ public abstract class $Type$Buffer * smaller than start and no larger than * remaining() * - * @return The new character sequence + * @return The new character buffer * * @throws IndexOutOfBoundsException * If the preconditions on start and end * do not hold */ - public abstract CharSequence subSequence(int start, int end); + public abstract CharBuffer subSequence(int start, int end); // --- Methods to support Appendable --- diff --git a/src/share/classes/java/nio/channels/DatagramChannel.java b/src/share/classes/java/nio/channels/DatagramChannel.java index 744495c55892907e46665fbeef8f3b2f38941f7e..b8697fa1dc69f22c32c09f8bc4ded6a0a19f1a12 100644 --- a/src/share/classes/java/nio/channels/DatagramChannel.java +++ b/src/share/classes/java/nio/channels/DatagramChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 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 @@ -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 @@ import java.nio.channels.spi.*; * 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 @@ import java.nio.channels.spi.*; public abstract class DatagramChannel extends AbstractSelectableChannel - implements ByteChannel, ScatteringByteChannel, GatheringByteChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel { /** @@ -88,7 +127,13 @@ public abstract class DatagramChannel * 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 * @@ -99,6 +144,39 @@ public abstract class DatagramChannel return SelectorProvider.provider().openDatagramChannel(); } + /** + * 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. @@ -117,6 +195,32 @@ public abstract class DatagramChannel // -- 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. * @@ -128,10 +232,10 @@ public abstract class DatagramChannel 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(); @@ -206,6 +310,19 @@ public abstract class DatagramChannel */ 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. * diff --git a/src/share/classes/java/nio/channels/MembershipKey.java b/src/share/classes/java/nio/channels/MembershipKey.java new file mode 100644 index 0000000000000000000000000000000000000000..0d2fc52bc4de195ca11c30016a1da39b807015df --- /dev/null +++ b/src/share/classes/java/nio/channels/MembershipKey.java @@ -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 --git a/src/share/classes/java/nio/channels/MulticastChannel.java b/src/share/classes/java/nio/channels/MulticastChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..440dd2a8b85a6eaa76eb2b4e7b754cdff1d2c01a --- /dev/null +++ b/src/share/classes/java/nio/channels/MulticastChannel.java @@ -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 --git a/src/share/classes/java/nio/channels/NetworkChannel.java b/src/share/classes/java/nio/channels/NetworkChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..fae642fcbdbe5263af754c847757296e39e0d417 --- /dev/null +++ b/src/share/classes/java/nio/channels/NetworkChannel.java @@ -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 --git a/src/share/classes/java/nio/channels/SelectionKey.java b/src/share/classes/java/nio/channels/SelectionKey.java index 00fd36f463a894a0c29bdf440d801de12f1e8129..032f240b912e23e8c5ab70cccda9dd07b9005069 100644 --- a/src/share/classes/java/nio/channels/SelectionKey.java +++ b/src/share/classes/java/nio/channels/SelectionKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 diff --git a/src/share/classes/java/nio/channels/ServerSocketChannel.java b/src/share/classes/java/nio/channels/ServerSocketChannel.java index 0ffed003a6c7ae0103e138586c35d08b7529b7b7..84ea062c9f08b8cb2d2f2c60882f96ae193fc18d 100644 --- a/src/share/classes/java/nio/channels/ServerSocketChannel.java +++ b/src/share/classes/java/nio/channels/ServerSocketChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 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 @@ -27,33 +27,44 @@ package java.nio.channels; 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. 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. + * 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. + * + *

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 @@ import java.nio.channels.spi.*; public abstract class ServerSocketChannel extends AbstractSelectableChannel + implements NetworkChannel { /** @@ -109,6 +121,89 @@ public abstract class ServerSocketChannel // -- 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. * diff --git a/src/share/classes/java/nio/channels/SocketChannel.java b/src/share/classes/java/nio/channels/SocketChannel.java index 8266994227b58869a1a695dd7ff2af5ce04315c1..2e96bd2e4ceafe3f8f72e76163f6b3d1ad2b5fd7 100644 --- a/src/share/classes/java/nio/channels/SocketChannel.java +++ b/src/share/classes/java/nio/channels/SocketChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 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 @@ -27,24 +27,17 @@ package java.nio.channels; 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 @@ import java.nio.channels.spi.*; * 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 @@ import java.nio.channels.spi.*; * 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 @@ import java.nio.channels.spi.*; * 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 @@ import java.nio.channels.spi.*; public abstract class SocketChannel extends AbstractSelectableChannel - implements ByteChannel, ScatteringByteChannel, GatheringByteChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel { /** @@ -191,6 +210,73 @@ public abstract class SocketChannel // -- 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. * @@ -202,10 +288,10 @@ public abstract class SocketChannel 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 class SocketChannel */ 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 --git a/src/share/classes/java/nio/channels/exceptions b/src/share/classes/java/nio/channels/exceptions index ae4d4c0d9603a055c0f544848dc4886db30f0fa4..04cfbe03e29a89d57b2ff375a57bfce1744e7212 100644 --- a/src/share/classes/java/nio/channels/exceptions +++ b/src/share/classes/java/nio/channels/exceptions @@ -1,5 +1,5 @@ # -# Copyright 2000-2007 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 @@ -146,3 +146,14 @@ gen OverlappingFileLockException " * 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 --git a/src/share/classes/java/nio/channels/package-info.java b/src/share/classes/java/nio/channels/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..e8c2a929d4b9f4273cff66a59cd8d0e2728fa0e7 --- /dev/null +++ b/src/share/classes/java/nio/channels/package-info.java @@ -0,0 +1,231 @@ +/* + * 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. + */ + +/** + * 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 --git a/src/share/classes/java/nio/channels/package.html b/src/share/classes/java/nio/channels/package.html deleted file mode 100644 index 151378f78fd1d20bd794a2d2f3f683c0ea838818..0000000000000000000000000000000000000000 --- a/src/share/classes/java/nio/channels/package.html +++ /dev/null @@ -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 --git a/src/share/classes/java/nio/channels/spi/AbstractSelector.java b/src/share/classes/java/nio/channels/spi/AbstractSelector.java index 019dd6ef49de7c1f21786717867eb8c0e011cc3f..060d2d3c50e7bb13ca4c626fbd6c795f4ee054c9 100644 --- a/src/share/classes/java/nio/channels/spi/AbstractSelector.java +++ b/src/share/classes/java/nio/channels/spi/AbstractSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2004 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 diff --git a/src/share/classes/java/nio/channels/spi/SelectorProvider.java b/src/share/classes/java/nio/channels/spi/SelectorProvider.java index 9a8a3cc707c87a4854fc3a27eb125d9c03d0075f..dc61c9c270abc391044eb95504b3c80d5db517a6 100644 --- a/src/share/classes/java/nio/channels/spi/SelectorProvider.java +++ b/src/share/classes/java/nio/channels/spi/SelectorProvider.java @@ -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 @@ public abstract class SelectorProvider { 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 --git a/src/share/classes/java/nio/charset/Charset-X-Coder.java b/src/share/classes/java/nio/charset/Charset-X-Coder.java index 1593be1da3de0d9b57df2155df826ee0e30fbd0e..6b4967ca082cf21192114fab16d9768479ae786c 100644 --- a/src/share/classes/java/nio/charset/Charset-X-Coder.java +++ b/src/share/classes/java/nio/charset/Charset-X-Coder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 diff --git a/src/share/classes/java/nio/charset/Charset.java b/src/share/classes/java/nio/charset/Charset.java index 4908c77d1dbda8a59f7357469e43f9332a184f49..804d0091c483129568e1b727575ddb9ed634ca63 100644 --- a/src/share/classes/java/nio/charset/Charset.java +++ b/src/share/classes/java/nio/charset/Charset.java @@ -85,6 +85,9 @@ import sun.security.action.GetPropertyAction; *
  • The dash character '-' * ('\u002d'HYPHEN-MINUS), * + *
  • The plus character '+' + * ('\u002b'PLUS SIGN), + * *
  • The period character '.' * ('\u002e'FULL STOP), * @@ -307,6 +310,7 @@ public abstract class Charset 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 --git a/src/share/classes/java/nio/charset/CoderResult.java b/src/share/classes/java/nio/charset/CoderResult.java index 8f3c0befaccc6fe6e81876af1a080f4093062d26..123214941ceefe19bbe0aacc7d1d5c42d1fa18e5 100644 --- a/src/share/classes/java/nio/charset/CoderResult.java +++ b/src/share/classes/java/nio/charset/CoderResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2002 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 diff --git a/src/share/classes/java/security/cert/CertPathValidatorException.java b/src/share/classes/java/security/cert/CertPathValidatorException.java index 5fd70c24a8795dbde7c230c71374188ff62919f2..8a04aeff5f307238938aba619719c95b54226098 100644 --- a/src/share/classes/java/security/cert/CertPathValidatorException.java +++ b/src/share/classes/java/security/cert/CertPathValidatorException.java @@ -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 @@ -25,6 +25,9 @@ package java.security.cert; +import java.io.InvalidObjectException; +import java.io.IOException; +import java.io.ObjectInputStream; import java.security.GeneralSecurityException; /** @@ -36,10 +39,11 @@ import java.security.GeneralSecurityException; * if any, that caused this exception to be thrown. *

    * A CertPathValidatorException may also include the - * certification path that was being validated when the exception was thrown - * and the index of the certificate in the certification path that caused the - * exception to be thrown. Use the {@link #getCertPath getCertPath} and - * {@link #getIndex getIndex} methods to retrieve this information. + * certification path that was being validated when the exception was thrown, + * the index of the certificate in the certification path that caused the + * exception to be thrown, and the reason that caused the failure. Use the + * {@link #getCertPath getCertPath}, {@link #getIndex getIndex}, and + * {@link #getReason getReason} methods to retrieve this information. * *

    * Concurrent Access @@ -71,12 +75,17 @@ public class CertPathValidatorException extends GeneralSecurityException { */ private CertPath certPath; + /** + * @serial the reason the validation failed + */ + private Reason reason = BasicReason.UNSPECIFIED; + /** * Creates a CertPathValidatorException with * no detail message. */ public CertPathValidatorException() { - super(); + this(null, null); } /** @@ -87,7 +96,7 @@ public class CertPathValidatorException extends GeneralSecurityException { * @param msg the detail message */ public CertPathValidatorException(String msg) { - super(msg); + this(msg, null); } /** @@ -104,7 +113,7 @@ public class CertPathValidatorException extends GeneralSecurityException { * permitted, and indicates that the cause is nonexistent or unknown.) */ public CertPathValidatorException(Throwable cause) { - super(cause); + this(null, cause); } /** @@ -117,7 +126,7 @@ public class CertPathValidatorException extends GeneralSecurityException { * permitted, and indicates that the cause is nonexistent or unknown.) */ public CertPathValidatorException(String msg, Throwable cause) { - super(msg, cause); + this(msg, cause, null, -1); } /** @@ -139,6 +148,32 @@ public class CertPathValidatorException extends GeneralSecurityException { */ public CertPathValidatorException(String msg, Throwable cause, CertPath certPath, int index) { + this(msg, cause, certPath, index, BasicReason.UNSPECIFIED); + } + + /** + * Creates a CertPathValidatorException with the specified + * detail message, cause, certification path, index, and reason. + * + * @param msg the detail message (or null if none) + * @param cause the cause (or null if none) + * @param certPath the certification path that was in the process of + * being validated when the error was encountered + * @param index the index of the certificate in the certification path + * that caused the error (or -1 if not applicable). Note that + * the list of certificates in a CertPath is zero based. + * @param reason the reason the validation failed + * @throws IndexOutOfBoundsException if the index is out of range + * (index < -1 || (certPath != null && index >= + * certPath.getCertificates().size()) + * @throws IllegalArgumentException if certPath is + * null and index is not -1 + * @throws NullPointerException if reason is null + * + * @since 1.7 + */ + public CertPathValidatorException(String msg, Throwable cause, + CertPath certPath, int index, Reason reason) { super(msg, cause); if (certPath == null && index != -1) { throw new IllegalArgumentException(); @@ -147,8 +182,12 @@ public class CertPathValidatorException extends GeneralSecurityException { (certPath != null && index >= certPath.getCertificates().size())) { throw new IndexOutOfBoundsException(); } + if (reason == null) { + throw new NullPointerException("reason can't be null"); + } this.certPath = certPath; this.index = index; + this.reason = reason; } /** @@ -174,4 +213,79 @@ public class CertPathValidatorException extends GeneralSecurityException { return this.index; } + /** + * Returns the reason that the validation failed. The reason is + * associated with the index of the certificate returned by + * {@link getIndex}. + * + * @return the reason that the validation failed, or + * BasicReason.UNSPECIFIED if a reason has not been + * specified + * + * @since 1.7 + */ + public Reason getReason() { + return this.reason; + } + + private void readObject(ObjectInputStream stream) + throws ClassNotFoundException, IOException { + stream.defaultReadObject(); + if (reason == null) { + reason = BasicReason.UNSPECIFIED; + } + if (certPath == null && index != -1) { + throw new InvalidObjectException("certpath is null and index != -1"); + } + if (index < -1 || + (certPath != null && index >= certPath.getCertificates().size())) { + throw new InvalidObjectException("index out of range"); + } + } + + /** + * The reason the validation algorithm failed. + * + * @since 1.7 + */ + public static interface Reason extends java.io.Serializable { } + + + /** + * The BasicReason enumerates the potential reasons that a certification + * path of any type may be invalid. + * + * @since 1.7 + */ + public static enum BasicReason implements Reason { + /** + * Unspecified reason. + */ + UNSPECIFIED, + + /** + * The certificate is expired. + */ + EXPIRED, + + /** + * The certificate is not yet valid. + */ + NOT_YET_VALID, + + /** + * The certificate is revoked. + */ + REVOKED, + + /** + * The revocation status of the certificate could not be determined. + */ + UNDETERMINED_REVOCATION_STATUS, + + /** + * The signature is invalid. + */ + INVALID_SIGNATURE + } } diff --git a/src/share/classes/java/security/cert/PKIXReason.java b/src/share/classes/java/security/cert/PKIXReason.java new file mode 100644 index 0000000000000000000000000000000000000000..ed798d334f2f83340f9a643774c29e9fa00a351a --- /dev/null +++ b/src/share/classes/java/security/cert/PKIXReason.java @@ -0,0 +1,77 @@ +/* + * 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 java.security.cert; + +/** + * The PKIXReason enumerates the potential PKIX-specific reasons + * that an X.509 certification path may be invalid according to the PKIX + * (RFC 3280) standard. These reasons are in addition to those of the + * CertPathValidatorException.BasicReason enumeration. + * + * @since 1.7 + */ +public enum PKIXReason implements CertPathValidatorException.Reason { + /** + * The certificate does not chain correctly. + */ + NAME_CHAINING, + + /** + * The certificate's key usage is invalid. + */ + INVALID_KEY_USAGE, + + /** + * The policy constraints have been violated. + */ + INVALID_POLICY, + + /** + * No acceptable trust anchor found. + */ + NO_TRUST_ANCHOR, + + /** + * The certificate contains one or more unrecognized critical + * extensions. + */ + UNRECOGNIZED_CRIT_EXT, + + /** + * The certificate is not a CA certificate. + */ + NOT_CA_CERT, + + /** + * The path length constraint has been violated. + */ + PATH_TOO_LONG, + + /** + * The name constraints have been violated. + */ + INVALID_NAME +} diff --git a/src/share/classes/java/util/CurrencyData.properties b/src/share/classes/java/util/CurrencyData.properties index 7b2bd36ba19bbbd49dc00066385b7e6fefcdd95e..15c45302e965da766b3547550d435e4ad78d1476 100644 --- a/src/share/classes/java/util/CurrencyData.properties +++ b/src/share/classes/java/util/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright 2000-2007 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 diff --git a/src/share/classes/java/util/EnumSet.java b/src/share/classes/java/util/EnumSet.java index d5c8d23dfa3cb22332fb716fa1addbb815a0f493..c6c013d5202d0849385b6986eaa080df85ea80d2 100644 --- a/src/share/classes/java/util/EnumSet.java +++ b/src/share/classes/java/util/EnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -432,4 +432,11 @@ public abstract class EnumSet> extends AbstractSet Object writeReplace() { return new SerializationProxy(this); } + + // readObject method for the serialization proxy pattern + // See Effective Java, Second Ed., Item 78. + private void readObject(java.io.ObjectInputStream stream) + throws java.io.InvalidObjectException { + throw new java.io.InvalidObjectException("Proxy required"); + } } diff --git a/src/share/classes/java/util/Timer.java b/src/share/classes/java/util/Timer.java index 224420972718c3abb74e9f13e49282d1d3a5e294..2387c478e504bad08483f803bdfbd980044babf2 100644 --- a/src/share/classes/java/util/Timer.java +++ b/src/share/classes/java/util/Timer.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 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,6 +25,7 @@ package java.util; import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; /** * A facility for threads to schedule tasks for future execution in a @@ -92,12 +93,12 @@ public class Timer { * and the timer thread consumes, executing timer tasks as appropriate, * and removing them from the queue when they're obsolete. */ - private TaskQueue queue = new TaskQueue(); + private final TaskQueue queue = new TaskQueue(); /** * The timer thread. */ - private TimerThread thread = new TimerThread(queue); + private final TimerThread thread = new TimerThread(queue); /** * This object causes the timer's task execution thread to exit @@ -106,7 +107,7 @@ public class Timer { * Timer as such a finalizer would be susceptible to a subclass's * finalizer forgetting to call it. */ - private Object threadReaper = new Object() { + private final Object threadReaper = new Object() { protected void finalize() throws Throwable { synchronized(queue) { thread.newTasksMayBeScheduled = false; @@ -116,12 +117,11 @@ public class Timer { }; /** - * This ID is used to generate thread names. (It could be replaced - * by an AtomicInteger as soon as they become available.) + * This ID is used to generate thread names. */ - private static int nextSerialNumber = 0; - private static synchronized int serialNumber() { - return nextSerialNumber++; + private final static AtomicInteger nextSerialNumber = new AtomicInteger(0); + private static int serialNumber() { + return nextSerialNumber.getAndIncrement(); } /** @@ -387,6 +387,11 @@ public class Timer { if (time < 0) throw new IllegalArgumentException("Illegal execution time."); + // Constrain value of period sufficiently to prevent numeric + // overflow while still being effectively infinitely large. + if (Math.abs(period) > (Long.MAX_VALUE >> 1)) + period >>= 1; + synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); diff --git a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index dc7fe113f2aa7a59adb6a5114da5d8ac4c86e22c..67a8b32205ef7f15ccc5a5e9b798ef757df7c7f3 100644 --- a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -223,8 +223,7 @@ public class ScheduledThreadPoolExecutor } public long getDelay(TimeUnit unit) { - long d = unit.convert(time - now(), TimeUnit.NANOSECONDS); - return d; + return unit.convert(time - now(), TimeUnit.NANOSECONDS); } public int compareTo(Delayed other) { @@ -264,7 +263,7 @@ public class ScheduledThreadPoolExecutor if (p > 0) time += p; else - time = now() - p; + time = triggerTime(-p); } public boolean cancel(boolean mayInterruptIfRunning) { @@ -472,6 +471,38 @@ public class ScheduledThreadPoolExecutor new DelayedWorkQueue(), threadFactory, handler); } + /** + * Returns the trigger time of a delayed action. + */ + private long triggerTime(long delay, TimeUnit unit) { + return triggerTime(unit.toNanos((delay < 0) ? 0 : delay)); + } + + /** + * Returns the trigger time of a delayed action. + */ + long triggerTime(long delay) { + return now() + + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); + } + + /** + * Constrains the values of all delays in the queue to be within + * Long.MAX_VALUE of each other, to avoid overflow in compareTo. + * This may occur if a task is eligible to be dequeued, but has + * not yet been, while some other task is added with a delay of + * Long.MAX_VALUE. + */ + private long overflowFree(long delay) { + Delayed head = (Delayed) super.getQueue().peek(); + if (head != null) { + long headDelay = head.getDelay(TimeUnit.NANOSECONDS); + if (headDelay < 0 && (delay - headDelay < 0)) + delay = Long.MAX_VALUE + headDelay; + } + return delay; + } + /** * @throws RejectedExecutionException {@inheritDoc} * @throws NullPointerException {@inheritDoc} @@ -481,10 +512,9 @@ public class ScheduledThreadPoolExecutor TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); - if (delay < 0) delay = 0; - long triggerTime = now() + unit.toNanos(delay); RunnableScheduledFuture t = decorateTask(command, - new ScheduledFutureTask(command, null, triggerTime)); + new ScheduledFutureTask(command, null, + triggerTime(delay, unit))); delayedExecute(t); return t; } @@ -498,10 +528,9 @@ public class ScheduledThreadPoolExecutor TimeUnit unit) { if (callable == null || unit == null) throw new NullPointerException(); - if (delay < 0) delay = 0; - long triggerTime = now() + unit.toNanos(delay); RunnableScheduledFuture t = decorateTask(callable, - new ScheduledFutureTask(callable, triggerTime)); + new ScheduledFutureTask(callable, + triggerTime(delay, unit))); delayedExecute(t); return t; } @@ -519,12 +548,10 @@ public class ScheduledThreadPoolExecutor throw new NullPointerException(); if (period <= 0) throw new IllegalArgumentException(); - if (initialDelay < 0) initialDelay = 0; - long triggerTime = now() + unit.toNanos(initialDelay); ScheduledFutureTask sft = new ScheduledFutureTask(command, null, - triggerTime, + triggerTime(initialDelay, unit), unit.toNanos(period)); RunnableScheduledFuture t = decorateTask(command, sft); sft.outerTask = t; @@ -545,12 +572,10 @@ public class ScheduledThreadPoolExecutor throw new NullPointerException(); if (delay <= 0) throw new IllegalArgumentException(); - if (initialDelay < 0) initialDelay = 0; - long triggerTime = now() + unit.toNanos(initialDelay); ScheduledFutureTask sft = new ScheduledFutureTask(command, null, - triggerTime, + triggerTime(initialDelay, unit), unit.toNanos(-delay)); RunnableScheduledFuture t = decorateTask(command, sft); sft.outerTask = t; diff --git a/src/share/classes/java/util/logging/Logging.java b/src/share/classes/java/util/logging/Logging.java index 72468699ead06d487d58f33903f52d4dbe3d45c7..d99782407a56a934be487c92d19b139b5f2c8cbe 100644 --- a/src/share/classes/java/util/logging/Logging.java +++ b/src/share/classes/java/util/logging/Logging.java @@ -118,6 +118,6 @@ class Logging implements LoggingMXBean { } public ObjectName getObjectName() { - return com.sun.jmx.mbeanserver.Util.newObjectName(LogManager.LOGGING_MXBEAN_NAME); + return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME); } } diff --git a/src/share/classes/java/util/zip/Inflater.java b/src/share/classes/java/util/zip/Inflater.java index bc0bdf55f3ec830db4f2c35366b36ebd4d8f4d7c..68c8d62339702138338abeda1420f67a70127279 100644 --- a/src/share/classes/java/util/zip/Inflater.java +++ b/src/share/classes/java/util/zip/Inflater.java @@ -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 @@ package java.util.zip; 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 @@ class Inflater { public synchronized void reset() { ensureOpen(); reset(strm); + buf = defaultBuf; finished = false; needDict = false; off = len = 0; diff --git a/src/share/classes/java/util/zip/ZipFile.java b/src/share/classes/java/util/zip/ZipFile.java index 8ad177fdc92999514a8e013e7b37fb350991ac1f..37e92ddecb77084c3bb64d75b70f184f403a0e4c 100644 --- a/src/share/classes/java/util/zip/ZipFile.java +++ b/src/share/classes/java/util/zip/ZipFile.java @@ -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 @@ class ZipFile implements ZipConstants { 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 @@ class ZipFile implements ZipConstants { */ private void releaseInflater(Inflater inf) { synchronized (inflaters) { + inf.reset(); inflaters.add(inf); } } diff --git a/src/share/classes/java/util/zip/ZipOutputStream.java b/src/share/classes/java/util/zip/ZipOutputStream.java index 65394268297bec06604b818b07b4303db7dfe18d..797a37392fe4e73ac57a3d8ee14a8887ee11b6b7 100644 --- a/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/share/classes/java/util/zip/ZipOutputStream.java @@ -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 @@ -317,9 +317,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { if (current != null) { closeEntry(); } - if (xentries.size() < 1) { - throw new ZipException("ZIP file must have at least one entry"); - } // write central directory long off = written; for (XEntry xentry : xentries) diff --git a/src/share/classes/javax/management/Description.java b/src/share/classes/javax/management/Description.java index a0bf96d9b1d4ad98a3360faff27bca76247c364d..3232054a8c9ab4d7b94817f112383bfbc0db4807 100644 --- a/src/share/classes/javax/management/Description.java +++ b/src/share/classes/javax/management/Description.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/Descriptor.java b/src/share/classes/javax/management/Descriptor.java index 9aa992486a04d0773fca329c0ad7f39fc3541780..70c17f2eedb51237d67dd5e002b583ea245047d2 100644 --- a/src/share/classes/javax/management/Descriptor.java +++ b/src/share/classes/javax/management/Descriptor.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Portions 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 diff --git a/src/share/classes/javax/management/DescriptorFields.java b/src/share/classes/javax/management/DescriptorFields.java index 95a4b3a6df1296f659f11a20fb0105f11d6b2a87..126425326000f716aaaa03f2ec94c8298c6e86a9 100644 --- a/src/share/classes/javax/management/DescriptorFields.java +++ b/src/share/classes/javax/management/DescriptorFields.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/DescriptorKey.java b/src/share/classes/javax/management/DescriptorKey.java index 9f9194905129cd81b54fae590c5aa20099af2874..7646862ce6a67522d08ec955873b523f19268c2c 100644 --- a/src/share/classes/javax/management/DescriptorKey.java +++ b/src/share/classes/javax/management/DescriptorKey.java @@ -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 diff --git a/src/share/classes/javax/management/DynamicWrapperMBean.java b/src/share/classes/javax/management/DynamicWrapperMBean.java index 4a67a96795a7d1104dc98f0a47540d99543662ed..45d2f17cf9615ca6eeb58175e9699b3f4ee7275f 100644 --- a/src/share/classes/javax/management/DynamicWrapperMBean.java +++ b/src/share/classes/javax/management/DynamicWrapperMBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/src/share/classes/javax/management/ImmutableDescriptor.java b/src/share/classes/javax/management/ImmutableDescriptor.java index cdfe459d0e76b599df77b735d121e57afcd0ac43..6a3bdc576b9f8ba9d351a9032f218cb7fa527488 100644 --- a/src/share/classes/javax/management/ImmutableDescriptor.java +++ b/src/share/classes/javax/management/ImmutableDescriptor.java @@ -128,13 +128,13 @@ public class ImmutableDescriptor implements Descriptor { * @throws InvalidObjectException if the read object has invalid fields. */ private Object readResolve() throws InvalidObjectException { - if (names.length == 0 && getClass() == ImmutableDescriptor.class) - return EMPTY_DESCRIPTOR; boolean bad = false; if (names == null || values == null || names.length != values.length) bad = true; if (!bad) { + if (names.length == 0 && getClass() == ImmutableDescriptor.class) + return EMPTY_DESCRIPTOR; final Comparator compare = String.CASE_INSENSITIVE_ORDER; String lastName = ""; // also catches illegal null name for (int i = 0; i < names.length; i++) { diff --git a/src/share/classes/javax/management/Impact.java b/src/share/classes/javax/management/Impact.java index 9416df6fac877b588c0c540791880b091719e9c9..a922e20ae3724cbcb22128be7370e35143bfb4a7 100644 --- a/src/share/classes/javax/management/Impact.java +++ b/src/share/classes/javax/management/Impact.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/InstanceNotFoundException.java b/src/share/classes/javax/management/InstanceNotFoundException.java index f572d614d0030319fa9ae22f83387bb038a08f5e..0b992d344f811673f957526e01e92e90f31a67bd 100644 --- a/src/share/classes/javax/management/InstanceNotFoundException.java +++ b/src/share/classes/javax/management/InstanceNotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2003 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 @@ -51,4 +51,16 @@ public class InstanceNotFoundException extends OperationsException { 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(String.valueOf(name)); + } } diff --git a/src/share/classes/javax/management/MBean.java b/src/share/classes/javax/management/MBean.java index 6837740334cb0f063761a1929e65974e5bd3e163..4b609c3da701dc0836991cb50934b6082e93bb86 100644 --- a/src/share/classes/javax/management/MBean.java +++ b/src/share/classes/javax/management/MBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/MBeanOperationInfo.java b/src/share/classes/javax/management/MBeanOperationInfo.java index 5863e96ef39991df8e101424b3e25b1fe4454575..e3c26df5265a3cf69b34c08b9720e1c9c117c8cf 100644 --- a/src/share/classes/javax/management/MBeanOperationInfo.java +++ b/src/share/classes/javax/management/MBeanOperationInfo.java @@ -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 diff --git a/src/share/classes/javax/management/MBeanPermission.java b/src/share/classes/javax/management/MBeanPermission.java index 762f5defc7c1bbd53746f05b3cf87a7272e249a7..fe328c2dae87e2b3a3ba208b0cd3c77e441d1771 100644 --- a/src/share/classes/javax/management/MBeanPermission.java +++ b/src/share/classes/javax/management/MBeanPermission.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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,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 @@ import java.security.Permission; * 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 @@ import java.security.Permission; * *

      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 @@ import java.security.Permission; * 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 @@ import java.security.Permission; *

    * *

    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 @@ import java.security.Permission; * ]. 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 @@ -246,6 +267,13 @@ public class MBeanPermission extends Permission { */ 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. */ @@ -283,6 +311,13 @@ public class MBeanPermission extends Permission { 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 @@ public class MBeanPermission extends Permission { // 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 @@ public class MBeanPermission extends Permission { } 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 @@ public class MBeanPermission extends Permission { 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 @@ public class MBeanPermission extends Permission { * 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 @@ public class MBeanPermission extends Permission { 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 @@ public class MBeanPermission extends Permission { * 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 @@ public class MBeanPermission extends Permission { String member, ObjectName objectName, String actions) { + this("*",className,member,objectName,actions); + } + + /** + *

    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(className, member, objectName)); - initName(className, member, objectName); + 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 @@ public class MBeanPermission extends Permission { * *
  • 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 @@ public class MBeanPermission extends Permission { * * * + *

    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 @@ public class MBeanPermission extends Permission { // 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 @@ public class MBeanPermission extends Permission { 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 --git a/src/share/classes/javax/management/MBeanRegistration.java b/src/share/classes/javax/management/MBeanRegistration.java index 1ba1c0d827fcde2d04ccc1c1e0de2ece850a0e23..723045acc936b1d6d9de58ccaa596a7da3ec2970 100644 --- a/src/share/classes/javax/management/MBeanRegistration.java +++ b/src/share/classes/javax/management/MBeanRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 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 @@ -158,7 +158,19 @@ public interface MBeanRegistration { /** * Allows the MBean to perform any operations needed after having been * registered in the MBean server or after the registration has failed. - * + *

    If the implementation of this method throws a {@link RuntimeException} + * or an {@link Error}, the MBean Server will rethrow those inside + * a {@link RuntimeMBeanException} or {@link RuntimeErrorException}, + * respectively. However, throwing an exception in {@code postRegister} + * will not change the state of the MBean: + * if the MBean was already registered ({@code registrationDone} is + * {@code true}), the MBean will remain registered.

    + *

    This might be confusing for the code calling {@code createMBean()} + * or {@code registerMBean()}, as such code might assume that MBean + * registration has failed when such an exception is raised. + * Therefore it is recommended that implementations of + * {@code postRegister} do not throw Runtime Exceptions or Errors if it + * can be avoided.

    * @param registrationDone Indicates whether or not the MBean has * been successfully registered in the MBean server. The value * false means that the registration phase has failed. @@ -178,6 +190,17 @@ public interface MBeanRegistration { /** * Allows the MBean to perform any operations needed after having been * unregistered in the MBean server. + *

    If the implementation of this method throws a {@link RuntimeException} + * or an {@link Error}, the MBean Server will rethrow those inside + * a {@link RuntimeMBeanException} or {@link RuntimeErrorException}, + * respectively. However, throwing an excepption in {@code postDeregister} + * will not change the state of the MBean: + * the MBean was already successfully deregistered and will remain so.

    + *

    This might be confusing for the code calling + * {@code unregisterMBean()}, as it might assume that MBean deregistration + * has failed. Therefore it is recommended that implementations of + * {@code postDeregister} do not throw Runtime Exceptions or Errors if it + * can be avoided.

    */ public void postDeregister(); diff --git a/src/share/classes/javax/management/MBeanServer.java b/src/share/classes/javax/management/MBeanServer.java index f0d4d16c46f3f64cb2b724ba8ab17ef2504a272f..90d42d2df6c2d2b2799b5a65c67e00685288d3f1 100644 --- a/src/share/classes/javax/management/MBeanServer.java +++ b/src/share/classes/javax/management/MBeanServer.java @@ -42,7 +42,7 @@ import javax.management.loading.ClassLoaderRepository; * *

    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 @@ -50,8 +50,8 @@ import javax.management.loading.ClassLoaderRepository; * server. A Java object cannot be registered in the MBean server * unless it is a JMX compliant MBean.

    * - *

    When an MBean is registered or unregistered in the MBean server - * a {@link javax.management.MBeanServerNotification + *

    When an MBean is registered or unregistered in the + * MBean server a {@link javax.management.MBeanServerNotification * MBeanServerNotification} Notification is emitted. To register an * object as listener to MBeanServerNotifications you should call the * MBean server method {@link #addNotificationListener @@ -62,8 +62,12 @@ import javax.management.loading.ClassLoaderRepository; * 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 @@ import javax.management.loading.ClassLoaderRepository; * *

    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 @@ import javax.management.loading.ClassLoaderRepository; * *
  • 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 @@ import javax.management.loading.ClassLoaderRepository; * *

  • 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 @@ import javax.management.loading.ClassLoaderRepository; * *

  • 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 @@ import javax.management.loading.ClassLoaderRepository; * *

  • 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 @@ import javax.management.loading.ClassLoaderRepository; * *

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

    * * * @@ -262,6 +293,10 @@ public interface MBeanServer extends MBeanServerConnection { * {@inheritDoc} *

    If this method successfully creates an MBean, a notification * is sent as described above.

    + * + * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, @@ -272,6 +307,10 @@ public interface MBeanServer extends MBeanServerConnection { * {@inheritDoc} *

    If this method successfully creates an MBean, a notification * is sent as described above.

    + * + * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) @@ -283,6 +322,10 @@ public interface MBeanServer extends MBeanServerConnection { * {@inheritDoc} *

    If this method successfully creates an MBean, a notification * 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[]) @@ -294,6 +337,10 @@ public interface MBeanServer extends MBeanServerConnection { * {@inheritDoc} *

    If this method successfully creates an MBean, a notification * 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[], @@ -328,11 +375,30 @@ public interface MBeanServer extends MBeanServerConnection { * preRegister (MBeanRegistration * interface) method of the MBean has thrown an exception. The * MBean will not be registered. + * @exception RuntimeMBeanException If the postRegister + * (MBeanRegistration interface) method of the MBean throws a + * RuntimeException, the registerMBean method will + * throw a RuntimeMBeanException, although the MBean + * registration succeeded. In such a case, the MBean will be actually + * registered even though the registerMBean 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 registerMBean method will + * throw a RuntimeErrorException, although the MBean + * registration succeeded. In such a case, the MBean will be actually + * registered even though the registerMBean method + * threw an exception. Note that RuntimeErrorException can + * also be thrown by preRegister, in which case 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. + * @see javax.management.MBeanRegistration */ public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException, MBeanRegistrationException, @@ -343,6 +409,8 @@ public interface MBeanServer extends MBeanServerConnection { * *

    If this method successfully unregisters an MBean, a notification * is sent as described above.

    + * + * @throws RuntimeOperationsException {@inheritDoc} */ public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException; @@ -358,6 +426,9 @@ public interface MBeanServer extends MBeanServerConnection { public Set queryNames(ObjectName name, QueryExp query); // doc comment inherited from MBeanServerConnection + /** + * @throws RuntimeOperationsException {@inheritDoc} + */ public boolean isRegistered(ObjectName name); /** @@ -370,21 +441,33 @@ public interface MBeanServer extends MBeanServerConnection { public Integer getMBeanCount(); // doc comment inherited from MBeanServerConnection + /** + * @throws RuntimeOperationsException {@inheritDoc} + */ public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException; // doc comment inherited from MBeanServerConnection + /** + * @throws RuntimeOperationsException {@inheritDoc} + */ public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException; // doc comment inherited from MBeanServerConnection + /** + * @throws RuntimeOperationsException {@inheritDoc} + */ public void setAttribute(ObjectName name, Attribute attribute) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException; // doc comment inherited from MBeanServerConnection + /** + * @throws RuntimeOperationsException {@inheritDoc} + */ public AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException, ReflectionException; @@ -401,14 +484,23 @@ public interface MBeanServer extends MBeanServerConnection { // doc comment inherited from MBeanServerConnection public String[] getDomains(); - // doc comment inherited from MBeanServerConnection + // doc comment inherited from MBeanServerConnection, plus: + /** + * {@inheritDoc} + * 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. + */ public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException; - // doc comment inherited from MBeanServerConnection + /** + * {@inheritDoc} + * @throws RuntimeOperationsException {@inheritDoc} + */ public void addNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, diff --git a/src/share/classes/javax/management/MBeanServerConnection.java b/src/share/classes/javax/management/MBeanServerConnection.java index 4047373c26159d80b34219065022479b97e266ba..0897684a0b52f4d826b550a03c8793c2de73cf7d 100644 --- a/src/share/classes/javax/management/MBeanServerConnection.java +++ b/src/share/classes/javax/management/MBeanServerConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 @@ -29,6 +29,7 @@ package javax.management; // java import import java.io.IOException; import java.util.Set; +import javax.management.event.NotificationManager; /** @@ -39,7 +40,7 @@ import java.util.Set; * * @since 1.5 */ -public interface MBeanServerConnection { +public interface MBeanServerConnection extends NotificationManager { /** *

    Instantiates and registers an MBean in the MBean server. The * MBean server will use its {@link @@ -75,6 +76,24 @@ public interface MBeanServerConnection { * preRegister (MBeanRegistration * interface) method of the MBean has thrown an exception. The * MBean will not be registered. + * @exception RuntimeMBeanException If the postRegister + * (MBeanRegistration interface) method of the MBean throws a + * 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 + * 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 + * 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 + * threw an exception. Note that RuntimeErrorException can + * also be thrown by preRegister, in which case 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 @@ -86,7 +105,7 @@ public interface MBeanServerConnection { * is specified for the MBean. * @exception IOException A communication problem occurred when * talking to the MBean server. - * + * @see javax.management.MBeanRegistration */ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, @@ -129,6 +148,24 @@ public interface MBeanServerConnection { * preRegister (MBeanRegistration * interface) method of the MBean has thrown an exception. The * MBean will not be registered. + * @exception RuntimeMBeanException If the postRegister + * (MBeanRegistration interface) method of the MBean throws a + * 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 + * 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 + * 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 + * threw an exception. Note that RuntimeErrorException can + * also be thrown by preRegister, in which case 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 @@ -142,6 +179,7 @@ public interface MBeanServerConnection { * is specified for the MBean. * @exception IOException A communication problem occurred when * talking to the MBean server. + * @see javax.management.MBeanRegistration */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) @@ -185,6 +223,24 @@ public interface MBeanServerConnection { * preRegister (MBeanRegistration * interface) method of the MBean has thrown an exception. The * MBean will not be registered. + * @exception RuntimeMBeanException If the postRegister + * (MBeanRegistration interface) method of the MBean throws a + * 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 + * 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 + * 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 + * threw an exception. Note that RuntimeErrorException can + * also be thrown by preRegister, in which case 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 @@ -196,7 +252,7 @@ public interface MBeanServerConnection { * is specified for the MBean. * @exception IOException A communication problem occurred when * talking to the MBean server. - * + * @see javax.management.MBeanRegistration */ public ObjectInstance createMBean(String className, ObjectName name, Object params[], String signature[]) @@ -239,6 +295,24 @@ public interface MBeanServerConnection { * preRegister (MBeanRegistration * interface) method of the MBean has thrown an exception. The * MBean will not be registered. + * @exception RuntimeMBeanException If the postRegister + * (MBeanRegistration interface) method of the MBean throws a + * 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 + * 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 + * 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 + * threw an exception. Note that RuntimeErrorException can + * also be thrown by preRegister, in which case 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 @@ -252,7 +326,7 @@ public interface MBeanServerConnection { * is specified for the MBean. * @exception IOException A communication problem occurred when * talking to the MBean server. - * + * @see javax.management.MBeanRegistration */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object params[], @@ -275,6 +349,24 @@ public interface MBeanServerConnection { * @exception MBeanRegistrationException The preDeregister * ((MBeanRegistration interface) method of the MBean * has thrown an exception. + * @exception RuntimeMBeanException If the postDeregister + * (MBeanRegistration interface) method of the MBean throws a + * 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 + * 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 + * throw a RuntimeErrorException, although the MBean + * unregistration succeeded. In such a case, the MBean will be actually + * 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 RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null or the MBean you are when trying to @@ -282,7 +374,7 @@ public interface MBeanServerConnection { * MBeanServerDelegate} MBean. * @exception IOException A communication problem occurred when * talking to the MBean server. - * + * @see javax.management.MBeanRegistration */ public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException, @@ -585,32 +677,7 @@ public interface MBeanServerConnection { public String[] getDomains() throws IOException; - /** - *

    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. - * @exception IOException A communication problem occurred when - * talking to the MBean server. - * - * @see #removeNotificationListener(ObjectName, NotificationListener) - * @see #removeNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) - */ + // doc inherited from NotificationManager public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, @@ -727,65 +794,13 @@ public interface MBeanServerConnection { throws InstanceNotFoundException, ListenerNotFoundException, IOException; - - /** - *

    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 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. - * @exception IOException A communication problem occurred when - * talking to the MBean server. - * - * @see #addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) - */ + // doc inherited from NotificationManager public void removeNotificationListener(ObjectName name, NotificationListener listener) throws InstanceNotFoundException, ListenerNotFoundException, IOException; - /** - *

    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 The listener to be removed. - * @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. - * @exception IOException A communication problem occurred when - * talking to the MBean server. - * - * @see #addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) - * - */ + // doc inherited from NotificationManager public void removeNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, diff --git a/src/share/classes/javax/management/MBeanServerDelegate.java b/src/share/classes/javax/management/MBeanServerDelegate.java index 4ee9766306b4b0e2aa86f95e1999d3d19ddb8c00..aa706da12c2fc81fd4985462104defc91bf22a01 100644 --- a/src/share/classes/javax/management/MBeanServerDelegate.java +++ b/src/share/classes/javax/management/MBeanServerDelegate.java @@ -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,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 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, /** The MBean server agent identification.*/ private String mbeanServerId ; + private String mbeanServerName; /** The NotificationBroadcasterSupport object that sends the notifications */ @@ -68,6 +71,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, public MBeanServerDelegate () { stamp = getStamp(); broadcaster = new NotificationBroadcasterSupport() ; + mbeanServerName=null; } @@ -82,13 +86,102 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, 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 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, * * @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 = + ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate"); /* Return a timestamp that is monotonically increasing even if System.currentTimeMillis() isn't (for example, if you call this diff --git a/src/share/classes/javax/management/MBeanServerFactory.java b/src/share/classes/javax/management/MBeanServerFactory.java index 743ca3a1827da1b86538cf166c960d85747990d2..365f2a7d9b59360ab3af9777c1c0b6d155924fd5 100644 --- a/src/share/classes/javax/management/MBeanServerFactory.java +++ b/src/share/classes/javax/management/MBeanServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 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,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 @@ import javax.management.loading.ClassLoaderRepository; * 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 @@ public class MBeanServerFactory { * 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 @@ public class MBeanServerFactory { * 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 @@ public class MBeanServerFactory { 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,16 +586,107 @@ public class MBeanServerFactory { ArrayList result = new ArrayList(); for (MBeanServer mbs : mBeanServerList) { - String name = mBeanServerName(mbs); + String name = mBeanServerId(mbs); if (agentId.equals(name)) result.add(mbs); } return result; } + /** + *

    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 class MBeanServerFactory { * **/ 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 @@ public class MBeanServerFactory { } 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 @@ public class MBeanServerFactory { **/ 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 @@ public class MBeanServerFactory { 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 @@ public class MBeanServerFactory { 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 --git a/src/share/classes/javax/management/MBeanServerNotification.java b/src/share/classes/javax/management/MBeanServerNotification.java index 25f125df0f788d0b28579aa019c6b5bcb434c945..723d2d4c1e679371e78ac9df09d85017cc1c88f0 100644 --- a/src/share/classes/javax/management/MBeanServerNotification.java +++ b/src/share/classes/javax/management/MBeanServerNotification.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2003 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 @@ -38,56 +38,64 @@ package javax.management; * * @since 1.5 */ - public class MBeanServerNotification extends Notification { +public class MBeanServerNotification extends Notification { - /* Serial version */ - private static final long serialVersionUID = 2876477500475969677L; + /* Serial version */ + private static final long serialVersionUID = 2876477500475969677L; + /** + * Notification type denoting that an MBean has been registered. + * Value is "JMX.mbean.registered". + */ + public static final String REGISTRATION_NOTIFICATION = + "JMX.mbean.registered"; + /** + * Notification type denoting that an MBean has been unregistered. + * Value is "JMX.mbean.unregistered". + */ + public static final String UNREGISTRATION_NOTIFICATION = + "JMX.mbean.unregistered"; + /** + * @serial The object names of the MBeans concerned by this notification + */ + private final ObjectName objectName; - /** - * Notification type denoting that an MBean has been registered. Value is "JMX.mbean.registered". - */ - public static final String REGISTRATION_NOTIFICATION = "JMX.mbean.registered" ; + /** + * Creates an MBeanServerNotification object specifying object names of + * the MBeans that caused the notification and the specified notification + * type. + * + * @param type A string denoting the type of the + * notification. Set it to one these values: {@link + * #REGISTRATION_NOTIFICATION}, {@link + * #UNREGISTRATION_NOTIFICATION}. + * @param source The MBeanServerNotification object responsible + * for forwarding MBean server notification. + * @param sequenceNumber A sequence number that can be used to order + * received notifications. + * @param objectName The object name of the MBean that caused the + * notification. + * + */ + public MBeanServerNotification(String type, Object source, + long sequenceNumber, ObjectName objectName) { + super(type, source, sequenceNumber); + this.objectName = objectName; + } - /** - * Notification type denoting that an MBean has been unregistered. Value is "JMX.mbean.unregistered". - */ - public static final String UNREGISTRATION_NOTIFICATION = "JMX.mbean.unregistered" ; + /** + * Returns the object name of the MBean that caused the notification. + * + * @return the object name of the MBean that caused the notification. + */ + public ObjectName getMBeanName() { + return objectName; + } + @Override + public String toString() { + return super.toString() + "[mbeanName=" + objectName + "]"; - /** - * @serial The object names of the MBeans concerned by this notification - */ - private final ObjectName objectName; - - - /** - * Creates an MBeanServerNotification object specifying object names of - * the MBeans that caused the notification and the specified notification type. - * - * @param type A string denoting the type of the - * notification. Set it to one these values: {@link - * #REGISTRATION_NOTIFICATION}, {@link - * #UNREGISTRATION_NOTIFICATION}. - * @param source The MBeanServerNotification object responsible - * for forwarding MBean server notification. - * @param sequenceNumber A sequence number that can be used to order - * received notifications. - * @param objectName The object name of the MBean that caused the notification. - * - */ - public MBeanServerNotification(String type, Object source, long sequenceNumber, ObjectName objectName ) { - super (type,source,sequenceNumber) ; - this.objectName = objectName ; - } - - /** - * Returns the object name of the MBean that caused the notification. - * - * @return the object name of the MBean that caused the notification. - */ - public ObjectName getMBeanName() { - return objectName ; - } + } } diff --git a/src/share/classes/javax/management/MXBean.java b/src/share/classes/javax/management/MXBean.java index a577fd94ff5a34ee10de03df67ac290829245361..f6691ccaeae6947d30cb34b9fa561f8be79a1368 100644 --- a/src/share/classes/javax/management/MXBean.java +++ b/src/share/classes/javax/management/MXBean.java @@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // remaining imports are for Javadoc -import java.beans.ConstructorProperties; import java.io.InvalidObjectException; import java.lang.management.MemoryUsage; import java.lang.reflect.UndeclaredThrowableException; @@ -470,8 +469,8 @@ public class MemoryPool 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 @@ -865,7 +864,8 @@ public interface ModuleMXBean { J.

  • Otherwise, if J has at least one public - constructor with a {@link ConstructorProperties} annotation, then one + constructor with a {@link java.beans.ConstructorProperties + ConstructorProperties} annotation, then one of those constructors (not necessarily always the same one) will be called to reconstruct an instance of J. Every such annotation must list as many strings as the @@ -1081,9 +1081,10 @@ public interface Node { MXBean is determined as follows.

      -
    • If an {@link JMX.MBeanOptions} argument is supplied to +

    • If a {@link JMX.MBeanOptions} argument is supplied to the {@link StandardMBean} constructor that makes an MXBean, - or to the {@link JMX#newMXBeanProxy JMX.newMXBeanProxy} + or to the {@link JMX#newMBeanProxy(MBeanServerConnection, + ObjectName, Class, JMX.MBeanOptions) JMX.newMBeanProxy} method, and the {@code MBeanOptions} object defines a non-null {@code MXBeanMappingFactory}, then that is the value of f.

    • diff --git a/src/share/classes/javax/management/ManagedAttribute.java b/src/share/classes/javax/management/ManagedAttribute.java index a8a7299d6f91387a6bf8d726a80ffed2d2ee8ae8..3b10b77c5dd97d1dcaeb01562f238e7482ce0312 100644 --- a/src/share/classes/javax/management/ManagedAttribute.java +++ b/src/share/classes/javax/management/ManagedAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/ManagedOperation.java b/src/share/classes/javax/management/ManagedOperation.java index fa01ac2bff6616039c89652308588c1f52aaa10e..7f70e447c962e2ce8363d8cfd09bda0f9751ab8e 100644 --- a/src/share/classes/javax/management/ManagedOperation.java +++ b/src/share/classes/javax/management/ManagedOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/NotificationBroadcasterSupport.java b/src/share/classes/javax/management/NotificationBroadcasterSupport.java index a358a7012a21c3729105f7f189fac7fc84ca2cb4..33df960645021c5c4c012a824ec26e8f3d1d3a42 100644 --- a/src/share/classes/javax/management/NotificationBroadcasterSupport.java +++ b/src/share/classes/javax/management/NotificationBroadcasterSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 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 diff --git a/src/share/classes/javax/management/NotificationInfo.java b/src/share/classes/javax/management/NotificationInfo.java index a899346c06b0178ac654f1e95ee578f175e446c3..29712c5b2d358031118c4ca464997e7118c6ff1d 100644 --- a/src/share/classes/javax/management/NotificationInfo.java +++ b/src/share/classes/javax/management/NotificationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/NotificationInfos.java b/src/share/classes/javax/management/NotificationInfos.java index 9d7c497a78d58eaa31d2d1734cbeadc80e0771d9..cc21d06d3a7926ad227d4db6e89029784e08c8b4 100644 --- a/src/share/classes/javax/management/NotificationInfos.java +++ b/src/share/classes/javax/management/NotificationInfos.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/ObjectName.java b/src/share/classes/javax/management/ObjectName.java index b45e9406e2b667ff8e970038227589b8c3c08816..8185edc274206b2e4e49edfae73f0e47c8ebe3e9 100644 --- a/src/share/classes/javax/management/ObjectName.java +++ b/src/share/classes/javax/management/ObjectName.java @@ -27,6 +27,8 @@ package javax.management; 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; @@ -38,9 +40,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.QueryExp; /** *

      Represents the object name of an MBean, or a pattern that can @@ -225,6 +224,17 @@ import javax.management.QueryExp; @SuppressWarnings("serial") // don't complain serialVersionUID not constant 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 @@ -254,16 +264,17 @@ public class ObjectName implements Comparable, QueryExp { /** * 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); } } @@ -396,6 +407,45 @@ public class ObjectName implements Comparable, QueryExp { */ 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 { + + // 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 <======================================== @@ -417,7 +467,7 @@ public class ObjectName implements Comparable, QueryExp { * is null. */ private void construct(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // The name cannot be null if (name == null) @@ -438,10 +488,10 @@ public class ObjectName implements Comparable, QueryExp { } // 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; @@ -640,10 +690,12 @@ public class ObjectName implements Comparable, QueryExp { // 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); @@ -677,7 +729,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException One of the parameters is null. */ private void construct(String domain, Map props) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // The domain cannot be null if (domain == null) @@ -728,12 +780,12 @@ public class ObjectName implements Comparable, QueryExp { 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()); } @@ -813,9 +865,9 @@ public class ObjectName implements Comparable, QueryExp { 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] = ','; @@ -1019,7 +1071,7 @@ public class ObjectName implements Comparable, QueryExp { * Check if the supplied key is a valid key. */ private static void checkKey(String key) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { if (key == null) throw new NullPointerException("Invalid key (null)"); @@ -1034,33 +1086,6 @@ public class ObjectName implements Comparable, QueryExp { 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 <============================== @@ -1160,9 +1185,19 @@ public class ObjectName implements Comparable, QueryExp { // //in.defaultReadObject(); final ObjectInputStream.GetField fields = in.readFields(); + String propListString = + (String)fields.get("propertyListString", ""); + + // 6616825: take care of property patterns + final boolean propPattern = + fields.get("propertyPattern" , false); + if (propPattern) { + propListString = + (propListString.length()==0?"*":(propListString+",*")); + } + cn = (String)fields.get("domain", "default")+ - ":"+ - (String)fields.get("propertyListString", ""); + ":"+ propListString; } else { // Read an object serialized in the new serial form // @@ -1170,15 +1205,43 @@ public class ObjectName implements Comparable, QueryExp { 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}. @@ -1241,15 +1304,22 @@ public class ObjectName implements Comparable, QueryExp { 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(); @@ -1259,7 +1329,8 @@ public class ObjectName implements Comparable, QueryExp { // Serializes this instance in the new serial form // out.defaultWriteObject(); - out.writeObject(getSerializedNameString()); + + out.writeObject(changeContext(ctxt,getSerializedNameString())); } } @@ -1288,9 +1359,10 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException The name parameter * is null. * + * @see #valueOf(String) */ public static ObjectName getInstance(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(name); } @@ -1315,10 +1387,11 @@ public class ObjectName implements Comparable, QueryExp { * follow the rules for quoting. * @exception NullPointerException One of the parameters is null. * + * @see #valueOf(String, String, String) */ public static ObjectName getInstance(String domain, String key, String value) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(domain, key, value); } @@ -1346,10 +1419,11 @@ public class ObjectName implements Comparable, QueryExp { * quoting. * @exception NullPointerException One of the parameters is null. * + * @see #valueOf(String, Hashtable) */ public static ObjectName getInstance(String domain, Hashtable table) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(domain, table); } @@ -1382,11 +1456,141 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException The name is null. * */ - public static ObjectName getInstance(ObjectName name) - throws NullPointerException { + public static ObjectName getInstance(ObjectName name) { if (name.getClass().equals(ObjectName.class)) return name; - return Util.newObjectName(name.getSerializedNameString()); + return valueOf(name.getSerializedNameString()); + } + + /** + *

      Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String) new + * ObjectName(name)} can be used. The returned object may be of + * a subclass of ObjectName. Calling this method twice with the + * same parameters may return the same object or two equal but + * not identical objects.

      + * + *

      This method is equivalent to {@link #getInstance(String)} except that + * it does not throw any checked exceptions.

      + * + * @param name A string representation of the object name. + * + * @return an ObjectName corresponding to the given String. + * + * @exception IllegalArgumentException The string passed as a + * parameter does not have the right format. The {@linkplain + * Throwable#getCause() cause} of this exception will be a + * {@link MalformedObjectNameException}. + * @exception NullPointerException The name parameter + * is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String name) { + try { + return getInstance(name); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + // Just plain IllegalArgumentException(e) produces an exception + // message "javax.management.MalformedObjectNameException: ..." + // which is distracting. + } + } + + /** + *

      Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String, String, + * String) new ObjectName(domain, key, value)} can be used. The + * returned object may be of a subclass of ObjectName. Calling + * this method twice with the same parameters may return the same + * object or two equal but not identical objects.

      + * + *

      This method is equivalent to {@link #getInstance(String, String, + * String)} except that it does not throw any checked exceptions.

      + * + * @param domain The domain part of the object name. + * @param key The attribute in the key property of the object name. + * @param value The value in the key property of the object name. + * + * @return an ObjectName corresponding to the given domain, + * key, and value. + * + * @exception IllegalArgumentException The + * domain, key, or value + * contains an illegal character, or value does not + * follow the rules for quoting. The {@linkplain + * Throwable#getCause() cause} of this exception will be a + * {@link MalformedObjectNameException}. + * @exception NullPointerException One of the parameters is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String domain, String key, String value) { + try { + return getInstance(domain, key, value); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + /** + *

      Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String, Hashtable) + * new ObjectName(domain, table)} can be used. The returned + * object may be of a subclass of ObjectName. Calling this method + * twice with the same parameters may return the same object or + * two equal but not identical objects.

      + * + *

      This method is equivalent to {@link #getInstance(String, Hashtable)} + * except that it does not throw any checked exceptions.

      + * + * @param domain The domain part of the object name. + * @param table A hash table containing one or more key + * properties. The key of each entry in the table is the key of a + * key property in the object name. The associated value in the + * table is the associated value in the object name. + * + * @return an ObjectName corresponding to the given domain and + * key mappings. + * + * @exception IllegalArgumentException The domain + * contains an illegal character, or one of the keys or values in + * table contains an illegal character, or one of the + * values in table does not follow the rules for + * quoting. The {@linkplain Throwable#getCause() cause} of this exception + * will be a {@link MalformedObjectNameException}. + * @exception NullPointerException One of the parameters is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String domain, + Hashtable table) { + try { + return new ObjectName(domain, table); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + /** + * 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 MalformedObjectNameException { + return new ObjectName(newDomain, this); } /** @@ -1398,9 +1602,11 @@ public class ObjectName implements Comparable, QueryExp { * parameter does not have the right format. * @exception NullPointerException The name parameter * is null. + * + * @see #valueOf(String) */ public ObjectName(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { construct(name); } @@ -1416,9 +1622,11 @@ public class ObjectName implements Comparable, QueryExp { * contains an illegal character, or value does not * follow the rules for quoting. * @exception NullPointerException One of the parameters is null. + * + * @see #valueOf(String, String, String) */ public ObjectName(String domain, String key, String value) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // If key or value are null a NullPointerException // will be thrown by the put method in Hashtable. // @@ -1441,9 +1649,11 @@ public class ObjectName implements Comparable, QueryExp { * values in table does not follow the rules for * quoting. * @exception NullPointerException One of the parameters is null. + * + * @see #valueOf(String, Hashtable) */ public ObjectName(String domain, Hashtable table) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { construct(domain, table); /* The exception for when a key or value in the table is not a String is now ClassCastException rather than @@ -1537,13 +1747,12 @@ public class ObjectName implements Comparable, QueryExp { * * @since 1.6 */ - public boolean isPropertyValuePattern(String property) - throws NullPointerException, IllegalArgumentException { + public boolean isPropertyValuePattern(String property) { if (property == null) 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); } @@ -1599,7 +1808,7 @@ public class ObjectName implements Comparable, QueryExp { * * @exception NullPointerException If property is null. */ - public String getKeyProperty(String property) throws NullPointerException { + public String getKeyProperty(String property) { return _getKeyPropertyList().get(property); } @@ -1623,8 +1832,10 @@ public class ObjectName implements Comparable, QueryExp { 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)); } } } @@ -1709,7 +1920,8 @@ public class ObjectName implements Comparable, QueryExp { } } - return new String(dest_chars); + final String name = new String(dest_chars); + return name; } /** @@ -1727,7 +1939,7 @@ public class ObjectName implements Comparable, QueryExp { 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; @@ -1735,7 +1947,7 @@ public class ObjectName implements Comparable, QueryExp { 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++] = ','; @@ -1796,6 +2008,7 @@ public class ObjectName implements Comparable, QueryExp { * @return True if object is an ObjectName whose * canonical form is equal to that of this ObjectName. */ + @Override public boolean equals(Object object) { // same object case @@ -1808,7 +2021,7 @@ public class ObjectName implements Comparable, QueryExp { // (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 @@ -1819,6 +2032,7 @@ public class ObjectName implements Comparable, QueryExp { * Returns a hash code for this object name. * */ + @Override public int hashCode() { return _canonicalName.hashCode(); } @@ -1853,8 +2067,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if s is null. * */ - public static String quote(String s) - throws NullPointerException { + public static String quote(String s) { final StringBuilder buf = new StringBuilder("\""); final int len = s.length(); for (int i = 0; i < len; i++) { @@ -1898,8 +2111,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if q is null. * */ - public static String unquote(String q) - throws IllegalArgumentException, NullPointerException { + public static String unquote(String q) { final StringBuilder buf = new StringBuilder(); final int len = q.length(); if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"') @@ -1944,7 +2156,7 @@ public class ObjectName implements Comparable, QueryExp { * * @since 1.6 */ - public static final ObjectName WILDCARD = Util.newObjectName("*:*"); + public static final ObjectName WILDCARD = valueOf("*:*"); // Category : Utilities <=================================== @@ -1967,7 +2179,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if name is null. * */ - public boolean apply(ObjectName name) throws NullPointerException { + public boolean apply(ObjectName name) { if (name == null) throw new NullPointerException(); @@ -1988,9 +2200,9 @@ public class ObjectName implements Comparable, QueryExp { 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()); } @@ -2016,7 +2228,7 @@ public class ObjectName implements Comparable, QueryExp { // 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 ? // @@ -2025,15 +2237,13 @@ public class ObjectName implements Comparable, QueryExp { // 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; @@ -2100,6 +2310,10 @@ public class ObjectName implements Comparable, QueryExp { * @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 --git a/src/share/classes/javax/management/QueryNotificationFilter.java b/src/share/classes/javax/management/QueryNotificationFilter.java index 42451088f2ede0a0ad8bc72c99472ae0e18ab0fa..7d1990fa2b9e1d703f57428aad47d37cd91fdb11 100644 --- a/src/share/classes/javax/management/QueryNotificationFilter.java +++ b/src/share/classes/javax/management/QueryNotificationFilter.java @@ -170,7 +170,7 @@ public class QueryNotificationFilter implements NotificationFilter { private static final long serialVersionUID = -8408613922660635231L; private static final ObjectName DEFAULT_NAME = - Util.newObjectName(":type=Notification"); + ObjectName.valueOf(":type=Notification"); private static final QueryExp trueQuery; static { ValueExp zero = Query.value(0); diff --git a/src/share/classes/javax/management/QueryParser.java b/src/share/classes/javax/management/QueryParser.java index babf05c7a2027610c19e97319cdbe30f8388ec30..715f42070e128b5a329e29a53b52e684288484cb 100644 --- a/src/share/classes/javax/management/QueryParser.java +++ b/src/share/classes/javax/management/QueryParser.java @@ -312,7 +312,7 @@ class QueryParser { if (e > 0) ss = s.substring(0, e); ss = ss.replace("0", "").replace(".", ""); - if (!ss.isEmpty()) + if (!ss.equals("")) throw new NumberFormatException("Underflow: " + s); } return d; diff --git a/src/share/classes/javax/management/SendNotification.java b/src/share/classes/javax/management/SendNotification.java index e2875d4f1217899fc867c481250cb6040e8f4cda..497b51e60342c21ff867d9bbb122bd4409d81bcd 100644 --- a/src/share/classes/javax/management/SendNotification.java +++ b/src/share/classes/javax/management/SendNotification.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/javax/management/StandardEmitterMBean.java b/src/share/classes/javax/management/StandardEmitterMBean.java index c3faec374eb9d1b74abfffd86b6d8be61774c592..da5f991f4271505c2b997d67cdaad6c833e8595e 100644 --- a/src/share/classes/javax/management/StandardEmitterMBean.java +++ b/src/share/classes/javax/management/StandardEmitterMBean.java @@ -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 diff --git a/src/share/classes/javax/management/StringValueExp.java b/src/share/classes/javax/management/StringValueExp.java index 9f2ed4a3b4538b587fd4c928061da5cfa97193d5..cc092db3818f49f4b71ea41634c9d068b7dc4e64 100644 --- a/src/share/classes/javax/management/StringValueExp.java +++ b/src/share/classes/javax/management/StringValueExp.java @@ -85,6 +85,7 @@ public class StringValueExp implements ValueExp { /* There is no need for this method, because if a query is being evaluated a StringValueExp can only appear inside a QueryExp, and that QueryExp will itself have done setMBeanServer. */ + @Deprecated public void setMBeanServer(MBeanServer s) { } /** diff --git a/src/share/classes/javax/management/event/EventClient.java b/src/share/classes/javax/management/event/EventClient.java new file mode 100644 index 0000000000000000000000000000000000000000..6f5c84eb2cd4bc24c9bdfa0cc1b4f67450349fec --- /dev/null +++ b/src/share/classes/javax/management/event/EventClient.java @@ -0,0 +1,1088 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.event.DaemonThreadFactory; +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; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServerConnection; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; + +/** + *

      This class is used to manage its notification listeners on the client + * side in the same way as on the MBean server side. This class needs to work + * with an {@link EventClientDelegateMBean} on the server side.

      + * + *

      A user can specify an {@link EventRelay} object to specify how to receive + * notifications forwarded by the {@link EventClientDelegateMBean}. By default, + * the class {@link FetchingEventRelay} is used.

      + * + *

      A user can specify an {@link java.util.concurrent.Executor Executor} + * to distribute notifications to local listeners. If no executor is + * specified, the thread in the {@link EventRelay} which calls {@link + * EventReceiver#receive EventReceiver.receive} will be reused to distribute + * the notifications (in other words, to call the {@link + * NotificationListener#handleNotification handleNotification} method of the + * appropriate listeners). It is useful to make a separate thread do this + * distribution in some cases. For example, if network communication is slow, + * the forwarding thread can concentrate on communication while, locally, + * the distributing thread distributes the received notifications. Another + * usage is to share a thread pool between many clients, for scalability. + * Note, though, that if the {@code Executor} can create more than one thread + * then it is possible that listeners will see notifications in a different + * order from the order in which they were sent.

      + * + *

      An object of this class sends notifications to listeners added with + * {@link #addEventClientListener}. The {@linkplain Notification#getType() + * type} of each such notification is one of {@link #FAILED}, {@link #NONFATAL}, + * or {@link #NOTIFS_LOST}.

      + * + * @since JMX 2.0 + */ +public class EventClient implements EventConsumer, NotificationManager { + + /** + *

      A notification string type used by an {@code EventClient} object + * to inform a listener added by {@link #addEventClientListener} that + * it failed to get notifications from a remote server, and that it is + * possible that no more notifications will be delivered.

      + * + * @see #addEventClientListener + * @see EventReceiver#failed + */ + public static final String FAILED = "jmx.event.service.failed"; + + /** + *

      Reports that an unexpected exception has been received by the {@link + * EventRelay} object but that it is non-fatal. For example, a notification + * received is not serializable or its class is not found.

      + * + * @see #addEventClientListener + * @see EventReceiver#nonFatal + */ + public static final String NONFATAL = "jmx.event.service.nonfatal"; + + /** + *

      A notification string type used by an {@code EventClient} object to + * inform a listener added by {@code #addEventClientListener} that it + * has detected that notifications have been lost. The {@link + * Notification#getUserData() userData} of the notification is a Long which + * is an upper bound on the number of lost notifications that have just + * been detected.

      + * + * @see #addEventClientListener + */ + public static final String NOTIFS_LOST = "jmx.event.service.notifs.lost"; + + /** + * The default lease time, {@value}, in milliseconds. + * + * @see EventClientDelegateMBean#lease + */ + public static final long DEFAULT_LEASE_TIMEOUT = 300000; + + /** + *

      Constructs a default {@code EventClient} object.

      + * + *

      This object creates a {@link FetchingEventRelay} object to + * receive notifications forwarded by the {@link EventClientDelegateMBean}. + * The {@link EventClientDelegateMBean} that it works with is the + * one registered with the {@linkplain EventClientDelegate#OBJECT_NAME + * default ObjectName}. The thread from the {@link FetchingEventRelay} + * object that fetches the notifications is also used to distribute them. + * + * @param conn An {@link MBeanServerConnection} object used to communicate + * with an {@link EventClientDelegateMBean} MBean. + * + * @throws IllegalArgumentException If {@code conn} is null. + * @throws IOException If an I/O error occurs when communicating with the + * {@code EventClientDelegateMBean}. + */ + public EventClient(MBeanServerConnection conn) throws IOException { + this(EventClientDelegate.getProxy(conn)); + } + + /** + * Constructs an {@code EventClient} object with a specified + * {@link EventClientDelegateMBean}. + * + *

      This object creates a {@link FetchingEventRelay} object to receive + * notifications forwarded by the {@link EventClientDelegateMBean}. The + * thread from the {@link FetchingEventRelay} object that fetches the + * notifications is also used to distribute them. + * + * @param delegate An {@link EventClientDelegateMBean} object to work with. + * + * @throws IllegalArgumentException If {@code delegate} is null. + * @throws IOException If an I/O error occurs when communicating with the + * the {@link EventClientDelegateMBean}. + */ + public EventClient(EventClientDelegateMBean delegate) + throws IOException { + this(delegate, null, null, null, DEFAULT_LEASE_TIMEOUT); + } + + /** + * Constructs an {@code EventClient} object with the specified + * {@link EventClientDelegateMBean}, {@link EventRelay} + * object, and distributing thread. + * + * @param delegate An {@link EventClientDelegateMBean} object to work with. + * Usually, this will be a proxy constructed using + * {@link EventClientDelegate#getProxy}. + * @param eventRelay An object used to receive notifications + * forwarded by the {@link EventClientDelegateMBean}. If {@code null}, a + * {@link FetchingEventRelay} object will be used. + * @param distributingExecutor Used to distribute notifications to local + * listeners. If {@code null}, the thread that calls {@link + * EventReceiver#receive EventReceiver.receive} from the {@link EventRelay} + * object is used. + * @param leaseScheduler An object that will be used to schedule the + * periodic {@linkplain EventClientDelegateMBean#lease lease updates}. + * If {@code null}, a default scheduler will be used. + * @param requestedLeaseTime The lease time used to keep this client alive + * in the {@link EventClientDelegateMBean}. A value of zero is equivalent + * to the {@linkplain #DEFAULT_LEASE_TIMEOUT default value}. + * + * @throws IllegalArgumentException If {@code delegate} is null. + * @throws IOException If an I/O error occurs when communicating with the + * {@link EventClientDelegateMBean}. + */ + public EventClient(EventClientDelegateMBean delegate, + EventRelay eventRelay, + Executor distributingExecutor, + ScheduledExecutorService leaseScheduler, + long requestedLeaseTime) + throws IOException { + if (delegate == null) { + throw new IllegalArgumentException("Null EventClientDelegateMBean"); + } + + if (requestedLeaseTime == 0) + requestedLeaseTime = DEFAULT_LEASE_TIMEOUT; + else if (requestedLeaseTime < 0) { + throw new IllegalArgumentException( + "Negative lease time: " + requestedLeaseTime); + } + + eventClientDelegate = delegate; + + if (eventRelay != null) { + this.eventRelay = eventRelay; + } else { + try { + this.eventRelay = new FetchingEventRelay(delegate); + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + // impossible? + final IOException ioee = new IOException(e.toString()); + ioee.initCause(e); + throw ioee; + } + } + + if (distributingExecutor == null) + distributingExecutor = callerExecutor; + this.distributingExecutor = distributingExecutor; + this.dispatchingJob = new DispatchingJob(); + + clientId = this.eventRelay.getClientId(); + + this.requestedLeaseTime = requestedLeaseTime; + if (leaseScheduler == null) + leaseScheduler = defaultLeaseScheduler(); + leaseRenewer = new LeaseRenewer(leaseScheduler, renewLease); + + if (logger.traceOn()) { + logger.trace("init", "New EventClient: "+clientId); + } + } + + private static ScheduledExecutorService defaultLeaseScheduler() { + // The default lease scheduler uses a ScheduledThreadPoolExecutor + // with a maximum of 20 threads. This means that if you have many + // EventClient instances and some of them get blocked (because of an + // unresponsive network, for example), then even the instances that + // are connected to responsive servers may have their leases expire. + // XXX check if the above is true and possibly fix. + PerThreadGroupPool.Create create = + new PerThreadGroupPool.Create() { + public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) { + ThreadFactory daemonThreadFactory = new DaemonThreadFactory( + "JMX EventClient lease renewer %d"); + ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor( + 20, daemonThreadFactory); + exec.setKeepAliveTime(1, TimeUnit.SECONDS); + exec.allowCoreThreadTimeOut(true); + exec.setRemoveOnCancelPolicy(true); + return exec; + } + }; + return leaseRenewerThreadPool.getThreadPoolExecutor(create); + + } + + /** + *

      Closes this EventClient, removes all listeners and stops receiving + * notifications.

      + * + *

      This method calls {@link + * EventClientDelegateMBean#removeClient(String)} and {@link + * EventRelay#stop}. Both operations occur even if one of them + * throws an {@code IOException}. + * + * @throws IOException if an I/O error occurs when communicating with + * {@link EventClientDelegateMBean}, or if {@link EventRelay#stop} + * throws an {@code IOException}. + */ + public void close() throws IOException { + if (logger.traceOn()) { + logger.trace("close", clientId); + } + + synchronized(listenerInfoMap) { + if (closed) { + return; + } + + closed = true; + listenerInfoMap.clear(); + } + + if (leaseRenewer != null) + leaseRenewer.close(); + + IOException ioe = null; + try { + eventRelay.stop(); + } catch (IOException e) { + ioe = e; + logger.debug("close", "EventRelay.stop", e); + } + + try { + eventClientDelegate.removeClient(clientId); + } catch (Exception e) { + if (e instanceof IOException) + ioe = (IOException) e; + else + ioe = new IOException(e); + logger.debug("close", + "Got exception when removing "+clientId, e); + } + + if (ioe != null) + throw ioe; + } + + /** + *

      Determine if this {@code EventClient} is closed.

      + * + * @return True if the {@code EventClient} is closed. + */ + public boolean closed() { + return closed; + } + + /** + *

      Return the {@link EventRelay} associated with this + * {@code EventClient}.

      + * + * @return The {@link EventRelay} object used. + */ + public EventRelay getEventRelay() { + return eventRelay; + } + + /** + *

      Return the lease time that this {@code EventClient} requests + * on every lease renewal.

      + * + * @return The requested lease time. + * + * @see EventClientDelegateMBean#lease + */ + public long getRequestedLeaseTime() { + return requestedLeaseTime; + } + + /** + * @see javax.management.MBeanServerConnection#addNotificationListener( + * ObjectName, NotificationListener, NotificationFilter, Object). + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, IOException { + if (logger.traceOn()) { + logger.trace("addNotificationListener", ""); + } + + checkState(); + + Integer listenerId; + try { + listenerId = + eventClientDelegate.addListener(clientId, name, filter); + } catch (EventClientNotFoundException ecnfe) { + final IOException ioe = new IOException(); + ioe.initCause(ecnfe); + throw ioe; + } + + synchronized(listenerInfoMap) { + listenerInfoMap.put(listenerId, new ListenerInfo( + name, + listener, + filter, + handback, + false)); + } + + startListening(); + } + + /** + * @see javax.management.MBeanServerConnection#removeNotificationListener( + * ObjectName, NotificationListener). + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, + ListenerNotFoundException, + IOException { + if (logger.traceOn()) { + logger.trace("removeNotificationListener", ""); + } + checkState(); + + for (Integer id : getListenerInfo(name, listener, false)) { + removeListener(id); + } + } + + /** + * @see javax.management.MBeanServerConnection#removeNotificationListener( + * ObjectName, NotificationListener, NotificationFilter, Object). + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, + ListenerNotFoundException, + IOException { + if (logger.traceOn()) { + logger.trace("removeNotificationListener", "with all arguments."); + } + checkState(); + final Integer listenerId = + getListenerInfo(name, listener, filter, handback, false); + + removeListener(listenerId); + } + + /** + * @see javax.management.event.EventConsumer#unsubscribe( + * ObjectName, NotificationListener). + */ + public void unsubscribe(ObjectName name, + NotificationListener listener) + throws ListenerNotFoundException, IOException { + if (logger.traceOn()) { + logger.trace("unsubscribe", ""); + } + checkState(); + final Integer listenerId = + getMatchedListenerInfo(name, listener, true); + + synchronized(listenerInfoMap) { + if (listenerInfoMap.remove(listenerId) == null) { + throw new ListenerNotFoundException(); + } + } + + stopListening(); + + try { + eventClientDelegate.removeListenerOrSubscriber(clientId, listenerId); + } catch (InstanceNotFoundException e) { + logger.trace("unsubscribe", "removeSubscriber", e); + } catch (EventClientNotFoundException cnfe) { + logger.trace("unsubscribe", "removeSubscriber", cnfe); + } + } + + /** + * @see javax.management.event.EventConsumer#subscribe( + * ObjectName, NotificationListener, NotificationFilter, Object). + */ + public void subscribe(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) throws IOException { + if (logger.traceOn()) { + logger.trace("subscribe", ""); + } + + checkState(); + + Integer listenerId; + try { + listenerId = + eventClientDelegate.addSubscriber(clientId, name, filter); + } catch (EventClientNotFoundException ecnfe) { + final IOException ioe = new IOException(); + ioe.initCause(ecnfe); + throw ioe; + } + + synchronized(listenerInfoMap) { + listenerInfoMap.put(listenerId, new ListenerInfo( + name, + listener, + filter, + handback, + true)); + } + + startListening(); + } + + /** + *

      Adds a set of listeners to the remote MBeanServer. This method can + * be used to copy the listeners from one {@code EventClient} to another.

      + * + *

      A listener is represented by a {@link ListenerInfo} object. The listener + * is added by calling {@link #subscribe(ObjectName, + * NotificationListener, NotificationFilter, Object)} if the method + * {@link ListenerInfo#isSubscription() isSubscription} + * returns {@code true}; otherwise it is added by calling + * {@link #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object)}.

      + * + *

      The method returns the listeners which were added successfully. The + * elements in the returned collection are a subset of the elements in + * {@code infoList}. If all listeners were added successfully, the two + * collections are the same. If no listener was added successfully, the + * returned collection is empty.

      + * + * @param listeners the listeners to add. + * + * @return The listeners that were added successfully. + * + * @throws IOException If an I/O error occurs. + * + * @see #getListeners() + */ + public Collection addListeners(Collection listeners) + throws IOException { + if (logger.traceOn()) { + logger.trace("addListeners", ""); + } + + checkState(); + + if (listeners == null || listeners.isEmpty()) + return Collections.emptySet(); + + final List list = new ArrayList(); + for (ListenerInfo l : listeners) { + try { + if (l.isSubscription()) { + subscribe(l.getObjectName(), + l.getListener(), + l.getFilter(), + l.getHandback()); + } else { + addNotificationListener(l.getObjectName(), + l.getListener(), + l.getFilter(), + l.getHandback()); + } + + list.add(l); + } catch (Exception e) { + if (logger.traceOn()) { + logger.trace("addListeners", "failed to add: "+l, e); + } + } + } + + return list; + } + + /** + * Returns the set of listeners that have been added through + * this {@code EventClient} and not subsequently removed. + * + * @return A collection of listener information. Empty if there are no + * current listeners or if this {@code EventClient} has been {@linkplain + * #close closed}. + * + * @see #addListeners + */ + public Collection getListeners() { + if (logger.traceOn()) { + logger.trace("getListeners", ""); + } + + synchronized(listenerInfoMap) { + return Collections.unmodifiableCollection(listenerInfoMap.values()); + } + } + + /** + * Adds a listener to receive the {@code EventClient} notifications specified in + * {@link #getEventClientNotificationInfo}. + * + * @param listener A listener to receive {@code EventClient} notifications. + * @param filter A filter to select which notifications are to be delivered + * to the listener, or {@code null} if all notifications are to be delivered. + * @param handback An object to be given to the listener along with each + * notification. Can be null. + * @throws NullPointerException If listener is null. + * @see #removeEventClientListener + */ + public void addEventClientListener(NotificationListener listener, + NotificationFilter filter, + Object handback) { + if (logger.traceOn()) { + logger.trace("addEventClientListener", ""); + } + broadcaster.addNotificationListener(listener, filter, handback); + } + + /** + * Removes a listener added to receive {@code EventClient} notifications specified in + * {@link #getEventClientNotificationInfo}. + * + * @param listener A listener to receive {@code EventClient} notifications. + * @throws NullPointerException If listener is null. + * @throws ListenerNotFoundException If the listener is not added to + * this {@code EventClient}. + */ + public void removeEventClientListener(NotificationListener listener) + throws ListenerNotFoundException { + if (logger.traceOn()) { + logger.trace("removeEventClientListener", ""); + } + broadcaster.removeNotificationListener(listener); + } + + /** + *

      Get the types of notification that an {@code EventClient} can send + * to listeners added with {@link #addEventClientListener + * addEventClientListener}.

      + * + * @return Types of notification emitted by this {@code EventClient}. + * + * @see #FAILED + * @see #NONFATAL + * @see #NOTIFS_LOST + */ + public MBeanNotificationInfo[] getEventClientNotificationInfo() { + return myInfo.clone(); + } + + private static boolean match(ListenerInfo li, + ObjectName name, + NotificationListener listener, + boolean subscribed) { + return li.getObjectName().equals(name) && + li.getListener() == listener && + li.isSubscription() == subscribed; + } + + private static boolean match(ListenerInfo li, + ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback, + boolean subscribed) { + return li.getObjectName().equals(name) && + li.getFilter() == filter && + li.getListener() == listener && + li.getHandback() == handback && + li.isSubscription() == subscribed; + } + +// --------------------------------------------------- +// private classes +// --------------------------------------------------- + private class DispatchingJob extends RepeatedSingletonJob { + public DispatchingJob() { + super(distributingExecutor); + } + + public boolean isSuspended() { + return closed || buffer.size() == 0; + } + + public void task() { + TargetedNotification[] tns ; + int lost = 0; + + synchronized(buffer) { + tns = buffer.removeNotifs(); + lost = buffer.removeLost(); + } + + if ((tns == null || tns.length == 0) + && lost == 0) { + return; + } + + // forwarding + if (tns != null && tns.length > 0) { + if (logger.traceOn()) { + logger.trace("DispatchingJob-task", + "Forwarding: "+tns.length); + } + for (TargetedNotification tn : tns) { + final ListenerInfo li = listenerInfoMap.get(tn.getListenerID()); + try { + li.getListener().handleNotification(tn.getNotification(), + li.getHandback()); + } catch (Exception e) { + logger.fine( + "DispatchingJob.task", "listener got exception", e); + } + } + } + + if (lost > 0) { + if (logger.traceOn()) { + logger.trace("DispatchingJob-task", + "lost: "+lost); + } + final Notification n = new Notification(NOTIFS_LOST, + EventClient.this, + myNotifCounter.getAndIncrement(), + System.currentTimeMillis(), + "Lost notifications."); + n.setUserData(new Long(lost)); + broadcaster.sendNotification(n); + } + } + } + + + private class EventReceiverImpl implements EventReceiver { + public void receive(NotificationResult nr) { + if (logger.traceOn()) { + logger.trace("MyEventReceiver-receive", ""); + } + + synchronized(buffer) { + buffer.addNotifs(nr); + + dispatchingJob.resume(); + } + } + + public void failed(Throwable t) { + if (logger.traceOn()) { + logger.trace("MyEventReceiver-failed", "", t); + } + final Notification n = new Notification(FAILED, + this, + myNotifCounter.getAndIncrement(), + System.currentTimeMillis()); + n.setSource(t); + broadcaster.sendNotification(n); + } + + public void nonFatal(Exception e) { + if (logger.traceOn()) { + logger.trace("MyEventReceiver-nonFatal", "", e); + } + + final Notification n = new Notification(NONFATAL, + this, + myNotifCounter.getAndIncrement(), + System.currentTimeMillis()); + n.setSource(e); + broadcaster.sendNotification(n); + } + } + +// ---------------------------------------------------- +// private class +// ---------------------------------------------------- + + +// ---------------------------------------------------- +// private methods +// ---------------------------------------------------- + private Integer getListenerInfo(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback, + boolean subscribed) throws ListenerNotFoundException { + + synchronized(listenerInfoMap) { + for (Map.Entry entry : + listenerInfoMap.entrySet()) { + ListenerInfo li = entry.getValue(); + if (match(li, name, listener, filter, handback, subscribed)) { + return entry.getKey(); + } + } + } + + throw new ListenerNotFoundException(); + } + + private Integer getMatchedListenerInfo(ObjectName name, + NotificationListener listener, + boolean subscribed) throws ListenerNotFoundException { + + synchronized(listenerInfoMap) { + for (Map.Entry entry : + listenerInfoMap.entrySet()) { + ListenerInfo li = entry.getValue(); + if (li.getObjectName().equals(name) && + li.getListener() == listener && + li.isSubscription() == subscribed) { + return entry.getKey(); + } + } + } + + throw new ListenerNotFoundException(); + } + + private Collection getListenerInfo(ObjectName name, + NotificationListener listener, + boolean subscribed) throws ListenerNotFoundException { + + final ArrayList ids = new ArrayList(); + synchronized(listenerInfoMap) { + for (Map.Entry entry : + listenerInfoMap.entrySet()) { + ListenerInfo li = entry.getValue(); + if (match(li, name, listener, subscribed)) { + ids.add(entry.getKey()); + } + } + } + + if (ids.isEmpty()) { + throw new ListenerNotFoundException(); + } + + return ids; + } + + private void checkState() throws IOException { + synchronized(listenerInfoMap) { + if (closed) { + throw new IOException("Ended!"); + } + } + } + + private void startListening() throws IOException { + synchronized(listenerInfoMap) { + if (!startedListening && listenerInfoMap.size() > 0) { + eventRelay.setEventReceiver(myReceiver); + } + + startedListening = true; + + if (logger.traceOn()) { + logger.trace("startListening", "listening"); + } + } + } + + private void stopListening() throws IOException { + synchronized(listenerInfoMap) { + if (listenerInfoMap.size() == 0 && startedListening) { + eventRelay.setEventReceiver(null); + + startedListening = false; + + if (logger.traceOn()) { + logger.trace("stopListening", "non listening"); + } + } + } + } + + private void removeListener(Integer id) + throws InstanceNotFoundException, + ListenerNotFoundException, + IOException { + synchronized(listenerInfoMap) { + if (listenerInfoMap.remove(id) == null) { + throw new ListenerNotFoundException(); + } + + stopListening(); + } + + try { + eventClientDelegate.removeListenerOrSubscriber(clientId, id); + } catch (EventClientNotFoundException cnfe) { + logger.trace("removeListener", "ecd.removeListener", cnfe); + } + } + + +// ---------------------------------------------------- +// private variables +// ---------------------------------------------------- + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventClient"); + + private final Executor distributingExecutor; + private final EventClientDelegateMBean eventClientDelegate; + private final EventRelay eventRelay; + private volatile String clientId = null; + private final long requestedLeaseTime; + + private final ReceiverBuffer buffer = new ReceiverBuffer(); + + private final EventReceiverImpl myReceiver = + new EventReceiverImpl(); + private final DispatchingJob dispatchingJob; + + private final HashMap listenerInfoMap = + new HashMap(); + + private volatile boolean closed = false; + + private volatile boolean startedListening = false; + + // Could change synchronization here. But at worst a race will mean + // sequence numbers are not contiguous, which may not matter much. + private final AtomicLong myNotifCounter = new AtomicLong(); + + private final static MBeanNotificationInfo[] myInfo = + new MBeanNotificationInfo[] { + new MBeanNotificationInfo( + new String[] {FAILED, NOTIFS_LOST}, + Notification.class.getName(), "")}; + + private final NotificationBroadcasterSupport broadcaster = + new NotificationBroadcasterSupport(); + + private final static Executor callerExecutor = new Executor() { + // DirectExecutor using caller thread + public void execute(Runnable r) { + r.run(); + } + }; + + private static void checkInit(final MBeanServerConnection conn, + final ObjectName delegateName) + throws IOException { + if (conn == null) { + throw new IllegalArgumentException("No connection specified"); + } + if (delegateName != null && + (!conn.isRegistered(delegateName))) { + throw new IllegalArgumentException( + delegateName + + ": not found"); + } + if (delegateName == null && + (!conn.isRegistered( + EventClientDelegate.OBJECT_NAME))) { + throw new IllegalArgumentException( + EventClientDelegate.OBJECT_NAME + + ": not found"); + } + } + +// ---------------------------------------------------- +// private event lease issues +// ---------------------------------------------------- + private Callable renewLease = new Callable() { + public Long call() throws IOException, EventClientNotFoundException { + return eventClientDelegate.lease(clientId, requestedLeaseTime); + } + }; + + private final LeaseRenewer leaseRenewer; + +// ------------------------------------------------------------------------ + /** + * Constructs an {@code MBeanServerConnection} that uses an {@code EventClient} object, + * if the underlying connection has an {@link EventClientDelegateMBean}. + *

      The {@code EventClient} object creates a default + * {@link FetchingEventRelay} object to + * receive notifications forwarded by the {@link EventClientDelegateMBean}. + * The {@link EventClientDelegateMBean} it works with is the + * default one registered with the ObjectName + * {@link EventClientDelegate#OBJECT_NAME + * OBJECT_NAME}. + * The thread from the {@link FetchingEventRelay} object that fetches the + * notifications is also used to distribute them. + * + * @param conn An {@link MBeanServerConnection} object used to communicate + * with an {@link EventClientDelegateMBean}. + * @throws IllegalArgumentException If the value of {@code conn} is null, + * or the default {@link EventClientDelegateMBean} is not registered. + * @throws IOException If an I/O error occurs. + */ + public static MBeanServerConnection getEventClientConnection( + final MBeanServerConnection conn) + throws IOException { + return getEventClientConnection(conn, null); + } + + /** + * Constructs an MBeanServerConnection that uses an {@code EventClient} + * object with a user-specific {@link EventRelay} + * object. + *

      + * The {@link EventClientDelegateMBean} which it works with is the + * default one registered with the ObjectName + * {@link EventClientDelegate#OBJECT_NAME + * OBJECT_NAME} + * The thread that calls {@link EventReceiver#receive + * EventReceiver.receive} from the {@link EventRelay} object is used + * to distribute notifications to their listeners. + * + * @param conn An {@link MBeanServerConnection} object used to communicate + * with an {@link EventClientDelegateMBean}. + * @param eventRelay A user-specific object used to receive notifications + * forwarded by the {@link EventClientDelegateMBean}. If null, the default + * {@link FetchingEventRelay} object is used. + * @throws IllegalArgumentException If the value of {@code conn} is null, + * or the default {@link EventClientDelegateMBean} is not registered. + * @throws IOException If an I/O error occurs. + */ + public static MBeanServerConnection getEventClientConnection( + final MBeanServerConnection conn, + final EventRelay eventRelay) + throws IOException { + + if (newEventConn == null) { + throw new IllegalArgumentException( + "Class not found: EventClientConnection"); + } + + checkInit(conn,null); + final Callable factory = new Callable() { + final public EventClient call() throws Exception { + EventClientDelegateMBean ecd = EventClientDelegate.getProxy(conn); + return new EventClient(ecd, eventRelay, null, null, + DEFAULT_LEASE_TIMEOUT); + } + }; + + try { + return (MBeanServerConnection)newEventConn.invoke(null, + conn, factory); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + private static Method newEventConn = null; + static { + try { + Class c = Class.forName( + "com.sun.jmx.remote.util.EventClientConnection", + false, Thread.currentThread().getContextClassLoader()); + newEventConn = c.getMethod("getEventConnectionFor", + MBeanServerConnection.class, Callable.class); + } catch (Exception e) { + // OK: we're running in a subset of our classes + } + } + + /** + *

      Get the client id of this {@code EventClient} in the + * {@link EventClientDelegateMBean}. + * + * @return the client id. + * + * @see EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient + */ + public String getClientId() { + 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 --git a/src/share/classes/javax/management/event/EventClientDelegate.java b/src/share/classes/javax/management/event/EventClientDelegate.java new file mode 100644 index 0000000000000000000000000000000000000000..8d144123a8763d9b9647607b2d3bfe6c1fcbcb9a --- /dev/null +++ b/src/share/classes/javax/management/event/EventClientDelegate.java @@ -0,0 +1,784 @@ +/* + * 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. + * + * @since JMX 2.0 + */ + +package javax.management.event; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; + +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.NotificationResult; +import com.sun.jmx.event.EventBuffer; +import com.sun.jmx.event.LeaseManager; +import com.sun.jmx.interceptor.SingleMBeanForwarder; +import com.sun.jmx.mbeanserver.Util; +import com.sun.jmx.remote.util.ClassLogger; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import javax.management.DynamicMBean; +import javax.management.MBeanException; +import javax.management.MBeanPermission; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MBeanServerNotification; +import javax.management.ObjectInstance; +import javax.management.StandardMBean; +import javax.management.remote.MBeanServerForwarder; + +/** + * This is the default implementation of the MBean + * {@link EventClientDelegateMBean}. + */ +public class EventClientDelegate implements EventClientDelegateMBean { + + private EventClientDelegate(MBeanServer server) { + if (server == null) { + throw new NullPointerException("Null MBeanServer."); + } + + if (logger.traceOn()) { + logger.trace("EventClientDelegate", "new one"); + } + mbeanServer = server; + eventSubscriber = EventSubscriber.getEventSubscriber(mbeanServer); + } + + /** + * Returns an {@code EventClientDelegate} instance for the given + * {@code MBeanServer}. Calling this method more than once with the same + * {@code server} argument may return the same object or a different object + * each time. See {@link EventClientDelegateMBean} for an example use of + * this method. + * + * @param server An MBean server instance to work with. + * @return An {@code EventClientDelegate} instance. + * @throws NullPointerException If {@code server} is null. + */ + public static EventClientDelegate getEventClientDelegate(MBeanServer server) { + EventClientDelegate delegate = null; + synchronized(delegateMap) { + final WeakReference wrf = delegateMap.get(server); + delegate = (wrf == null) ? null : (EventClientDelegate)wrf.get(); + + if (delegate == null) { + delegate = new EventClientDelegate(server); + try { + // TODO: this may not work with federated MBean, because + // the delegate will *not* emit notifications for those MBeans. + delegate.mbeanServer.addNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, + delegate.cleanListener, null, null); + } catch (InstanceNotFoundException e) { + logger.fine( + "getEventClientDelegate", + "Could not add MBeanServerDelegate listener", e); + } + delegateMap.put(server, + new WeakReference(delegate)); + } + } + + return delegate; + } + + // Logic for the MBeanServerForwarder that simulates the existence of the + // EventClientDelegate MBean. Things are complicated by the fact that + // there may not be anything in the chain after this forwarder when it is + // created - the connection to a real MBeanServer might only come later. + // Recall that there are two ways of creating a JMXConnectorServer - + // either you specify its MBeanServer when you create it, or you specify + // no MBeanServer and register it in an MBeanServer later. In the latter + // case, the forwarder chain points nowhere until this registration + // happens. Since EventClientDelegate wants to add a listener to the + // MBeanServerDelegate, we can't create an EventClientDelegate until + // there is an MBeanServer. So the forwarder initially has + // a dummy ECD where every method throws an exception, and + // the real ECD is created as soon as doing so does not produce an + // exception. + // TODO: rewrite so that the switch from the dummy to the real ECD happens + // just before we would otherwise have thrown UnsupportedOperationException. + // This is more correct, because it's not guaranteed that we will see the + // moment where the real MBeanServer is attached, if it happens by virtue + // of a setMBeanServer on some other forwarder later in the chain. + + private static class Forwarder extends SingleMBeanForwarder { + + private static class UnsupportedInvocationHandler + implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + throw new UnsupportedOperationException( + "EventClientDelegate unavailable: no MBeanServer, or " + + "MBeanServer inaccessible"); + } + } + + private static DynamicMBean makeUnsupportedECD() { + EventClientDelegateMBean unsupported = (EventClientDelegateMBean) + Proxy.newProxyInstance( + EventClientDelegateMBean.class.getClassLoader(), + new Class[] {EventClientDelegateMBean.class}, + new UnsupportedInvocationHandler()); + return new StandardMBean( + unsupported, EventClientDelegateMBean.class, false); + } + + private volatile boolean madeECD; + + Forwarder() { + super(OBJECT_NAME, makeUnsupportedECD()); + } + + @Override + public synchronized void setMBeanServer(final MBeanServer mbs) { + super.setMBeanServer(mbs); + + if (!madeECD) { + try { + EventClientDelegate ecd = + AccessController.doPrivileged( + new PrivilegedAction() { + public EventClientDelegate run() { + return getEventClientDelegate(Forwarder.this); + } + }); + DynamicMBean mbean = new StandardMBean( + ecd, EventClientDelegateMBean.class, false); + setSingleMBean(mbean); + madeECD = true; + } catch (Exception e) { + // OK: assume no MBeanServer + logger.fine("setMBeanServer", "isRegistered", e); + } + } + } + } + + /** + *

      Create a new {@link MBeanServerForwarder} that simulates the existence + * of an {@code EventClientDelegateMBean} with the {@linkplain + * #OBJECT_NAME default name}. This forwarder intercepts MBean requests + * that are targeted for that MBean and handles them itself. All other + * requests are forwarded to the next element in the forwarder chain.

      + * + * @return a new {@code MBeanServerForwarder} that simulates the existence + * of an {@code EventClientDelegateMBean}. + */ + public static MBeanServerForwarder newForwarder() { + return new Forwarder(); + } + + /** + * Returns a proxy of the default {@code EventClientDelegateMBean}. + * + * @param conn An {@link MBeanServerConnection} to work with. + */ + @SuppressWarnings("cast") // cast for jdk 1.5 + public static EventClientDelegateMBean getProxy(MBeanServerConnection conn) { + return (EventClientDelegateMBean)MBeanServerInvocationHandler. + newProxyInstance(conn, + OBJECT_NAME, + EventClientDelegateMBean.class, + false); + } + + public String addClient(String className, Object[] params, String[] sig) + throws MBeanException { + return addClient(className, null, params, sig, true); + } + + public String addClient(String className, + ObjectName classLoader, + Object[] params, + String[] sig) throws MBeanException { + return addClient(className, classLoader, params, sig, false); + } + + private String addClient(String className, + ObjectName classLoader, + Object[] params, + String[] sig, + boolean classLoaderRepository) throws MBeanException { + try { + return addClientX( + className, classLoader, params, sig, classLoaderRepository); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new MBeanException(e); + } + } + + private String addClientX(String className, + ObjectName classLoader, + Object[] params, + String[] sig, + boolean classLoaderRepository) throws Exception { + if (className == null) { + throw new IllegalArgumentException("Null class name."); + } + + final Object o; + + // The special treatment of standard EventForwarders is so that no + // special permissions are necessary to use them. Otherwise you + // couldn't use EventClient if you didn't have permission to call + // MBeanServer.instantiate. We do require that permission for + // non-standard forwarders, because otherwise you could instantiate + // any class with possibly adverse consequences. We also avoid using + // MBeanInstantiator because it looks up constructors by loading each + // class in the sig array, which means a remote user could cause any + // class to be loaded. That's probably not hugely risky but still. + if (className.startsWith("javax.management.event.")) { + Class c = Class.forName( + className, false, this.getClass().getClassLoader()); + Constructor foundCons = null; + if (sig == null) + sig = new String[0]; + for (Constructor cons : c.getConstructors()) { + Class[] types = cons.getParameterTypes(); + String[] consSig = new String[types.length]; + for (int i = 0; i < types.length; i++) + consSig[i] = types[i].getName(); + if (Arrays.equals(sig, consSig)) { + foundCons = cons; + break; + } + } + if (foundCons == null) { + throw new NoSuchMethodException( + "Constructor for " + className + " with argument types " + + Arrays.toString(sig)); + } + o = foundCons.newInstance(params); + } else if (classLoaderRepository) { + o = mbeanServer.instantiate(className, params, sig); + } else { + o = mbeanServer.instantiate(className, classLoader, params, sig); + } + + if (!(o instanceof EventForwarder)) { + throw new IllegalArgumentException( + className+" is not an EventForwarder class."); + } + + final EventForwarder forwarder = (EventForwarder)o; + final String clientId = UUID.randomUUID().toString(); + ClientInfo clientInfo = new ClientInfo(clientId, forwarder); + + clientInfoMap.put(clientId, clientInfo); + + forwarder.setClientId(clientId); + + if (logger.traceOn()) { + logger.trace("addClient", clientId); + } + + return clientId; + } + + public Integer[] getListenerIds(String clientId) + throws IOException, EventClientNotFoundException { + ClientInfo clientInfo = getClientInfo(clientId); + + if (clientInfo == null) { + throw new EventClientNotFoundException("The client is not found."); + } + + Map listenerInfoMap = clientInfo.listenerInfoMap; + synchronized (listenerInfoMap) { + Set ids = listenerInfoMap.keySet(); + return ids.toArray(new Integer[ids.size()]); + } + } + + /** + * {@inheritDoc} + * + *

      The execution of this method includes a call to + * {@link MBeanServer#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object)}.

      + */ + public Integer addListener(String clientId, + final ObjectName name, + NotificationFilter filter) + throws EventClientNotFoundException, InstanceNotFoundException { + + if (logger.traceOn()) { + logger.trace("addListener", ""); + } + + return getClientInfo(clientId).addListenerInfo(name, filter); + } + + /** + * {@inheritDoc} + * + *

      The execution of this method can include call to + * {@link MBeanServer#removeNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object)}.

      + */ + public void removeListenerOrSubscriber(String clientId, Integer listenerId) + throws InstanceNotFoundException, + ListenerNotFoundException, + EventClientNotFoundException, + IOException { + if (logger.traceOn()) { + logger.trace("removeListener", ""+listenerId); + } + getClientInfo(clientId).removeListenerInfo(listenerId); + } + + /** + * {@inheritDoc} + * + *

      The execution of this method includes a call to + * {@link MBeanServer#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object)} for + * every MBean matching {@code name}. If {@code name} is + * an {@code ObjectName} pattern, then the execution of this + * method will include a call to {@link MBeanServer#queryNames}.

      + */ + public Integer addSubscriber(String clientId, ObjectName name, + NotificationFilter filter) + throws EventClientNotFoundException, IOException { + if (logger.traceOn()) { + logger.trace("addSubscriber", ""); + } + return getClientInfo(clientId).subscribeListenerInfo(name, filter); + } + + public NotificationResult fetchNotifications(String clientId, + long startSequenceNumber, + int maxNotifs, + long timeout) + throws EventClientNotFoundException { + if (logger.traceOn()) { + logger.trace("fetchNotifications", "for "+clientId); + } + return getClientInfo(clientId).fetchNotifications(startSequenceNumber, + maxNotifs, + timeout); + } + + public void removeClient(String clientId) + throws EventClientNotFoundException { + if (clientId == null) + throw new EventClientNotFoundException("Null clientId"); + if (logger.traceOn()) { + logger.trace("removeClient", clientId); + } + ClientInfo ci = null; + ci = clientInfoMap.remove(clientId); + + if (ci == null) { + throw new EventClientNotFoundException("clientId is "+clientId); + } else { + ci.clean(); + } + } + + public long lease(String clientId, long timeout) + throws IOException, EventClientNotFoundException { + if (logger.traceOn()) { + logger.trace("lease", "for "+clientId); + } + return getClientInfo(clientId).lease(timeout); + } + + // ------------------------------------ + // private classes + // ------------------------------------ + private class ClientInfo { + String clientId; + EventBuffer buffer; + NotificationListener clientListener; + Map listenerInfoMap = + new HashMap(); + + ClientInfo(String clientId, EventForwarder forwarder) { + this.clientId = clientId; + this.forwarder = forwarder; + clientListener = + new ForwardingClientListener(listenerInfoMap, forwarder); + } + + Integer addOrSubscribeListenerInfo( + ObjectName name, NotificationFilter filter, boolean subscribe) + throws InstanceNotFoundException, IOException { + + final Integer listenerId = nextListenerId(); + AddedListener listenerInfo = new AddedListener( + listenerId, filter, name, subscribe); + if (subscribe) { + eventSubscriber.subscribe(name, + clientListener, + filter, + listenerInfo); + } else { + mbeanServer.addNotificationListener(name, + clientListener, + filter, + listenerInfo); + } + + synchronized(listenerInfoMap) { + listenerInfoMap.put(listenerId, listenerInfo); + } + + return listenerId; + } + + Integer addListenerInfo(ObjectName name, + NotificationFilter filter) throws InstanceNotFoundException { + try { + return addOrSubscribeListenerInfo(name, filter, false); + } catch (IOException e) { // can't happen + logger.warning( + "EventClientDelegate.addListenerInfo", + "unexpected exception", e); + throw new RuntimeException(e); + } + } + + Integer subscribeListenerInfo(ObjectName name, + NotificationFilter filter) throws IOException { + try { + return addOrSubscribeListenerInfo(name, filter, true); + } catch (InstanceNotFoundException e) { // can't happen + logger.warning( + "EventClientDelegate.subscribeListenerInfo", + "unexpected exception", e); + throw new RuntimeException(e); + } + } + + private final AtomicInteger nextListenerId = new AtomicInteger(); + + private Integer nextListenerId() { + return nextListenerId.getAndIncrement(); + } + + NotificationResult fetchNotifications(long startSequenceNumber, + int maxNotifs, + long timeout) { + + if (!(forwarder instanceof FetchingEventForwarder)) { + throw new IllegalArgumentException( + "This client is using Event Postal Service!"); + } + + return ((FetchingEventForwarder)forwarder). + fetchNotifications(startSequenceNumber, + maxNotifs, timeout); + } + + void removeListenerInfo(Integer listenerId) + throws InstanceNotFoundException, ListenerNotFoundException, IOException { + AddedListener listenerInfo; + synchronized(listenerInfoMap) { + listenerInfo = listenerInfoMap.remove(listenerId); + } + + if (listenerInfo == null) { + throw new ListenerNotFoundException("The listener is not found."); + } + + if (listenerInfo.subscription) { + eventSubscriber.unsubscribe(listenerInfo.name, + clientListener); + } else { + mbeanServer.removeNotificationListener(listenerInfo.name, + clientListener, + listenerInfo.filter, + listenerInfo); + } + } + + void clean(ObjectName name) { + synchronized(listenerInfoMap) { + for (Map.Entry entry : + listenerInfoMap.entrySet()) { + AddedListener li = entry.getValue(); + if (name.equals(li.name)) { + listenerInfoMap.remove(entry.getKey()); + } + } + } + } + + void clean() { + synchronized(listenerInfoMap) { + for (AddedListener li : listenerInfoMap.values()) { + try { + mbeanServer.removeNotificationListener(li.name, + clientListener); + } catch (Exception e) { + logger.trace("ClientInfo.clean", "removeNL", e); + } + } + listenerInfoMap.clear(); + } + + try { + forwarder.close(); + } catch (Exception e) { + logger.trace( + "ClientInfo.clean", "forwarder.close", e); + } + + if (leaseManager != null) { + leaseManager.stop(); + } + } + + long lease(long timeout) { + return leaseManager.lease(timeout); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof ClientInfo && + clientId.equals(((ClientInfo)o).clientId)) { + return true; + } + + return false; + } + + @Override + public int hashCode() { + return clientId.hashCode(); + } + + private EventForwarder forwarder = null; + + private final Runnable leaseExpiryCallback = new Runnable() { + public void run() { + try { + removeClient(clientId); + } catch (Exception e) { + logger.trace( + "ClientInfo.leaseExpiryCallback", "removeClient", e); + } + } + }; + + private LeaseManager leaseManager = new LeaseManager(leaseExpiryCallback); + } + + private class ForwardingClientListener implements NotificationListener { + public ForwardingClientListener(Map listenerInfoMap, + EventForwarder forwarder) { + this.listenerInfoMap = listenerInfoMap; + this.forwarder = forwarder; + } + + public void handleNotification(Notification n, Object o) { + if (n == null || (!(o instanceof AddedListener))) { + if (logger.traceOn()) { + logger.trace("ForwardingClientListener-handleNotification", + "received a unknown notif"); + } + return; + } + + AddedListener li = (AddedListener) o; + + if (checkListenerPermission(li.name,li.acc)) { + try { + forwarder.forward(n, li.listenerId); + } catch (Exception e) { + if (logger.traceOn()) { + logger.trace( + "ForwardingClientListener-handleNotification", + "forwarding failed.", e); + } + } + } + } + + private final Map listenerInfoMap; + private final EventForwarder forwarder; + } + + private class AddedListener { + final int listenerId; + final NotificationFilter filter; + final ObjectName name; + final boolean subscription; + final AccessControlContext acc; + + public AddedListener( + int listenerId, + NotificationFilter filter, + ObjectName name, + boolean subscription) { + this.listenerId = listenerId; + this.filter = filter; + this.name = name; + this.subscription = subscription; + acc = AccessController.getContext(); + } + } + + private class CleanListener implements NotificationListener { + public void handleNotification(Notification notification, + Object handback) { + if (notification instanceof MBeanServerNotification) { + if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals( + notification.getType())) { + final ObjectName name = + ((MBeanServerNotification)notification).getMBeanName(); + + final Collection list = + Collections.unmodifiableCollection(clientInfoMap.values()); + + for (ClientInfo ci : list) { + ci.clean(name); + } + } + + } + } + } + + // ------------------------------------------------- + // private method + // ------------------------------------------------- + private ClientInfo getClientInfo(String clientId) + throws EventClientNotFoundException { + ClientInfo clientInfo = null; + clientInfo = clientInfoMap.get(clientId); + + if (clientInfo == null) { + throw new EventClientNotFoundException("The client is not found."); + } + + return clientInfo; + } + + /** + * Explicitly check the MBeanPermission for + * the current access control context. + */ + private boolean checkListenerPermission(final ObjectName name, + final AccessControlContext acc) { + if (logger.traceOn()) { + logger.trace("checkListenerPermission", ""); + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + final String serverName = getMBeanServerName(); + + ObjectInstance oi = (ObjectInstance) + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public Object run() + throws InstanceNotFoundException { + return mbeanServer.getObjectInstance(name); + } + }); + + String classname = oi.getClassName(); + MBeanPermission perm = new MBeanPermission( + serverName, + classname, + null, + name, + "addNotificationListener"); + sm.checkPermission(perm, acc); + } catch (Exception e) { + if (logger.debugOn()) { + logger.debug("checkListenerPermission", "refused.", e); + } + return false; + } + } + 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 + // ------------------------------------ + private final MBeanServer mbeanServer; + private volatile String mbeanServerName = null; + private Map clientInfoMap = + new ConcurrentHashMap(); + + private final CleanListener cleanListener = new CleanListener(); + private final EventSubscriber eventSubscriber; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventClientDelegate"); + + private static final + Map> delegateMap = + new WeakHashMap>(); +} diff --git a/src/share/classes/javax/management/event/EventClientDelegateMBean.java b/src/share/classes/javax/management/event/EventClientDelegateMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..a9718a931dca6ae6e98bfa7a007515a720cf3eff --- /dev/null +++ b/src/share/classes/javax/management/event/EventClientDelegateMBean.java @@ -0,0 +1,318 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.NotificationFilter; +import javax.management.ObjectName; +import javax.management.remote.NotificationResult; + +/** + *

      This interface specifies necessary methods on the MBean server + * side for a JMX remote client to manage its notification listeners as + * if they are local. + * Users do not usually work directly with this MBean; instead, the {@link + * EventClient} class is designed to be used directly by the user.

      + * + *

      A default implementation of this interface can be added to an MBean + * Server in one of several ways.

      + * + *
        + *
      • The most usual is to insert an {@link + * javax.management.remote.MBeanServerForwarder MBeanServerForwarder} between + * the {@linkplain javax.management.remote.JMXConnectorServer Connector Server} + * and the MBean Server, that will intercept accesses to the Event Client + * Delegate MBean and treat them as the real MBean would. This forwarder is + * inserted by default with the standard RMI Connector Server, and can also + * be created explicitly using {@link EventClientDelegate#newForwarder()}. + * + *

      • A variant on the above is to replace the MBean Server that is + * used locally with a forwarder as described above. Since + * {@code MBeanServerForwarder} extends {@code MBeanServer}, you can use + * a forwarder anywhere you would have used the original MBean Server. The + * code to do this replacement typically looks something like this:

        + * + *
        + * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  // or whatever
        + * MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
        + * mbsf.setMBeanServer(mbs);
        + * mbs = mbsf;
        + * // now use mbs just as you did before, but it will have an EventClientDelegate
        + * 
        + * + *
      • The final way is to create an instance of {@link EventClientDelegate} + * and register it in the MBean Server under the standard {@linkplain + * #OBJECT_NAME name}:

        + * + *
        + * MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  // or whatever
        + * EventClientDelegate ecd = EventClientDelegate.getEventClientDelegate(mbs);
        + * mbs.registerMBean(ecd, EventClientDelegateMBean.OBJECT_NAME);
        + * 
        + * 
      + * + * @since JMX 2.0 + */ +public interface EventClientDelegateMBean { + /** + * The string representation of {@link #OBJECT_NAME}. + */ + // This shouldn't really be necessary but an apparent javadoc bug + // meant that the {@value} tags didn't work if this was a + // field in EventClientDelegate, even a public field. + public static final String OBJECT_NAME_STRING = + "javax.management.event:type=EventClientDelegate"; + + /** + * The standard ObjectName used to register the default + * EventClientDelegateMBean. The name is + * {@value #OBJECT_NAME_STRING}. + */ + public final static ObjectName OBJECT_NAME = + ObjectName.valueOf(OBJECT_NAME_STRING); + + /** + * A unique listener identifier specified for an EventClient. + * Any notification associated with this id is intended for + * the EventClient which receives the notification, rather than + * a listener added using that EventClient. + */ + public static final int EVENT_CLIENT_LISTENER_ID = -100; + + /** + * Adds a new client to the EventClientDelegateMBean with + * a user-specified + * {@link EventForwarder} to forward notifications to the client. The + * EventForwarder is created by calling + * {@link javax.management.MBeanServer#instantiate(String, Object[], + * String[])}. + * + * @param className The class name used to create an + * {@code EventForwarder}. + * @param params An array containing the parameters of the constructor to + * be invoked. + * @param sig An array containing the signature of the constructor to be + * invoked + * @return A client identifier. + * @exception IOException Reserved for a remote call to throw on the client + * side. + * @exception MBeanException An exception thrown when creating the user + * specified EventForwarder. + */ + public String addClient(String className, Object[] params, String[] sig) + throws IOException, MBeanException; + + /** + * Adds a new client to the EventClientDelegateMBean with + * a user-specified + * {@link EventForwarder} to forward notifications to the client. The + * EventForwarder is created by calling + * {@link javax.management.MBeanServer#instantiate(String, ObjectName, + * Object[], String[])}. A user-specified class loader is used to create + * this EventForwarder. + * + * @param className The class name used to create an + * {@code EventForwarder}. + * @param classLoader An ObjectName registered as a + * ClassLoader MBean. + * @param params An array containing the parameters of the constructor to + * be invoked. + * @param sig An array containing the signature of the constructor to be + * invoked + * @return A client identifier. + * @exception IOException Reserved for a remote call to throw on the client + * side. + * @exception MBeanException An exception thrown when creating the user + * specified EventForwarder. + */ + public String addClient(String className, + ObjectName classLoader, + Object[] params, + String[] sig) throws IOException, MBeanException; + + /** + * Removes an added client. Calling this method will remove all listeners + * added with the client. + * + * @exception EventClientNotFoundException If the {@code clientId} is + * not found. + * @exception IOException Reserved for a remote call to throw on the client + * side. + */ + public void removeClient(String clientID) + throws EventClientNotFoundException, IOException; + + /** + * Returns the identifiers of listeners added or subscribed to with the + * specified client identifier. + *

      If no listener is currently registered with the client, an empty + * array is returned. + * @param clientID The client identifier with which the listeners are + * added or subscribed to. + * @return An array of listener identifiers. + * @exception EventClientNotFoundException If the {@code clientId} is + * not found. + * @exception IOException Reserved for a remote call to throw on the client + * side. + */ + public Integer[] getListenerIds(String clientID) + throws EventClientNotFoundException, IOException; + + /** + * Adds a listener to receive notifications from an MBean and returns + * a non-negative integer as the identifier of the listener. + *

      This method is called by an {@link EventClient} to implement the + * method {@link EventClient#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object)}. + * + * @param name The name of the MBean onto which the listener should be added. + * @param filter The filter object. If {@code filter} is null, + * no filtering will be performed before handling notifications. + * @param clientId The client identifier with which the listener is added. + * @return A listener identifier. + * @throws EventClientNotFoundException Thrown if the {@code clientId} is + * not found. + * @throws InstanceNotFoundException Thrown if the MBean is not found. + * @throws IOException Reserved for a remote call to throw on the client + * side. + */ + public Integer addListener(String clientId, + ObjectName name, + NotificationFilter filter) + throws InstanceNotFoundException, EventClientNotFoundException, + IOException; + + + /** + *

      Subscribes a listener to receive notifications from an MBean or a + * set of MBeans represented by an {@code ObjectName} pattern. (It is + * not an error if no MBeans match the pattern at the time this method is + * called.)

      + * + *

      Returns a non-negative integer as the identifier of the listener.

      + * + *

      This method is called by an {@link EventClient} to execute its + * method {@link EventClient#subscribe(ObjectName, NotificationListener, + * NotificationFilter, Object)}.

      + * + * @param clientId The remote client's identifier. + * @param name The name of an MBean or an {@code ObjectName} pattern + * representing a set of MBeans to which the listener should listen. + * @param filter The filter object. If {@code filter} is null, no + * filtering will be performed before notifications are handled. + * + * @return A listener identifier. + * + * @throws IllegalArgumentException If the {@code name} or + * {@code listener} is null. + * @throws EventClientNotFoundException If the client ID is not found. + * @throws IOException Reserved for a remote client to throw if + * an I/O error occurs. + * + * @see EventConsumer#subscribe(ObjectName, NotificationListener, + * NotificationFilter,Object) + * @see #removeListenerOrSubscriber(String, Integer) + */ + public Integer addSubscriber(String clientId, ObjectName name, + NotificationFilter filter) + throws EventClientNotFoundException, IOException; + + /** + * Removes a listener, to stop receiving notifications. + *

      This method is called by an {@link EventClient} to execute its + * methods {@link EventClient#removeNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object)}, + * {@link EventClient#removeNotificationListener(ObjectName, + * NotificationListener)}, and {@link EventClient#unsubscribe}. + * + * @param clientId The client identifier with which the listener was added. + * @param listenerId The listener identifier to be removed. This must be + * an identifier returned by a previous {@link #addListener addListener} + * or {@link #addSubscriber addSubscriber} call. + * + * @throws InstanceNotFoundException if the MBean on which the listener + * was added no longer exists. + * @throws ListenerNotFoundException if there is no listener with the + * given {@code listenerId}. + * @throws EventClientNotFoundException if the {@code clientId} is + * not found. + * @throws IOException Reserved for a remote call to throw on the client + * side. + */ + public void removeListenerOrSubscriber(String clientId, Integer listenerId) + throws InstanceNotFoundException, ListenerNotFoundException, + EventClientNotFoundException, IOException; + + /** + * Called by a client to fetch notifications that are to be sent to its + * listeners. + * + * @param clientId The client's identifier. + * @param startSequenceNumber The first sequence number to + * consider. + * @param timeout The maximum waiting time. + * @param maxNotifs The maximum number of notifications to return. + * + * @throws EventClientNotFoundException Thrown if the {@code clientId} is + * not found. + * @throws IllegalArgumentException if the client was {@linkplain + * #addClient(String, Object[], String[]) added} with an {@link + * EventForwarder} that is not a {@link FetchingEventForwarder}. + * @throws IOException Reserved for a remote call to throw on the client + * side. + */ + public NotificationResult fetchNotifications(String clientId, + long startSequenceNumber, + int maxNotifs, + long timeout) + throws EventClientNotFoundException, IOException; + + /** + * An {@code EventClient} calls this method to keep its {@code clientId} + * alive in this MBean. The client will be removed if the lease times out. + * + * @param clientId The client's identifier. + * @param timeout The time in milliseconds by which the lease is to be + * extended. The value zero has no special meaning, so it will cause the + * lease to time out immediately. + * + * @return The new lifetime of the lease in milliseconds. This may be + * different from the requested time. + * + * @throws EventClientNotFoundException if the {@code clientId} is + * not found. + * @throws IOException reserved for a remote call to throw on the client + * side. + * @throws IllegalArgumentException if {@code clientId} is null or + * {@code timeout} is negative. + */ + public long lease(String clientId, long timeout) + throws IOException, EventClientNotFoundException; +} diff --git a/src/share/classes/javax/management/event/EventClientNotFoundException.java b/src/share/classes/javax/management/event/EventClientNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..22f22d7313f55fa606dd5a5940912a1eaf511fea --- /dev/null +++ b/src/share/classes/javax/management/event/EventClientNotFoundException.java @@ -0,0 +1,79 @@ +/* + * 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 javax.management.event; + +import javax.management.JMException; + +/** + * Thrown if an event client identifier is unknown. + */ +public class EventClientNotFoundException extends JMException { + + /* Serial version */ + private static final long serialVersionUID = -3910667345840643089L; + + /** + *Constructs a {@code ClientNotFoundException} without a detail message. + */ + public EventClientNotFoundException() { + super(); + } + + /** + * Constructs a {@code ClientNotFoundException} with the specified detail message. + * @param message The message. + */ + public EventClientNotFoundException(String message) { + super(message); + } + + /** + * Constructs a {@code ClientNotFoundException} with the specified detail message + * and cause. + * + * @param message The message. + * @param cause The cause (which is saved for later retrieval by the + * {@code Throwable.getCause()} method). A null value is permitted, and indicates + * that the cause is non-existent or unknown. + */ + public EventClientNotFoundException(String message, Throwable cause) { + super(message); + + initCause(cause); + } + + /** + * Constructs a new exception with the specified cause. + * @param cause The cause (which is saved for later retrieval by the + * {@code Throwable.getCause()} method). A null value is permitted, and indicates + * that the cause is non-existent or unknown. + */ + public EventClientNotFoundException(Throwable cause) { + super(); + + initCause(cause); + } +} diff --git a/src/share/classes/javax/management/event/EventConsumer.java b/src/share/classes/javax/management/event/EventConsumer.java new file mode 100644 index 0000000000000000000000000000000000000000..c2617764e86a58e8135e37a9c3ac35e81adc8caa --- /dev/null +++ b/src/share/classes/javax/management/event/EventConsumer.java @@ -0,0 +1,98 @@ +/* + * 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 javax.management.event; + +import java.io.IOException; +import javax.management.ListenerNotFoundException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +/** + * This interface specifies methods to subscribe a listener to receive events + * from an MBean or a set of MBeans. The MBeans can already be registered in + * an MBean server, or they can be pending registration, or they can be MBeans + * that will never be registered, or they can be MBeans that will be registered + * then unregistered. + * @since JMX 2.0 + */ +public interface EventConsumer { + /** + *

      Subscribes a listener to receive events from an MBean or a set + * of MBeans represented by an {@code ObjectName} pattern.

      + * + *

      An event emitted by an MBean is forwarded to every listener that was + * subscribed with the name of that MBean, or with a pattern that matches + * that name.

      + * + * @param name The name of an MBean or an {@code ObjectName} pattern + * representing a set of MBeans to which the listener should listen. + * @param listener The listener object that will handle the + * notifications emitted by the MBeans. + * @param filter The filter object. If {@code filter} is null, no + * filtering will be performed before notification handling. + * @param handback The context to be sent to the listener when a + * notification is emitted. + * + * @throws IllegalArgumentException If the {@code name} or + * {@code listener} is null. + * @throws IOException for a remote client, thrown if + * an I/O error occurs. + * @see #unsubscribe(ObjectName, NotificationListener) + */ + public void subscribe(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IOException; + + /** + *

      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}. 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}, perhaps with different filters or handbacks, then all such + * listeners are 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}. + * @throws IOException for a remote client, thrown if + * an I/O error occurs. + * + * @see #subscribe + */ + public void unsubscribe(ObjectName name, + NotificationListener listener) + throws ListenerNotFoundException, IOException; +} diff --git a/src/share/classes/javax/management/event/EventForwarder.java b/src/share/classes/javax/management/event/EventForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..3dff0a7bcf185294e2957c794d15e2be474f79c0 --- /dev/null +++ b/src/share/classes/javax/management/event/EventForwarder.java @@ -0,0 +1,63 @@ +/* + * 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 javax.management.event; + +import java.io.IOException; +import javax.management.Notification; + +/** + * This interface can be used to specify a custom forwarding mechanism for + * {@code EventClientDelegateMBean} to forward events to the client. + * + * @see Custom notification + * transports + */ +public interface EventForwarder { + /** + * Forwards a notification. + * @param n The notification to be forwarded to a remote listener. + * @param listenerId The identifier of the listener to receive the notification. + * @throws IOException If it is closed or an I/O error occurs. + */ + public void forward(Notification n, Integer listenerId) + throws IOException; + + /** + * Informs the {@code EventForwarder} to shut down. + *

      After this method is called, any call to the method + * {@link #forward forward(Notification, Integer)} may get an {@code IOException}. + * @throws IOException If an I/O error occurs. + */ + public void close() throws IOException; + + /** + * Sets an event client identifier created by {@link EventClientDelegateMBean}. + *

      This method will be called just after this {@code EventForwarder} + * is constructed and before calling the {@code forward} method to forward any + * notifications. + */ + public void setClientId(String clientId) throws IOException; +} diff --git a/src/share/classes/javax/management/event/EventReceiver.java b/src/share/classes/javax/management/event/EventReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..7cdd38b7fb992db74c5637afb64d50f4d8228f2d --- /dev/null +++ b/src/share/classes/javax/management/event/EventReceiver.java @@ -0,0 +1,77 @@ +/* + * 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 javax.management.event; + +import javax.management.remote.NotificationResult; + +/** + * An object implementing this interface is passed by an {@link EventClient} + * to its {@link EventRelay}, to allow the {@code EventRelay} to communicate + * received notifications to the {@code EventClient}. + * + * @see Custom notification + * transports + */ +public interface EventReceiver { + + /** + * This method is implemented by {@code EventClient} as a callback to + * receive notifications from {@code EventRelay}. + *

      The notifications are included in an object specified by the class + * {@link NotificationResult}. In + * addition to a set of notifications, the class object also contains two values: + * {@code earliestSequenceNumber} and {@code nextSequenceNumber}. + * These two values determine whether any notifications have been lost. + * The {@code nextSequenceNumber} value of the last time is compared + * to the received value {@code earliestSequenceNumber}. If the + * received {@code earliesSequenceNumber} is greater, than the difference + * signifies the number of lost notifications. A sender should + * ensure the sequence of notifications sent, meaning that the value + * {@code earliestSequenceNumber} of the next return should be always equal to + * or greater than the value {@code nextSequenceNumber} of the last return. + * + * @param nr the received notifications and sequence numbers. + */ + public void receive(NotificationResult nr); + + /** + * Allows the {@link EventRelay} to report when it receives an unexpected + * exception, which may be fatal and which may make it stop receiving + * notifications. + * + * @param t The unexpected exception received while {@link EventRelay} was running. + */ + public void failed(Throwable t); + + /** + * Allows the {@link EventRelay} to report when it receives an unexpected + * exception that is not fatal. For example, a notification received is not + * serializable or its class is not found. + * + * @param e The unexpected exception received while notifications are being received. + */ + public void nonFatal(Exception e); +} diff --git a/src/share/classes/javax/management/event/EventRelay.java b/src/share/classes/javax/management/event/EventRelay.java new file mode 100644 index 0000000000000000000000000000000000000000..d723bb04c4e535864a595a311c46aa5c00f8795b --- /dev/null +++ b/src/share/classes/javax/management/event/EventRelay.java @@ -0,0 +1,80 @@ +/* + * 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 javax.management.event; + +import java.io.IOException; +import java.util.concurrent.Executors; // for javadoc +import java.util.concurrent.ScheduledFuture; + +/** + * This interface is used to specify a way to receive + * notifications from a remote MBean server and then to forward the notifications + * to an {@link EventClient}. + * + * @see Custom notification + * transports + */ +public interface EventRelay { + /** + * Returns an identifier that is used by this {@code EventRelay} to identify + * the client when communicating with the {@link EventClientDelegateMBean}. + *

      This identifier is obtained by calling + * {@link EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient}. + *

      It is the {@code EventRelay} that calls {@code EventClientDelegateMBean} to obtain + * the client identifier because it is the {@code EventRelay} that decides + * how to get notifications from the {@code EventClientDelegateMBean}, + * by creating the appropriate {@link EventForwarder}. + * + * @return A client identifier. + * @throws IOException If an I/O error occurs when communicating with + * the {@code EventClientDelegateMBean}. + */ + public String getClientId() throws IOException; + + /** + * This method is called by {@link EventClient} to register a callback + * to receive notifications from an {@link EventClientDelegateMBean} object. + * A {@code null} value is allowed, which means that the {@code EventClient} suspends + * reception of notifications, so that the {@code EventRelay} can decide to stop receiving + * notifications from its {@code EventForwarder}. + * + * @param eventReceiver An {@link EventClient} callback to receive + * events. + */ + public void setEventReceiver(EventReceiver eventReceiver); + + /** + * Stops receiving and forwarding notifications and performs any necessary + * cleanup. After calling this method, the {@link EventClient} will never + * call any other methods of this object. + * + * @throws IOException If an I/O exception appears. + * + * @see EventClient#close + */ + public void stop() throws IOException; +} diff --git a/src/share/classes/javax/management/event/EventSubscriber.java b/src/share/classes/javax/management/event/EventSubscriber.java new file mode 100644 index 0000000000000000000000000000000000000000..9948810bfeb52e03fcb40b8c06005014c19d7b53 --- /dev/null +++ b/src/share/classes/javax/management/event/EventSubscriber.java @@ -0,0 +1,377 @@ +/* + * 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.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.Query; +import javax.management.QueryEval; +import javax.management.QueryExp; + +/** + *

      An object that can be used to subscribe for notifications from all MBeans + * in an MBeanServer that match a pattern. For example, to listen for + * notifications from all MBeans in the MBeanServer {@code mbs} that match + * {@code com.example:type=Controller,name=*} you could write:

      + * + *
      + * EventSubscriber subscriber = EventSubscriber.getEventSubscriber(mbs);
      + * ObjectName pattern = new ObjectName("com.example:type=Controller,name=*");
      + * NotificationListener myListener = ...;
      + * NotificationFilter myFilter = null;  // or whatever
      + * Object handback = null;              // or whatever
      + * subscriber.subscribe(pattern, myListener, myFilter, myHandback);
      + * 
      + */ +public class EventSubscriber implements EventConsumer { + /** + * Returns an {@code EventSubscriber} object to subscribe for notifications + * from the given {@code MBeanServer}. Calling this method more + * than once with the same parameter may or may not return the same object. + * + * @param mbs the {@code MBeanServer} containing MBeans to be subscribed to. + * @return An {@code EventSubscriber} object. + * + * @throws NullPointerException if mbs is null. + */ + public static EventSubscriber getEventSubscriber(MBeanServer mbs) { + if (mbs == null) + throw new NullPointerException("Null MBeanServer"); + + EventSubscriber eventSubscriber = null; + synchronized (subscriberMap) { + final WeakReference wrf = subscriberMap.get(mbs); + eventSubscriber = (wrf == null) ? null : wrf.get(); + + if (eventSubscriber == null) { + eventSubscriber = new EventSubscriber(mbs); + + subscriberMap.put(mbs, + new WeakReference(eventSubscriber)); + } + } + + return eventSubscriber; + } + + private EventSubscriber(final MBeanServer mbs) { + logger.trace("EventSubscriber", "create a new one"); + this.mbeanServer = mbs; + + Exception x = null; + try { + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public Void run() throws Exception { + mbs.addNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, + myMBeanServerListener, null, null); + return null; + } + }); + } catch (PrivilegedActionException ex) { + x = ex.getException(); + } + + // handle possible exceptions. + // + // Fail unless x is null or x is instance of InstanceNotFoundException + // The logic here is that if the MBeanServerDelegate is not present, + // we will assume that the connection will not emit any + // MBeanServerNotifications. + // + if (x != null && !(x instanceof InstanceNotFoundException)) { + if (x instanceof RuntimeException) + throw (RuntimeException) x; + throw new RuntimeException( + "Can't add listener to MBean server delegate: " + x, x); + } + } + + public void subscribe(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IOException { + + if (logger.traceOn()) + logger.trace("subscribe", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new IllegalArgumentException("Null listener"); + + final MyListenerInfo li = new MyListenerInfo(listener, filter, handback); + List list; + + Map> map; + Set names; + if (name.isPattern()) { + map = patternSubscriptionMap; + names = mbeanServer.queryNames(name, notificationBroadcasterExp); + } else { + map = exactSubscriptionMap; + names = Collections.singleton(name); + } + + synchronized (map) { + list = map.get(name); + if (list == null) { + list = new ArrayList(); + map.put(name, list); + } + list.add(li); + } + + for (ObjectName mbeanName : names) { + try { + mbeanServer.addNotificationListener(mbeanName, + listener, + filter, + handback); + } catch (Exception e) { + logger.fine("subscribe", "addNotificationListener", e); + } + } + } + + public void unsubscribe(ObjectName name, + NotificationListener listener) + throws ListenerNotFoundException, IOException { + if (logger.traceOn()) + logger.trace("unsubscribe", "" + name); + + if (name == null) + throw new IllegalArgumentException("Null MBean name"); + + if (listener == null) + throw new ListenerNotFoundException(); + + Map> map; + Set names; + + if (name.isPattern()) { + map = patternSubscriptionMap; + names = mbeanServer.queryNames(name, notificationBroadcasterExp); + } else { + map = exactSubscriptionMap; + names = Collections.singleton(name); + } + + List toRemove = new ArrayList(); + synchronized (map) { + List list = map.get(name); + if (list == null) { + throw new ListenerNotFoundException(); + } + + for (MyListenerInfo info : list) { + if (info.listener == listener) { + toRemove.add(info); + } + } + + if (toRemove.isEmpty()) { + throw new ListenerNotFoundException(); + } + + for (MyListenerInfo info : toRemove) { + list.remove(info); + } + + if (list.isEmpty()) + map.remove(name); + } + + for (ObjectName mbeanName : names) { + for (MyListenerInfo i : toRemove) { + try { + mbeanServer.removeNotificationListener(mbeanName, + i.listener, i.filter, i.handback); + } catch (Exception e) { + logger.fine("unsubscribe", "removeNotificationListener", e); + } + } + } + } + + // --------------------------------- + // private stuff + // --------------------------------- + // used to receive MBeanServerNotification + private NotificationListener myMBeanServerListener = + new NotificationListener() { + public void handleNotification(Notification n, Object hb) { + if (!(n instanceof MBeanServerNotification) || + !MBeanServerNotification. + REGISTRATION_NOTIFICATION.equals(n.getType())) { + return; + } + + final ObjectName name = + ((MBeanServerNotification)n).getMBeanName(); + try { + if (!mbeanServer.isInstanceOf(name, + NotificationBroadcaster.class.getName())) { + return; + } + } catch (Exception e) { + // The only documented exception is InstanceNotFoundException, + // which could conceivably happen if the MBean is unregistered + // immediately after being registered. + logger.fine("myMBeanServerListener.handleNotification", + "isInstanceOf", e); + return; + } + + final List listeners = new ArrayList(); + + // If there are subscribers for the exact name that has just arrived + // then add their listeners to the list. + synchronized (exactSubscriptionMap) { + List exactListeners = exactSubscriptionMap.get(name); + if (exactListeners != null) + listeners.addAll(exactListeners); + } + + // For every subscription pattern that matches the new name, + // add all the listeners for that pattern to "listeners". + synchronized (patternSubscriptionMap) { + for (ObjectName on : patternSubscriptionMap.keySet()) { + if (on.apply(name)) { + listeners.addAll(patternSubscriptionMap.get(on)); + } + } + } + + // Add all the listeners just found to the new MBean. + for (MyListenerInfo li : listeners) { + try { + mbeanServer.addNotificationListener( + name, + li.listener, + li.filter, + li.handback); + } catch (Exception e) { + logger.fine("myMBeanServerListener.handleNotification", + "addNotificationListener", e); + } + } + } + }; + + private static class MyListenerInfo { + public final NotificationListener listener; + public final NotificationFilter filter; + public final Object handback; + + public MyListenerInfo(NotificationListener listener, + NotificationFilter filter, + Object handback) { + + if (listener == null) + throw new IllegalArgumentException("Null listener"); + + this.listener = listener; + this.filter = filter; + this.handback = handback; + } + } + + // --------------------------------- + // private methods + // --------------------------------- + // --------------------------------- + // private variables + // --------------------------------- + private final MBeanServer mbeanServer; + + private final Map> exactSubscriptionMap = + new HashMap>(); + private final Map> patternSubscriptionMap = + new HashMap>(); + + + + // trace issues + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "EventSubscriber"); + + // Compatibility code, so we can run on Tiger: + private static final QueryExp notificationBroadcasterExp; + static { + QueryExp broadcasterExp; + try { + final Method m = Query.class.getMethod("isInstanceOf", + new Class[] {String.class}); + broadcasterExp = (QueryExp)m.invoke(Query.class, + new Object[] {NotificationBroadcaster.class.getName()}); + } catch (Exception e) { + broadcasterExp = new BroadcasterQueryExp(); + } + notificationBroadcasterExp = broadcasterExp; + } + private static class BroadcasterQueryExp extends QueryEval implements QueryExp { + private static final long serialVersionUID = 1234L; + public boolean apply(ObjectName name) { + try { + return getMBeanServer().isInstanceOf( + name, NotificationBroadcaster.class.getName()); + } catch (Exception e) { + return false; + } + } + } + + private static final + Map> subscriberMap = + new WeakHashMap>(); +} diff --git a/src/share/classes/javax/management/event/FetchingEventForwarder.java b/src/share/classes/javax/management/event/FetchingEventForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..fd0ae6de3e21dcc0409e44c212a4c2b24bf874e9 --- /dev/null +++ b/src/share/classes/javax/management/event/FetchingEventForwarder.java @@ -0,0 +1,151 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.event.EventBuffer; +import com.sun.jmx.remote.util.ClassLogger; +import java.io.IOException; +import java.util.List; +import javax.management.Notification; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; + +/** + * This class is used by {@link FetchingEventRelay}. When + * {@link FetchingEventRelay} calls {@link + * EventClientDelegateMBean#addClient(String, Object[], String[])} to get a new + * client identifier, it uses + * this class name as the first argument to ask {@code EventClientDelegateMBean} + * to create an object of this class. + * Then {@code EventClientDelegateMBean} forwards client notifications + * to this object. + * When {@link FetchingEventRelay} calls + * {@link EventClientDelegateMBean#fetchNotifications(String, long, int, long)} + * to fetch notifications, the {@code EventClientDelegateMBean} will forward + * the call to this object. + */ +public class FetchingEventForwarder implements EventForwarder { + + /** + * Construct a new {@code FetchingEventForwarder} with the given + * buffer size. + * @param bufferSize the size of the buffer that will store notifications + * until they have been fetched and acknowledged by the client. + */ + public FetchingEventForwarder(int bufferSize) { + if (logger.traceOn()) { + logger.trace("Constructor", "buffer size is "+bufferSize); + } + + buffer = new EventBuffer(bufferSize); + this.bufferSize = bufferSize; + } + + /** + * Called by an {@link EventClientDelegateMBean} to forward a user call + * {@link EventClientDelegateMBean#fetchNotifications(String, long, int, long)}. + * A call of this method is considered to acknowledge reception of all + * notifications whose sequence numbers are less the + * {@code startSequenceNumber}, so all these notifications can be deleted + * from this object. + * + * @param startSequenceNumber The first sequence number to + * consider. + * @param timeout The maximum waiting time in milliseconds. + * If no notifications have arrived after this period of time, the call + * will return with an empty list of notifications. + * @param maxNotifs The maximum number of notifications to return. + */ + public NotificationResult fetchNotifications(long startSequenceNumber, + int maxNotifs, long timeout) { + if (logger.traceOn()) { + logger.trace("fetchNotifications", + startSequenceNumber+" "+ + maxNotifs+" "+ + timeout); + } + + return buffer.fetchNotifications(startSequenceNumber, + timeout, + maxNotifs); + } + + /** + * {@inheritDoc} + * In this implementation, the notification is stored in the local buffer + * waiting for {@link #fetchNotifications fetchNotifications} to pick + * it up. + */ + public void forward(Notification n, Integer listenerId) throws IOException { + if (logger.traceOn()) { + logger.trace("forward", n+" "+listenerId); + } + + buffer.add(new TargetedNotification(n, listenerId)); + } + + public void close() throws IOException { + if (logger.traceOn()) { + logger.trace("close", ""); + } + + buffer.close(); + } + + public void setClientId(String clientId) throws IOException { + if (logger.traceOn()) { + logger.trace("setClientId", clientId); + } + this.clientId = clientId; + } + + /** + * Sets a user specific list to save notifications in server side + * before forwarding to an FetchingEventRelay in client side. + *

      This method should be called before any notification is + * forwarded to this forwader. + * + * @param list a user specific list to save notifications + */ + protected void setList(List list) { + if (logger.traceOn()) { + logger.trace("setList", ""); + } + + if (clientId == null) { + buffer = new EventBuffer(bufferSize, list); + } else { + throw new IllegalStateException(); + } + } + + private EventBuffer buffer; + private int bufferSize; + private String clientId; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "FetchingEventForwarder"); +} diff --git a/src/share/classes/javax/management/event/FetchingEventRelay.java b/src/share/classes/javax/management/event/FetchingEventRelay.java new file mode 100644 index 0000000000000000000000000000000000000000..2a456ec44c7b919641a6647fe702c6af1698875a --- /dev/null +++ b/src/share/classes/javax/management/event/FetchingEventRelay.java @@ -0,0 +1,383 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.event.DaemonThreadFactory; +import com.sun.jmx.event.RepeatedSingletonJob; +import com.sun.jmx.remote.util.ClassLogger; +import java.io.IOException; +import java.io.NotSerializableException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import javax.management.MBeanException; +import javax.management.remote.NotificationResult; + +/** + * This class is an implementation of the {@link EventRelay} interface. It calls + * {@link EventClientDelegateMBean#fetchNotifications + * fetchNotifications(String, long, int, long)} to get + * notifications and then forwards them to an {@link EventReceiver} object. + * + * @since JMX 2.0 + */ +public class FetchingEventRelay implements EventRelay { + /** + * The default buffer size: {@value #DEFAULT_BUFFER_SIZE}. + */ + public final static int DEFAULT_BUFFER_SIZE = 1000; + + /** + * The default waiting timeout: {@value #DEFAULT_WAITING_TIMEOUT} + * in millseconds when fetching notifications from + * an {@code EventClientDelegateMBean}. + */ + public final static long DEFAULT_WAITING_TIMEOUT = 60000; + + /** + * The default maximum notifications to fetch every time: + * {@value #DEFAULT_MAX_NOTIFICATIONS}. + */ + public final static int DEFAULT_MAX_NOTIFICATIONS = DEFAULT_BUFFER_SIZE; + + /** + * Constructs a default {@code FetchingEventRelay} object by using the default + * configuration: {@code DEFAULT_BUFFER_SIZE}, {@code DEFAULT_WAITING_TIMEOUT} + * {@code DEFAULT_MAX_NOTIFICATIONS}. A single thread is created + * to do fetching. + * + * @param delegate The {@code EventClientDelegateMBean} to work with. + * @throws IOException If failed to work with the {@code delegate}. + * @throws MBeanException if unable to add a client to the remote + * {@code EventClientDelegateMBean} (see {@link + * EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient}). + * @throws IllegalArgumentException If {@code delegate} is {@code null}. + */ + public FetchingEventRelay(EventClientDelegateMBean delegate) + throws IOException, MBeanException { + this(delegate, null); + } + + /** + * Constructs a {@code FetchingEventRelay} object by using the default + * configuration: {@code DEFAULT_BUFFER_SIZE}, {@code DEFAULT_WAITING_TIMEOUT} + * {@code DEFAULT_MAX_NOTIFICATIONS}, with a user-specific executor to do + * the fetching. + * + * @param delegate The {@code EventClientDelegateMBean} to work with. + * @param executor Used to do the fetching. A new thread is created if + * {@code null}. + * @throws IOException If failed to work with the {@code delegate}. + * @throws MBeanException if unable to add a client to the remote + * {@code EventClientDelegateMBean} (see {@link + * EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient}). + * @throws IllegalArgumentException If {@code delegate} is {@code null}. + */ + public FetchingEventRelay(EventClientDelegateMBean delegate, + Executor executor) throws IOException, MBeanException { + this(delegate, + DEFAULT_BUFFER_SIZE, + DEFAULT_WAITING_TIMEOUT, + DEFAULT_MAX_NOTIFICATIONS, + executor); + } + + /** + * Constructs a {@code FetchingEventRelay} object with user-specific + * configuration and executor to fetch notifications via the + * {@link EventClientDelegateMBean}. + * + * @param delegate The {@code EventClientDelegateMBean} to work with. + * @param bufferSize The buffer size for saving notifications in + * {@link EventClientDelegateMBean} before they are fetched. + * @param timeout The waiting time in millseconds when fetching + * notifications from an {@code EventClientDelegateMBean}. + * @param maxNotifs The maximum notifications to fetch every time. + * @param executor Used to do the fetching. A new thread is created if + * {@code null}. + * @throws IOException if failed to communicate with the {@code delegate}. + * @throws MBeanException if unable to add a client to the remote + * {@code EventClientDelegateMBean} (see {@link + * EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient}). + * @throws IllegalArgumentException If {@code delegate} is {@code null}. + */ + public FetchingEventRelay(EventClientDelegateMBean delegate, + int bufferSize, + long timeout, + int maxNotifs, + Executor executor) throws IOException, MBeanException { + this(delegate, + bufferSize, + timeout, + maxNotifs, + executor, + FetchingEventForwarder.class.getName(), + new Object[] {bufferSize}, + new String[] {int.class.getName()}); + } + + /** + * Constructs a {@code FetchingEventRelay} object with user-specific + * configuration and executor to fetch notifications via the + * {@link EventClientDelegateMBean}. + * + * @param delegate The {@code EventClientDelegateMBean} to work with. + * @param bufferSize The buffer size for saving notifications in + * {@link EventClientDelegateMBean} before they are fetched. + * @param timeout The waiting time in millseconds when fetching + * notifications from an {@code EventClientDelegateMBean}. + * @param maxNotifs The maximum notifications to fetch every time. + * @param executor Used to do the fetching. + * @param forwarderName the class name of a user specific EventForwarder + * to create in server to forward notifications to this object. The class + * should be a subclass of the class {@link FetchingEventForwarder}. + * @param params the parameters passed to create {@code forwarderName} + * @param sig the signature of the {@code params} + * @throws IOException if failed to communicate with the {@code delegate}. + * @throws MBeanException if unable to add a client to the remote + * {@code EventClientDelegateMBean} (see {@link + * EventClientDelegateMBean#addClient(String, Object[], String[]) + * EventClientDelegateMBean.addClient}). + * @throws IllegalArgumentException if {@code bufferSize} or + * {@code maxNotifs} is less than {@code 1} + * @throws NullPointerException if {@code delegate} is {@code null}. + */ + public FetchingEventRelay(EventClientDelegateMBean delegate, + int bufferSize, + long timeout, + int maxNotifs, + Executor executor, + String forwarderName, + Object[] params, + String[] sig) throws IOException, MBeanException { + + if (logger.traceOn()) { + logger.trace("FetchingEventRelay", "delegateMBean "+ + bufferSize+" "+ + timeout+" "+ + maxNotifs+" "+ + executor+" "+ + forwarderName+" "); + } + + if(delegate == null) { + throw new NullPointerException("Null EventClientDelegateMBean!"); + } + + + if (bufferSize<=1) { + throw new IllegalArgumentException( + "The bufferSize cannot be less than 1, no meaning."); + } + + if (maxNotifs<=1) { + throw new IllegalArgumentException( + "The maxNotifs cannot be less than 1, no meaning."); + } + + clientId = delegate.addClient( + forwarderName, + params, + sig); + + this.delegate = delegate; + this.timeout = timeout; + this.maxNotifs = maxNotifs; + + if (executor == null) { + ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1, + daemonThreadFactory); + stpe.setKeepAliveTime(1, TimeUnit.SECONDS); + stpe.allowCoreThreadTimeOut(true); + executor = stpe; + this.defaultExecutor = stpe; + } else + this.defaultExecutor = null; + this.executor = executor; + + startSequenceNumber = 0; + fetchingJob = new MyJob(); + } + + public synchronized void setEventReceiver(EventReceiver eventReceiver) { + if (logger.traceOn()) { + logger.trace("setEventReceiver", ""+eventReceiver); + } + + EventReceiver old = this.eventReceiver; + this.eventReceiver = eventReceiver; + if (old == null && eventReceiver != null) + fetchingJob.resume(); + } + + public String getClientId() { + return clientId; + } + + public synchronized void stop() { + if (logger.traceOn()) { + logger.trace("stop", ""); + } + if (stopped) { + return; + } + + stopped = true; + clientId = null; + if (defaultExecutor != null) + defaultExecutor.shutdown(); + } + + private class MyJob extends RepeatedSingletonJob { + public MyJob() { + super(executor); + } + + public boolean isSuspended() { + boolean b; + synchronized(FetchingEventRelay.this) { + b = stopped || + (eventReceiver == null) || + (clientId == null); + } + + if (logger.traceOn()) { + logger.trace("-MyJob-isSuspended", ""+b); + } + return b; + } + + public void task() { + logger.trace("MyJob-task", ""); + long fetchTimeout = timeout; + NotificationResult nr = null; + Throwable failedExcep = null; + try { + nr = delegate.fetchNotifications( + clientId, + startSequenceNumber, + maxNotifs, + fetchTimeout); + } catch (Exception e) { + if (isSerialOrClassNotFound(e)) { + try { + nr = fetchOne(); + } catch (Exception ee) { + failedExcep = e; + } + } else { + failedExcep = e; + } + } + + if (failedExcep != null && + !isSuspended()) { + logger.fine("MyJob-task", + "Failed to fetch notification, stopping...", failedExcep); + try { + eventReceiver.failed(failedExcep); + } catch (Exception e) { + logger.trace( + "MyJob-task", "exception from eventReceiver.failed", e); + } + + stop(); + } else if (nr != null) { + try { + eventReceiver.receive(nr); + } catch (RuntimeException e) { + logger.trace( + "MyJob-task", + "exception delivering notifs to EventClient", e); + } finally { + startSequenceNumber = nr.getNextSequenceNumber(); + } + } + } + } + + private NotificationResult fetchOne() throws Exception { + logger.trace("fetchOne", ""); + + while (true) { + try { + // 1 notif to skip possible missing class + return delegate.fetchNotifications( + clientId, + startSequenceNumber, + 1, + timeout); + } catch (Exception e) { + if (isSerialOrClassNotFound(e)) { // skip and continue + if (logger.traceOn()) { + logger.trace("fetchOne", "Ignore", e); + } + eventReceiver.nonFatal(e); + startSequenceNumber++; + } else { + throw e; + } + } + } + } + + static boolean isSerialOrClassNotFound(Exception e) { + Throwable cause = e.getCause(); + + while (cause != null && + !(cause instanceof ClassNotFoundException) && + !(cause instanceof NotSerializableException)) { + cause = cause.getCause(); + } + + return (cause instanceof ClassNotFoundException || + cause instanceof NotSerializableException); + } + + private long startSequenceNumber = 0; + private EventReceiver eventReceiver = null; + private final EventClientDelegateMBean delegate; + private String clientId; + private boolean stopped = false; + + private final Executor executor; + private final ExecutorService defaultExecutor; + private final MyJob fetchingJob; + + private final long timeout; + private final int maxNotifs; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", + "FetchingEventRelay"); + private static final ThreadFactory daemonThreadFactory = + new DaemonThreadFactory("JMX FetchingEventRelay executor %d"); +} diff --git a/src/share/classes/javax/management/event/ListenerInfo.java b/src/share/classes/javax/management/event/ListenerInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..9c7a8fc59333c799cb7362d64ecc301fc6da4136 --- /dev/null +++ b/src/share/classes/javax/management/event/ListenerInfo.java @@ -0,0 +1,169 @@ +/* + * 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 javax.management.event; + +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +/** + * This class specifies all the information required to register a user listener into + * a remote MBean server. This class is not serializable because a user listener + * is not serialized in order to be sent to the remote server. + * + * @since JMX 2.0 + */ +public class ListenerInfo { + + /** + * Constructs a {@code ListenerInfo} object. + * + * @param name The name of the MBean to which the listener should + * be added. + * @param listener The listener object which will handle the + * notifications emitted by the MBean. + * @param filter The filter object. If the filter is null, no + * filtering will be performed before notifications are handled. + * @param handback The context to be sent to the listener when a + * notification is emitted. + * @param isSubscription If true, the listener is subscribed via + * an {@code EventManager}. Otherwise it is added to a registered MBean. + */ + public ListenerInfo(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback, + boolean isSubscription) { + this.name = name; + this.listener = listener; + this.filter = filter; + this.handback = handback; + this.isSubscription = isSubscription; + } + + /** + * Returns an MBean or an MBean pattern that the listener listens to. + * + * @return An MBean or an MBean pattern. + */ + public ObjectName getObjectName() { + return name; + } + + /** + * Returns the listener. + * + * @return The listener. + */ + public NotificationListener getListener() { + return listener; + } + + /** + * Returns the listener filter. + * + * @return The filter. + */ + public NotificationFilter getFilter() { + return filter; + } + + /** + * Returns the listener handback. + * + * @return The handback. + */ + public Object getHandback() { + return handback; + } + + /** + * Returns true if this is a subscription listener. + * + * @return True if this is a subscription listener. + * + * @see EventClient#addListeners + */ + public boolean isSubscription() { + return isSubscription; + } + + /** + *

      Indicates whether some other object is "equal to" this one. + * The return value is true if and only if {@code o} is an instance of + * {@code ListenerInfo} and has equal values for all of its properties.

      + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof ListenerInfo)) { + return false; + } + + ListenerInfo li = (ListenerInfo)o; + + boolean ret = name.equals(li.name) && + (listener == li.listener) && + (isSubscription == li.isSubscription); + + if (filter != null) { + ret &= filter.equals(li.filter); + } else { + ret &= (li.filter == null); + } + + if (handback != null) { + ret &= handback.equals(li.handback); + } else { + ret &= (li.handback == null); + } + + return ret; + } + + @Override + public int hashCode() { + return name.hashCode() + listener.hashCode(); + } + + @Override + public String toString() { + return name.toString() + "_" + + listener + "_" + + filter + "_" + + handback + "_" + + isSubscription; + } + + private final ObjectName name; + private final NotificationListener listener; + private final NotificationFilter filter; + private final Object handback; + private final boolean isSubscription; +} diff --git a/src/share/classes/javax/management/event/NotificationManager.java b/src/share/classes/javax/management/event/NotificationManager.java new file mode 100644 index 0000000000000000000000000000000000000000..89edf9ba9d6e76a968616738bea5c4bc25c24d25 --- /dev/null +++ b/src/share/classes/javax/management/event/NotificationManager.java @@ -0,0 +1,136 @@ +/* + * 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 javax.management.event; + +import java.io.IOException; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +/** + * This interface specifies methods to add and remove notification listeners + * on named MBeans. + */ +public interface NotificationManager { + /** + *

      Adds a listener to a registered MBean. + * Notifications emitted by the MBean will be forwarded + * to the listener. + * + * @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. + * @exception IOException A communication problem occurred when + * talking to the MBean server. + * + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + */ + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, + IOException; + + /** + *

      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 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. + * @exception IOException A communication problem occurred when + * talking to the MBean server. + * + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, + ListenerNotFoundException, + IOException; + + /** + *

      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 The listener to be removed. + * @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. + * @exception IOException A communication problem occurred when + * talking to the MBean server. + * + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, + ListenerNotFoundException, + IOException; +} diff --git a/src/share/classes/javax/management/event/RMIPushEventForwarder.java b/src/share/classes/javax/management/event/RMIPushEventForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..636f2e57aaa5404770001c3c7e9ede3d99a358b9 --- /dev/null +++ b/src/share/classes/javax/management/event/RMIPushEventForwarder.java @@ -0,0 +1,198 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.event.DaemonThreadFactory; +import com.sun.jmx.event.RepeatedSingletonJob; +import com.sun.jmx.remote.util.ClassLogger; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.management.Notification; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; + + +/** + * This class is used by {@link RMIPushEventRelay}. When + * {@link RMIPushEventRelay} calls {@link + * EventClientDelegateMBean#addClient(String, Object[], String[])} to get a new + * client identifier, it uses this class name as the + * first argument to ask {@code EventClientDelegateMBean} to create an object of + * this class. + * Then {@code EventClientDelegateMBean} forwards client notifications + * to this object. This object then continues forwarding the notifications + * to the {@code RMIPushEventRelay}. + */ +public class RMIPushEventForwarder implements EventForwarder { + private static final int DEFAULT_BUFFER_SIZE = 6000; + + /** + * Creates a new instance of {@code RMIPushEventForwarder}. + * + * @param receiver An RMI stub exported to receive notifications + * from this object for its {@link RMIPushEventRelay}. + * + * @param bufferSize The maximum number of notifications to store + * while waiting for the last remote send to complete. + */ + public RMIPushEventForwarder(RMIPushServer receiver, int bufferSize) { + if (logger.traceOn()) { + logger.trace("RMIEventForwarder", "new one"); + } + + if (bufferSize < 0) { + throw new IllegalArgumentException( + "Negative buffer size: " + bufferSize); + } else if (bufferSize == 0) + bufferSize = DEFAULT_BUFFER_SIZE; + + if (receiver == null) { + throw new NullPointerException(); + } + + this.receiver = receiver; + this.buffer = new ArrayBlockingQueue(bufferSize); + } + + public void forward(Notification n, Integer listenerId) { + if (logger.traceOn()) { + logger.trace("forward", "to the listener: "+listenerId); + } + synchronized(sendingJob) { + TargetedNotification tn = new TargetedNotification(n, listenerId); + while (!buffer.offer(tn)) { + buffer.remove(); + passed++; + } + sendingJob.resume(); + } + } + + public void close() { + if (logger.traceOn()) { + logger.trace("close", "called"); + } + + synchronized(sendingJob) { + ended = true; + buffer.clear(); + } + } + + public void setClientId(String clientId) { + if (logger.traceOn()) { + logger.trace("setClientId", clientId); + } + } + + private class SendingJob extends RepeatedSingletonJob { + public SendingJob() { + super(executor); + } + + public boolean isSuspended() { + return ended || buffer.isEmpty(); + } + + public void task() { + final long earliest = passed; + + List tns = + new ArrayList(buffer.size()); + synchronized(sendingJob) { + buffer.drainTo(tns); + passed += tns.size(); + } + + if (logger.traceOn()) { + logger.trace("SendingJob-task", "sending: "+tns.size()); + } + + if (!tns.isEmpty()) { + try { + TargetedNotification[] tnArray = + new TargetedNotification[tns.size()]; + tns.toArray(tnArray); + receiver.receive(new NotificationResult(earliest, passed, tnArray)); + } catch (RemoteException e) { + if (logger.debugOn()) { + logger.debug("SendingJob-task", + "Got exception to forward notifs.", e); + } + + long currentLost = passed - earliest; + if (FetchingEventRelay.isSerialOrClassNotFound(e)) { + // send one by one + long tmpPassed = earliest; + for (TargetedNotification tn : tns) { + try { + receiver.receive(new NotificationResult(earliest, + ++tmpPassed, new TargetedNotification[]{tn})); + } catch (RemoteException ioee) { + logger.trace( + "SendingJob-task", "send to remote", ioee); + // sends nonFatal notifs? + } + } + + currentLost = passed - tmpPassed; + } + + if (currentLost > 0) { // inform of the lost. + try { + receiver.receive(new NotificationResult( + passed, passed, + new TargetedNotification[]{})); + } catch (RemoteException ee) { + logger.trace( + "SendingJob-task", "receiver.receive", ee); + } + } + } + } + } + } + + private long passed = 0; + + private static final ExecutorService executor = + Executors.newCachedThreadPool( + new DaemonThreadFactory("JMX RMIEventForwarder Executor")); + private final SendingJob sendingJob = new SendingJob(); + + private final BlockingQueue buffer; + + private final RMIPushServer receiver; + private boolean ended = false; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", "RMIEventForwarder"); +} diff --git a/src/share/classes/javax/management/event/RMIPushEventRelay.java b/src/share/classes/javax/management/event/RMIPushEventRelay.java new file mode 100644 index 0000000000000000000000000000000000000000..1cc5509557319c82b3ff8e417ad8553fad22e5b1 --- /dev/null +++ b/src/share/classes/javax/management/event/RMIPushEventRelay.java @@ -0,0 +1,161 @@ +/* + * 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 javax.management.event; + +import com.sun.jmx.remote.util.ClassLogger; +import java.io.IOException; +import java.rmi.NoSuchObjectException; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import javax.management.MBeanException; +import javax.management.remote.NotificationResult; + +/** + * This class is an implementation of the {@link EventRelay} interface, using + * push mode. It exports an RMI object that {@link RMIPushEventForwarder} uses + * to forward notifications. + * + * @since JMX 2.0 + */ +public class RMIPushEventRelay implements EventRelay { + /** + * Constructs a default {@code RMIPushEventRelay} object + * and exports its {@linkplain RMIPushServer notification + * receiver} on any free port. This constructor is equivalent + * to {@link #RMIPushEventRelay(EventClientDelegateMBean, + * int, RMIClientSocketFactory, RMIServerSocketFactory, int) + * RMIPushEventRelay(delegate, 0, null, null, <default buffer + * size>)}. + * + * @param delegate The {@link EventClientDelegateMBean} proxy to work with. + * @throws IOException if failed to communicate with + * {@link EventClientDelegateMBean}. + * @throws MBeanException if the {@link EventClientDelegateMBean} failed + * to create an {@code EventForwarder} for this object. + */ + public RMIPushEventRelay(EventClientDelegateMBean delegate) + throws IOException, MBeanException { + this(delegate, 0, null, null, 0); + } + + /** + * Constructs a {@code RMIPushEventRelay} object and exports its + * {@linkplain RMIPushServer notification receiver} on a specified port. + * + * @param delegate The {@link EventClientDelegateMBean} proxy to work with. + * @param port The port used to export an RMI object to receive notifications + * from a server. If the port is zero, an anonymous port is used. + * @param csf The client socket factory used to export the RMI object. + * Can be null. + * @param ssf The server socket factory used to export the RMI object. + * Can be null. + * @param bufferSize The number of notifications held on the server + * while waiting for the previous transmission to complete. A value of + * zero means the default buffer size. + * + * @throws IOException if failed to communicate with + * {@link EventClientDelegateMBean}. + * @throws MBeanException if the {@link EventClientDelegateMBean} failed + * to create an {@code EventForwarder} for this object. + * + * @see RMIPushEventForwarder#RMIPushEventForwarder(RMIPushServer, int) + */ + public RMIPushEventRelay(EventClientDelegateMBean delegate, + int port, + RMIClientSocketFactory csf, + RMIServerSocketFactory ssf, + int bufferSize) + throws IOException, MBeanException { + + UnicastRemoteObject.exportObject(exportedReceiver, port, csf, ssf); + + clientId = delegate.addClient( + RMIPushEventForwarder.class.getName(), + new Object[] {exportedReceiver, bufferSize}, + new String[] {RMIPushServer.class.getName(), + int.class.getName()}); + } + + public String getClientId() { + return clientId; + } + + public void setEventReceiver(EventReceiver receiver) { + if (logger.traceOn()) { + logger.trace("setEventReceiver", ""+receiver); + } + synchronized(lock) { + this.receiver = receiver; + } + } + + public void stop() { + if (logger.traceOn()) { + logger.trace("stop", ""); + } + synchronized(lock) { + if (stopped) { + return; + } else { + stopped = true; + } + + if (clientId == null) { + return; + } + + try { + UnicastRemoteObject.unexportObject(exportedReceiver, true); + } catch (NoSuchObjectException nsoe) { + logger.fine("RMIPushEventRelay.stop", "unexport", nsoe); + // OK: we wanted it unexported, and apparently it already is + } + } + } + + private volatile String clientId; + private volatile EventReceiver receiver; + + private RMIPushServer exportedReceiver = new RMIPushServer() { + public void receive(NotificationResult nr) throws RemoteException { + if (logger.traceOn()) { + logger.trace("EventPusherImpl-receive",""); + } + receiver.receive(nr); + // Any exception will be sent back to the client. + } + }; + + private boolean stopped = false; + + private final int[] lock = new int[0]; + + private static final ClassLogger logger = + new ClassLogger("javax.management.event", + "PushEventRelay"); +} diff --git a/src/share/classes/javax/management/event/RMIPushServer.java b/src/share/classes/javax/management/event/RMIPushServer.java new file mode 100644 index 0000000000000000000000000000000000000000..253498459a11f0d668de370dbc0766ce1d07badc --- /dev/null +++ b/src/share/classes/javax/management/event/RMIPushServer.java @@ -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 javax.management.event; + +import java.rmi.Remote; +import java.rmi.RemoteException; +import javax.management.remote.NotificationResult; + +/** + * The {@link RMIPushEventRelay} exports an RMI object of this class and + * sends a client stub for that object to the associated + * {@link RMIPushEventForwarder} in a remote MBean server. The + * {@code RMIPushEventForwarder} then sends notifications to the + * RMI object. + */ +public interface RMIPushServer extends Remote { + /** + *

      Dispatch the notifications in {@code nr} to the {@link RMIPushEventRelay} + * associated with this object.

      + * @param nr the notification result to dispatch. + * @throws java.rmi.RemoteException if the remote invocation of this method + * failed. + */ + public void receive(NotificationResult nr) throws RemoteException; +} diff --git a/src/share/classes/javax/management/event/package-info.java b/src/share/classes/javax/management/event/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..c4c7dbed63dd1ae7e9cb302ebd4d96771bc1ad2f --- /dev/null +++ b/src/share/classes/javax/management/event/package-info.java @@ -0,0 +1,312 @@ +/** + *

      Defines the Event Service, which provides extended support + * for JMX notifications.

      + * + *

      The Event Service provides greater control over + * notification handling than the default technique using {@link + * javax.management.MBeanServer#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object) + * MBeanServer.addNotificationListener} or {@link + * javax.management.MBeanServerConnection#addNotificationListener(ObjectName, + * NotificationListener, NotificationFilter, Object) + * MBeanServerConnection.addNotificationListener}.

      + * + *

      Here are some reasons you may want to use the Event Service:

      + * + *
        + *
      • To receive notifications from a set of MBeans defined by an + * ObjectName pattern, such as {@code com.example.config:type=Cache,*}. + * + *
      • When the notification-handling behavior of the connector you are + * using does not match your requirements. For example, with the standard + * RMI connector you can lose notifications if there are very many of them + * in the MBean Server you are connected to, even if you are only listening + * for a small proportion of them. + * + *
      • To change the threading behavior of notification dispatch. + * + *
      • To define a different transport for notifications, for example to + * arrange for them to be delivered through the Java Message Service (JMS). The Event Service comes with + * one alternative transport as standard, a "push-mode" RMI transport. + * + *
      • To handle notifications on behalf of MBeans (often virtual) in a + * namespace. + *
      + * + *

      The Event Service is new in version 2.0 of the JMX API, which is the + * version introduced in version 7 of the Java SE platform. It is not usually + * possible to use the Event Service when connecting remotely to an + * MBean Server that is running an earlier version.

      + * + * + *

      Handling remote notifications with the Event + * Service

      + * + *

      Prior to version 2.0 of the JMX API, every connector + * had to include logic to handle notifications. The standard {@linkplain + * javax.management.remote.rmi RMI} and JMXMP connectors defined by JSR 160 handle notifications + * in a way that is not always appropriate for applications. Specifically, + * the connector server adds one listener to every MBean that might emit + * notifications, and adds all received notifications to a fixed-size + * buffer. This means that if there are very many notifications, a + * remote client may miss some, even if it is only registered for a + * very small subset of notifications. Furthermore, since every {@link + * javax.management.NotificationBroadcaster NotificationBroadcaster} MBean + * gets a listener from the connector server, MBeans cannot usefully optimize + * by only sending notifications when there is a listener. Finally, since + * the connector server uses just one listener per MBean, MBeans cannot + * impose custom behavior per listener, such as security checks or localized + * notifications.

      + * + *

      The Event Service does not have these restrictions. The RMI connector + * that is included in this version of the JMX API uses the Event Service by + * default, although it can be configured to have the previous behavior if + * required.

      + * + *

      The Event Service can be used with any connector via the + * method {@link javax.management.event.EventClient#getEventClientConnection + * EventClient.getEventClientConnection}, like this:

      + * + *
      + * JMXConnector conn = ...;
      + * MBeanServerConnection mbsc = conn.getMBeanServerConnection();
      + * MBeanServerConnection eventMbsc = EventClient.getEventClientConnection(mbsc);
      + * 
      + * + *

      If you add listeners using {@code eventMbsc.addNotificationListener} + * instead of {@code mbsc.addNotificationListener}, then they will be handled + * by the Event Service rather than by the connector's notification system.

      + * + *

      For the Event Service to work, either the {@link + * javax.management.event.EventClientDelegateMBean EventClientDelegateMBean} + * must be registered in the MBean Server, or the connector server must + * be configured to simulate the existence of this MBean, for example + * using {@link javax.management.event.EventClientDelegate#newForwarder() + * EventClientDelegate.newForwarder()}. The standard RMI connector is so + * configured by default. The {@code EventClientDelegateMBean} documentation + * has further details.

      + * + * + *

      Receiving notifications from a set of MBeans

      + * + *

      The Event Server allows you to receive notifications from every MBean + * that matches an {@link javax.management.ObjectName ObjectName} pattern. + * For local clients (in the same JVM as the MBean Server), the {@link + * javax.management.event.EventSubscriber EventSubscriber} class can be used for + * this. For remote clients, or if the same code is to be used locally and + * remotely, use an + * {@link javax.management.event.EventClient EventClient}.

      + * + *

      EventSubscriber and EventClient correctly handle the case where a new + * MBean is registered under a name that matches the pattern. Notifications + * from the new MBean will also be received.

      + * + *

      Here is how to receive notifications from all MBeans in a local + * {@code MBeanServer} that match {@code com.example.config:type=Cache,*}:

      + * + *
      + * MBeanServer mbs = ...;
      + * NotificationListener listener = ...;
      + * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
      + * EventSubscriber esub = EventSubscriber.getEventSubscriber(mbs);
      + * esub.{@link javax.management.event.EventSubscriber#subscribe
      + * subscribe}(pattern, listener, null, null);
      + * 
      + * + *

      Here is how to do the same thing remotely:

      + * + *
      + * MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
      + * EventClient events = new EventClient(mbsc);
      + * NotificationListener listener = ...;
      + * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
      + * events.{@link javax.management.event.EventClient#subscribe
      + * subscribe}(pattern, listener, null, null);
      + * 
      + * + * + *

      Controlling threading behavior for notification + * dispatch

      + * + *

      The EventClient class can be used to control threading of listener + * dispatch. For example, to arrange for all listeners to be invoked + * in the same thread, you can create an {@code EventClient} like this:

      + * + *
      + * MBeanServerConnection mbsc = ...;
      + * Executor singleThreadExecutor = {@link
      + * java.util.concurrent.Executors#newSingleThreadExecutor()
      + * Executors.newSingleThreadExecutor}();
      + * EventClient events = new EventClient(
      + *         mbsc, null, singleThreadExecutor, EventClient.DEFAULT_LEASE_TIMEOUT);
      + * events.addNotificationListener(...);
      + * events.subscribe(...);
      + * 
      + * + * + *

      Leasing

      + * + *

      The {@code EventClient} uses a lease mechanism to ensure + * that resources are eventually released on the server even if the client + * does not explicitly clean up. (This can happen through network + * partitioning, for example.)

      + * + *

      When an {@code EventClient} registers with the {@code + * EventClientDelegateMBean} using one of the {@code addClient} methods, + * an initial lease is created with a default expiry time. The {@code + * EventClient} requests an explicit lease shortly after that, with a + * configurable expiry time. Then the {@code EventClient} periodically + * renews the lease before it expires, typically about half way + * through the lifetime of the lease. If at any point the lease reaches + * the expiry time of the last renewal then it expires, and {@code + * EventClient} is unregistered as if it had called the {@link + * javax.management.event.EventClientDelegateMBean#removeClient removeClient} + * method.

      + * + * + *

      Custom notification transports

      + * + *

      When you create an {@code EventClient}, you can define the transport + * that it uses to deliver notifications. The transport might use the + * Java Message Service (JMS) or + * any other communication system. Specifying a transport is useful for + * example when you want different network behavior from the default, or + * different reliability guarantees. The default transport calls {@link + * javax.management.event.EventClientDelegateMBean#fetchNotifications + * EventClientDelegateMBean.fetchNotifications} repeatedly, which usually means + * that there must be a network connection permanently open between the client + * and the server. If the same client is connected to many servers this can + * cause scalability problems. If notifications are relatively rare, then + * JMS or the {@linkplain javax.management.event.RMIPushEventRelay push-mode + * RMI transport} may be more suitable.

      + * + *

      A transport is implemented by an {@link javax.management.event.EventRelay + * EventRelay} on the client side and a corresponding {@link + * javax.management.event.EventForwarder EventForwarder} + * on the server side. An example is the {@link + * javax.management.event.RMIPushEventRelay RMIPushEventRelay} and its + * {@link javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}.

      + * + *

      To use a given transport with an {@code EventClient}, you first create + * an instance of its {@code EventRelay}. Typically the {@code EventRelay}'s + * constructor will have a parameter of type {@code MBeanServerConnection} + * or {@code EventClientDelegateMBean}, so that it can communicate with the + * {@code EventClientDelegateMBean} in the server. For example, the {@link + * javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}'s constructors + * all take an {@code EventClientDelegateMBean} parameter, which is expected to + * be a {@linkplain javax.management.JMX#newMBeanProxy(MBeanServerConnection, + * ObjectName, Class) proxy} for the {@code EventClientDelegateMBean} in the + * server.

      + * + *

      When it is created, the {@code EventRelay} will call + * {@link javax.management.event.EventClientDelegateMBean#addClient(String, + * Object[], String[]) EventClientDelegateMBean.addClient}. It passes the + * name of the {@code EventForwarder} class and its constructor parameters. + * The {@code EventClientDelegateMBean} will instantiate this class using + * {@link javax.management.MBeanServer#instantiate(String, Object[], String[]) + * MBeanServer.instantiate}, and it will return a unique client id.

      + * + *

      Then you pass the newly-created {@code EventRelay} to one of the {@code + * EventClient} constructors, and you have an {@code EventClient} that uses the + * chosen transport.

      + * + *

      For example, when you create an {@code RMIPushEventRelay}, it + * uses {@code MBeanServerDelegateMBean.addClient} to create an {@code + * RMIEventForwarder} in the server. Notifications will then be delivered + * through an RMI communication from the {@code RMIEventForwarder} to the + * {@code RMIPushEventRelay}.

      + * + * + *

      Writing a custom transport

      + * + *

      To write a custom transport, you need to understand the sequence + * of events when an {@code EventRelay} and its corresponding {@code + * EventForwarder} are created, and when a notification is sent from the {@code + * EventForwarder} to the {@code EventRelay}.

      + * + *

      When an {@code EventRelay} is created:

      + * + *
        + *
      • The {@code EventRelay} must call {@code + * EventClientDelegateMBean.addClient} with the name of the {@code + * EventForwarder} and the constructor parameters.

        + * + *
      • {@code EventClientDelegateMBean.addClient} will do the following + * steps:

        + * + *
          + *
        • create the {@code EventForwarder} using {@code MBeanServer.instantiate}; + *
        • allocate a unique client id; + *
        • call the new {@code EventForwarder}'s {@link + * javax.management.event.EventForwarder#setClientId setClientId} method with + * the new client id; + *
        • return the client id to the caller. + *
        + * + *
      + * + *

      When an {@code EventClient} is created with an {@code EventRelay} + * parameter, it calls {@link javax.management.event.EventRelay#setEventReceiver + * EventRelay.setEventReceiver} with an {@code EventReceiver} that the + * {@code EventRelay} will use to deliver notifications.

      + * + *

      When a listener is added using the {@code EventClient}, the + * {@code EventRelay} and {@code EventForwarder} are not involved.

      + * + *

      When an MBean emits a notification and a listener has been added + * to that MBean using the {@code EventClient}:

      + * + *
        + *
      • The {@code EventForwarder}'s + * {@link javax.management.event.EventForwarder#forward forward} method + * is called with the notification and a listener id.

        + * + *
      • The {@code EventForwarder} sends the notification and listener id + * to the {@code EventRelay} using the custom transport.

        + * + *
      • The {@code EventRelay} delivers the notification by calling + * {@link javax.management.event.EventReceiver#receive EventReceiver.receive}.

        + *
      + * + *

      When the {@code EventClient} is closed ({@link + * javax.management.event.EventClient#close EventClient.close}):

      + * + *
        + *
      • The {@code EventClient} calls {@link + * javax.management.event.EventRelay#stop EventRelay.stop}.

        + * + *
      • The {@code EventClient} calls {@link + * javax.management.event.EventClientDelegateMBean#removeClient + * EventClientDelegateMBean.removeClient}.

        + * + *
      • The {@code EventClientDelegateMBean} removes any listeners it + * had added on behalf of this {@code EventClient}.

        + * + *
      • The {@code EventClientDelegateMBean} calls + * {@link javax.management.event.EventForwarder#close EventForwarder.close}.

        + *
      + * + * + *

      Threading and buffering

      + * + *

      The {@link javax.management.event.EventForwarder#forward + * EventForwarder.forward} method may be called in the thread that the + * source MBean is using to send its notification. MBeans can expect + * that notification sending does not block. Therefore a {@code forward} + * method will typically add the notification to a queue, with a separate + * thread that takes notifications off the queue and sends them.

      + * + *

      An {@code EventRelay} does not usually need to buffer notifications + * before giving them to + * {@link javax.management.event.EventReceiver#receive EventReceiver.receive}. + * Although by default each such notification will be sent to potentially-slow + * listeners, if this is a problem then an {@code Executor} can be given to + * the {@code EventClient} constructor to cause the listeners to be called + * in a different thread.

      + * + * @since 1.7 + */ + +package javax.management.event; diff --git a/src/share/classes/javax/management/loading/MLet.java b/src/share/classes/javax/management/loading/MLet.java index ba27646df6aea9d00b2c757b0ba17ec4428b4d8d..d6540591e9843c244480dd0565d359f5248593ea 100644 --- a/src/share/classes/javax/management/loading/MLet.java +++ b/src/share/classes/javax/management/loading/MLet.java @@ -1154,21 +1154,29 @@ public class MLet extends java.net.URLClassLoader */ private synchronized String loadLibraryAsResource(String libname) { try { - InputStream is = getResourceAsStream(libname.replace(File.separatorChar,'/')); + InputStream is = getResourceAsStream( + libname.replace(File.separatorChar,'/')); if (is != null) { - File directory = new File(libraryDirectory); - directory.mkdirs(); - File file = File.createTempFile(libname + ".", null, directory); - file.deleteOnExit(); - FileOutputStream fileOutput = new FileOutputStream(file); - int c; - while ((c = is.read()) != -1) { - fileOutput.write(c); - } - is.close(); - fileOutput.close(); - if (file.exists()) { - return file.getAbsolutePath(); + try { + File directory = new File(libraryDirectory); + directory.mkdirs(); + File file = File.createTempFile(libname + ".", null, + directory); + file.deleteOnExit(); + FileOutputStream fileOutput = new FileOutputStream(file); + try { + int c; + while ((c = is.read()) != -1) { + fileOutput.write(c); + } + } finally { + fileOutput.close(); + } + if (file.exists()) { + return file.getAbsolutePath(); + } + } finally { + is.close(); } } } catch (Exception e) { diff --git a/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java b/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java index 6e4a3ed6368ccb0a0bad8bb53ce6d22d51e08c3e..3655daadd1fb2bf96413985ac61210fa78a18a9e 100644 --- a/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java +++ b/src/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java @@ -373,7 +373,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { "getDescriptors(String)", "Entry"); } - if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) { + if ((inDescriptorType == null) || (inDescriptorType.equals(""))) { inDescriptorType = "all"; } @@ -616,7 +616,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { inDescriptor = new DescriptorSupport(); } - if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) { + if ((inDescriptorType == null) || (inDescriptorType.equals(""))) { inDescriptorType = (String) inDescriptor.getFieldValue("descriptorType"); diff --git a/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java b/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java index 3c09c3ff2ccd298003a58fa8a8f8dbebd53a452a..7d99fba0021ca50f1df2e2f4a8e61d6943adf62f 100644 --- a/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java +++ b/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java @@ -1123,7 +1123,7 @@ public class RequiredModelMBean if (tracing) { MODELMBEAN_LOGGER.logp(Level.FINER, RequiredModelMBean.class.getName(),"resolveMethod", - "resolving " + targetClass + "." + opMethodName); + "resolving " + targetClass.getName() + "." + opMethodName); } final Class[] argClasses; diff --git a/src/share/classes/javax/management/namespace/JMXDomain.java b/src/share/classes/javax/management/namespace/JMXDomain.java new file mode 100644 index 0000000000000000000000000000000000000000..bff3c1370624db19ab97825f470253407c1d00c2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXDomain.java @@ -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 suppliedName) { + if (suppliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(suppliedName.getDomain()); + final ObjectName handlerName = getDomainObjectName(dirName); + if (!suppliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + suppliedName); + + return suppliedName; + } + + /** + * 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 --git a/src/share/classes/javax/management/namespace/JMXNamespace.java b/src/share/classes/javax/management/namespace/JMXNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..23f3004ebe5dce2d0619c28dbb0d5d281d4b83a2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespace.java @@ -0,0 +1,666 @@ +/* + * 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 reference to the MBean server in which it is + * registered. It also checks 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 { + // need to synchronize to protect against multiple registration. + synchronized(this) { + 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 suppliedName) { + if (suppliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(suppliedName.getDomain()); + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dirName); + if (!suppliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + suppliedName); + return suppliedName; + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a reference 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 reference 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() { + // need to synchronize to protect against multiple registration. + synchronized(this) { + 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 --git a/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java b/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..4632b410ae756b7d7e3206a4eb42ed1c028af034 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java @@ -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 --git a/src/share/classes/javax/management/namespace/JMXNamespacePermission.java b/src/share/classes/javax/management/namespace/JMXNamespacePermission.java new file mode 100644 index 0000000000000000000000000000000000000000..5dd012672b3ba2afe86057ea36c68f3fe9b8bcb0 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespacePermission.java @@ -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 --git a/src/share/classes/javax/management/namespace/JMXNamespaceView.java b/src/share/classes/javax/management/namespace/JMXNamespaceView.java new file mode 100644 index 0000000000000000000000000000000000000000..eacc0f4bce76a16992211a9794822a0271c5fba2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaceView.java @@ -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 --git a/src/share/classes/javax/management/namespace/JMXNamespaces.java b/src/share/classes/javax/management/namespace/JMXNamespaces.java new file mode 100644 index 0000000000000000000000000000000000000000..429a9d466d6175a2f56e0f5b4d7c74d2b7fb8211 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaces.java @@ -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.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 { + // We could use Util.newObjectName here - but throwing an + // IllegalArgumentException that contains just the supplied + // namespace instead of the whole ObjectName seems preferable. + return ObjectName.getInstance(sourcePath+ + NAMESPACE_SEPARATOR+":"+ + JMXNamespace.TYPE_ASSIGNMENT); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException("Invalid namespace: " + + 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 --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..6958f57f2d72db7a17c99e2acb93fb058c33b1f3 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java @@ -0,0 +1,734 @@ +/* + * 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.remote.util.EnvHelp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +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.MBeanServerConnection; +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; + + + // 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 class ConnectionListener implements NotificationListener { + private ConnectionListener() { + } + public void handleNotification(Notification notification, + Object handback) { + if (!(notification instanceof JMXConnectionNotification)) + return; + final JMXConnectionNotification cn = + (JMXConnectionNotification)notification; + final String type = cn.getType(); + if (JMXConnectionNotification.CLOSED.equals(type) + || JMXConnectionNotification.FAILED.equals(type)) { + 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 { + 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; + + } + + } + + private static final MBeanNotificationInfo connectNotification = + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + "Connected", + "Emitted when the Connected state of this object changes"); + + private static AtomicLong seqNumber = new AtomicLong(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; + + /** + * 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(); + } + + /** + * 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; + } + + 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 long getNextSeqNumber() { + return seqNumber.getAndIncrement(); + } + + + /** + * 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. The 'emittingConnector' is the connector from which the + // notification originated. This could be an 'old' connector - as + // closed() and connect() could already have been called before the + // notification arrived. So what we do is to compare the + // 'emittingConnector' with the current connector, to see if the + // notification actually comes from the curent connector. + // + 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 close(JMXConnector c) { + 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 { + LOG.fine("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) { + close(aconn); + throw io; + } catch (RuntimeException x) { + close(aconn); + throw x; + } + + switchConnection(conn,aconn,msc); + + LOG.fine("connected."); + } + + 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 --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..18b0fb86dfeeb4ecda2e8e69d24eb88f2887446e --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java @@ -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 --git a/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java b/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..7eeda961e31756773b635df5aa45fb44c2fc3207 --- /dev/null +++ b/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java @@ -0,0 +1,702 @@ +/* + * 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.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 --git a/src/share/classes/javax/management/namespace/MBeanServerSupport.java b/src/share/classes/javax/management/namespace/MBeanServerSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..903be3c308f1029a76777a1cbb18efa7a0de2a92 --- /dev/null +++ b/src/share/classes/javax/management/namespace/MBeanServerSupport.java @@ -0,0 +1,1331 @@ +/* + * 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 {
      + *     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 = ObjectName.valueOf(
      + *                     "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 = ObjectName.valueOf(
      + *                     "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 = ObjectName.valueOf(
      + *                 "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 --git a/src/share/classes/javax/management/namespace/VirtualEventManager.java b/src/share/classes/javax/management/namespace/VirtualEventManager.java new file mode 100644 index 0000000000000000000000000000000000000000..336f37565cba35728219ba18a5b53edda1415845 --- /dev/null +++ b/src/share/classes/javax/management/namespace/VirtualEventManager.java @@ -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 --git a/src/share/classes/javax/management/namespace/package-info.java b/src/share/classes/javax/management/namespace/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..df8354bab635379c29f3340676192c2c1b0a5238 --- /dev/null +++ b/src/share/classes/javax/management/namespace/package-info.java @@ -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 --git a/src/share/classes/javax/management/openmbean/CompositeDataSupport.java b/src/share/classes/javax/management/openmbean/CompositeDataSupport.java index 172fa756161cb2b305ec86d65858cb368382d499..4ef93b47611ccc649afec6294b6c993607a171d2 100644 --- a/src/share/classes/javax/management/openmbean/CompositeDataSupport.java +++ b/src/share/classes/javax/management/openmbean/CompositeDataSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -355,6 +355,7 @@ public class CompositeDataSupport * @return true if the specified object is equal to this * CompositeDataSupport instance. */ + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -419,6 +420,7 @@ public class CompositeDataSupport * * @return the hash code value for this CompositeDataSupport instance */ + @Override public int hashCode() { int hashcode = compositeType.hashCode(); @@ -457,16 +459,28 @@ public class CompositeDataSupport * * @return a string representation of this CompositeDataSupport instance */ + @Override public String toString() { - return new StringBuilder() .append(this.getClass().getName()) .append("(compositeType=") .append(compositeType.toString()) .append(",contents=") - .append(contents.toString()) + .append(contentString()) .append(")") .toString(); } + private String contentString() { + StringBuilder sb = new StringBuilder("{"); + String sep = ""; + for (Map.Entry entry : contents.entrySet()) { + sb.append(sep).append(entry.getKey()).append("="); + String s = Arrays.deepToString(new Object[] {entry.getValue()}); + sb.append(s.substring(1, s.length() - 1)); + sep = ", "; + } + sb.append("}"); + return sb.toString(); + } } diff --git a/src/share/classes/javax/management/openmbean/CompositeType.java b/src/share/classes/javax/management/openmbean/CompositeType.java index b513b0faa9af1aaae461d123ab53c81d9b122388..b4c662ec9bce8a7f0e91a112c990fa6f3dc666fb 100644 --- a/src/share/classes/javax/management/openmbean/CompositeType.java +++ b/src/share/classes/javax/management/openmbean/CompositeType.java @@ -89,7 +89,7 @@ public class CompositeType extends OpenType { *
        * @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 @@ public class CompositeType extends OpenType { * @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 @@ public class CompositeType extends OpenType { // 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 --git a/src/share/classes/javax/management/openmbean/MXBeanMapping.java b/src/share/classes/javax/management/openmbean/MXBeanMapping.java index 216912a4e3172085302686d7737647d5dc5b925f..339fbb21c0933ed4ce46ac28d89688837229d8ba 100644 --- a/src/share/classes/javax/management/openmbean/MXBeanMapping.java +++ b/src/share/classes/javax/management/openmbean/MXBeanMapping.java @@ -108,6 +108,9 @@ import java.lang.reflect.Type; *

      If we are unable to modify the {@code MyLinkedList} class, * we can define an {@link MXBeanMappingFactory}. See the documentation * of that class for further details.

      + * + * @see MXBean specification, section + * "Custom MXBean type mappings" */ public abstract class MXBeanMapping { private final Type javaType; diff --git a/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java b/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java index 0820bf86a5ddfa5be838eb27ac9ea9dc3fc9b956..d5808c3a1eb4042da782568e90b213eeb60d8358 100644 --- a/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java +++ b/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java @@ -82,6 +82,9 @@ import java.lang.reflect.Type; * appears in, or we can supply the factory to a {@link * javax.management.StandardMBean StandardMBean} constructor or MXBean * proxy.

      + * + * @see MXBean specification, section + * "Custom MXBean type mappings" */ public abstract class MXBeanMappingFactory { /** diff --git a/src/share/classes/javax/management/openmbean/TabularDataSupport.java b/src/share/classes/javax/management/openmbean/TabularDataSupport.java index f01b8e0a7589914c559f9d637b9eaef49848e20b..4e0c51cc9bae522179fab1980b25c41d9f5d173c 100644 --- a/src/share/classes/javax/management/openmbean/TabularDataSupport.java +++ b/src/share/classes/javax/management/openmbean/TabularDataSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -29,15 +29,18 @@ package javax.management.openmbean; // java import // +import com.sun.jmx.mbeanserver.GetPropertyAction; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; +import java.security.AccessController; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -79,12 +82,13 @@ public class TabularDataSupport /** * @serial This tabular data instance's contents: a {@link HashMap} */ + // field cannot be final because of clone method private Map dataMap; /** * @serial This tabular data instance's tabular type */ - private TabularType tabularType; + private final TabularType tabularType; /** * The array of item names that define the index used for rows (convenience field) @@ -109,7 +113,7 @@ public class TabularDataSupport */ public TabularDataSupport(TabularType tabularType) { - this(tabularType, 101, 0.75f); + this(tabularType, 16, 0.75f); } /** @@ -141,10 +145,18 @@ public class TabularDataSupport List tmpNames = tabularType.getIndexNames(); this.indexNamesArray = tmpNames.toArray(new String[tmpNames.size()]); + // Since LinkedHashMap was introduced in SE 1.4, it's conceivable even + // if very unlikely that we might be the server of a 1.3 client. In + // that case you'll need to set this property. See CR 6334663. + String useHashMapProp = AccessController.doPrivileged( + new GetPropertyAction("jmx.tabular.data.hash.map")); + boolean useHashMap = "true".equalsIgnoreCase(useHashMapProp); + // Construct the empty contents HashMap // - this.dataMap = - new HashMap(initialCapacity, loadFactor); + this.dataMap = useHashMap ? + new HashMap(initialCapacity, loadFactor) : + new LinkedHashMap(initialCapacity, loadFactor); } diff --git a/src/share/classes/javax/management/relation/RelationService.java b/src/share/classes/javax/management/relation/RelationService.java index 5950aafa573438bbf685b90c13d7c4d161948610..98a4809ea4173433362b98cc6e0761566c55a565 100644 --- a/src/share/classes/javax/management/relation/RelationService.java +++ b/src/share/classes/javax/management/relation/RelationService.java @@ -108,7 +108,7 @@ public class RelationService extends NotificationBroadcasterSupport // the value HashMap mapping: // -> ArrayList of // to track where a given MBean is referenced. - private Map>> + private final Map>> myRefedMBeanObjName2RelIdsMap = new HashMap>>(); @@ -1492,7 +1492,7 @@ public class RelationService extends NotificationBroadcasterSupport // Clones the list of notifications to be able to still receive new // notifications while proceeding those ones List localUnregNtfList; - synchronized(myUnregNtfList) { + synchronized(myRefedMBeanObjName2RelIdsMap) { localUnregNtfList = new ArrayList(myUnregNtfList); // Resets list diff --git a/src/share/classes/javax/management/remote/IdentityMBeanServerForwarder.java b/src/share/classes/javax/management/remote/IdentityMBeanServerForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..0b1e996d7474217d86da2c9e20ece42c23b5ec3b --- /dev/null +++ b/src/share/classes/javax/management/remote/IdentityMBeanServerForwarder.java @@ -0,0 +1,303 @@ +/* + * 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.remote; + +import java.io.ObjectInputStream; +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; + +/** + * An {@link MBeanServerForwarder} that forwards all {@link MBeanServer} + * operations unchanged to the next {@code MBeanServer} in the chain. + * This class is typically subclassed to override some but not all methods. + */ +public class IdentityMBeanServerForwarder implements MBeanServerForwarder { + + private MBeanServer next; + + /** + *

      Construct a forwarder that has no next {@code MBeanServer}. + * The resulting object will be unusable until {@link #setMBeanServer + * setMBeanServer} is called to establish the next item in the chain.

      + */ + public IdentityMBeanServerForwarder() { + } + + /** + *

      Construct a forwarder that forwards to the given {@code MBeanServer}. + * It is not an error for {@code next} to be null, but the resulting object + * will be unusable until {@link #setMBeanServer setMBeanServer} is called + * to establish the next item in the chain.

      + */ + public IdentityMBeanServerForwarder(MBeanServer next) { + this.next = next; + } + + public synchronized MBeanServer getMBeanServer() { + return next; + } + + public synchronized void setMBeanServer(MBeanServer mbs) { + next = mbs; + } + + private synchronized MBeanServer next() { + return next; + } + + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + next().unregisterMBean(name); + } + + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + return next().setAttributes(name, attributes); + } + + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + next().setAttribute(name, attribute); + } + + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + next().removeNotificationListener(name, listener, filter, handback); + } + + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + next().removeNotificationListener(name, listener); + } + + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + next().removeNotificationListener(name, listener, filter, handback); + } + + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + next().removeNotificationListener(name, listener); + } + + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + return next().registerMBean(object, name); + } + + public Set queryNames(ObjectName name, QueryExp query) { + return next().queryNames(name, query); + } + + public Set queryMBeans(ObjectName name, QueryExp query) { + return next().queryMBeans(name, query); + } + + public boolean isRegistered(ObjectName name) { + return next().isRegistered(name); + } + + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + return next().isInstanceOf(name, className); + } + + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, + ReflectionException { + return next().invoke(name, operationName, params, signature); + } + + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + return next().instantiate(className, loaderName, params, signature); + } + + public Object instantiate(String className, Object[] params, + String[] signature) + throws ReflectionException, MBeanException { + return next().instantiate(className, params, signature); + } + + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + return next().instantiate(className, loaderName); + } + + public Object instantiate(String className) + throws ReflectionException, MBeanException { + return next().instantiate(className); + } + + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + return next().getObjectInstance(name); + } + + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + return next().getMBeanInfo(name); + } + + public Integer getMBeanCount() { + return next().getMBeanCount(); + } + + public String[] getDomains() { + return next().getDomains(); + } + + public String getDefaultDomain() { + return next().getDefaultDomain(); + } + + public ClassLoaderRepository getClassLoaderRepository() { + return next().getClassLoaderRepository(); + } + + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return next().getClassLoaderFor(mbeanName); + } + + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + return next().getClassLoader(loaderName); + } + + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + return next().getAttributes(name, attributes); + } + + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + return next().getAttribute(name, attribute); + } + + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, + byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + return next().deserialize(className, loaderName, data); + } + + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + return next().deserialize(className, data); + } + + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + return next().deserialize(name, data); + } + + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, + String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return next().createMBean(className, name, loaderName, params, signature); + } + + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return next().createMBean(className, name, params, signature); + } + + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return next().createMBean(className, name, loaderName); + } + + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return next().createMBean(className, name); + } + + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + next().addNotificationListener(name, listener, filter, handback); + } + + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + next().addNotificationListener(name, listener, filter, handback); + } +} diff --git a/src/share/classes/javax/management/remote/JMXConnector.java b/src/share/classes/javax/management/remote/JMXConnector.java index 9ac3aa04304e7d8cc0948d769904ae92077133fe..1909a5afd3c01675f533f7f813f240e9c4affb65 100644 --- a/src/share/classes/javax/management/remote/JMXConnector.java +++ b/src/share/classes/javax/management/remote/JMXConnector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 @@ -57,6 +57,26 @@ public interface JMXConnector extends Closeable { public static final String CREDENTIALS = "jmx.remote.credentials"; + /** + *

      Name of the attribute that specifies whether to use the + * {@linkplain javax.management.event Event Service} to handle + * notifications for this connector. The value associated with + * this attribute, if any, is a String, which must be equal, + * ignoring case, to {@code "true"} or {@code "false"}.

      + * + *

      Not all connectors will understand this attribute, but the + * standard {@linkplain javax.management.remote.rmi.RMIConnector + * RMI Connector} does.

      + * + *

      If this attribute is not present, then the system property of the + * same name ({@value}) is consulted. If that is not set + * either, then the Event Service is not used.

      + * + * @since 1.7 + */ + public static final String USE_EVENT_SERVICE = + "jmx.remote.use.event.service"; + /** *

      Establishes the connection to the connector server. This * method is equivalent to {@link #connect(Map) diff --git a/src/share/classes/javax/management/remote/JMXConnectorFactory.java b/src/share/classes/javax/management/remote/JMXConnectorFactory.java index 23003f007c596acd6bec82154846f7bb4ce30c23..219865b603c9dc1e07d5b8fb5aaaceb841c65b11 100644 --- a/src/share/classes/javax/management/remote/JMXConnectorFactory.java +++ b/src/share/classes/javax/management/remote/JMXConnectorFactory.java @@ -268,6 +268,14 @@ public class JMXConnectorFactory { 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 class JMXConnectorFactory { 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 @@ public class JMXConnectorFactory { } } - 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 @@ public class JMXConnectorFactory { 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 @@ public class JMXConnectorFactory { 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 @@ public class JMXConnectorFactory { } if (loader == null) - loader = - AccessController.doPrivileged(new PrivilegedAction() { + loader = AccessController.doPrivileged( + new PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); diff --git a/src/share/classes/javax/management/remote/JMXConnectorServer.java b/src/share/classes/javax/management/remote/JMXConnectorServer.java index 240bc3bdc0ebae8053a7f399d574afda5a962781..88348ff5de39d5517f7c4a3409f11c2ce7261937 100644 --- a/src/share/classes/javax/management/remote/JMXConnectorServer.java +++ b/src/share/classes/javax/management/remote/JMXConnectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,17 +26,21 @@ package javax.management.remote; +import com.sun.jmx.remote.util.EnvHelp; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; +import javax.management.MBeanInfo; // for javadoc import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; +import javax.management.event.EventClientDelegate; /** *

      Superclass of every connector server. A connector server is @@ -75,6 +79,48 @@ public abstract class JMXConnectorServer public static final String AUTHENTICATOR = "jmx.remote.authenticator"; + /** + *

      Name of the attribute that specifies whether this connector + * server can delegate notification handling to the + * {@linkplain javax.management.event Event Service}. + * The value associated with + * this attribute, if any, is a String, which must be equal, + * ignoring case, to {@code "true"} or {@code "false"}.

      + * + *

      Not all connector servers will understand this attribute, but the + * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer + * RMI Connector Server} does.

      + * + *

      If this attribute is not present, then the system property of the + * same name ({@value}) is consulted. If that is not set + * either, then the Event Service is used if the connector server + * supports it.

      + * + * @since 1.7 + */ + public static final String DELEGATE_TO_EVENT_SERVICE = + "jmx.remote.delegate.event.service"; + + /** + *

      Name of the attribute that specifies whether this connector + * server simulates the existence of the {@link EventClientDelegate} + * MBean. The value associated with this attribute, if any, must + * be a string that is equal to {@code "true"} or {@code "false"}, + * ignoring case. If it is {@code "true"}, then the connector server + * will simulate an EventClientDelegate MBean, as described in {@link + * EventClientDelegate#newForwarder}. This MBean is needed for {@link + * javax.management.event.EventClient EventClient} to function correctly.

      + * + *

      Not all connector servers will understand this attribute, but the + * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer + * RMI Connector Server} does. For a connector server that understands + * this attribute, the default value is {@code "true"}.

      + * + * @since 1.7 + */ + public static final String EVENT_CLIENT_DELEGATE_FORWARDER = + "jmx.remote.event.client.delegate.forwarder"; + /** *

      Constructs a connector server that will be registered as an * MBean in the MBean server it is attached to. This constructor @@ -89,34 +135,274 @@ public abstract class JMXConnectorServer /** *

      Constructs a connector server that is attached to the given * MBean server. A connector server that is created in this way - * can be registered in a different MBean server.

      + * can be registered in a different MBean server, or not registered + * in any MBean server.

      * * @param mbeanServer the MBean server that this connector server * is attached to. Null if this connector server will be attached * to an MBean server by being registered in it. */ public JMXConnectorServer(MBeanServer mbeanServer) { - this.mbeanServer = mbeanServer; + insertUserMBeanServer(mbeanServer); } /** *

      Returns the MBean server that this connector server is - * attached to.

      + * attached to, or the first in a chain of user-added + * {@link MBeanServerForwarder}s, if any.

      * * @return the MBean server that this connector server is attached * to, or null if it is not yet attached to an MBean server. + * + * @see #setMBeanServerForwarder + * @see #getSystemMBeanServer */ public synchronized MBeanServer getMBeanServer() { - return mbeanServer; + return userMBeanServer; } - public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) - { + public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) { + if (mbsf == null) + throw new IllegalArgumentException("Invalid null argument: mbsf"); + + if (userMBeanServer != null) + mbsf.setMBeanServer(userMBeanServer); + insertUserMBeanServer(mbsf); + } + + /** + *

      Remove a forwarder from the chain of forwarders. The forwarder can + * be in the system chain or the user chain. On successful return from + * this method, the first occurrence in the chain of an object that is + * {@linkplain Object#equals equal} to {@code mbsf} will have been + * removed.

      + * @param mbsf the forwarder to remove + * @throws NoSuchElementException if there is no occurrence of {@code mbsf} + * in the chain. + * @throws IllegalArgumentException if {@code mbsf} is null. + */ + public synchronized void removeMBeanServerForwarder(MBeanServerForwarder mbsf) { if (mbsf == null) throw new IllegalArgumentException("Invalid null argument: mbsf"); - if (mbeanServer != null) mbsf.setMBeanServer(mbeanServer); - mbeanServer = mbsf; + MBeanServerForwarder prev = null; + MBeanServer curr = systemMBeanServer; + while (curr instanceof MBeanServerForwarder && !mbsf.equals(curr)) { + prev = (MBeanServerForwarder) curr; + curr = prev.getMBeanServer(); + } + if (!(curr instanceof MBeanServerForwarder)) + throw new NoSuchElementException("MBeanServerForwarder not in chain"); + MBeanServerForwarder deleted = (MBeanServerForwarder) curr; + MBeanServer next = deleted.getMBeanServer(); + if (prev != null) + prev.setMBeanServer(next); + if (systemMBeanServer == deleted) + systemMBeanServer = next; + if (userMBeanServer == deleted) + userMBeanServer = next; + } + + /* + * Set userMBeanServer to mbs and arrange for the end of the chain of + * system MBeanServerForwarders to point to it. See the comment before + * the systemMBeanServer and userMBeanServer field declarations. + */ + private void insertUserMBeanServer(MBeanServer mbs) { + MBeanServerForwarder lastSystemMBSF = null; + for (MBeanServer mbsi = systemMBeanServer; + mbsi != userMBeanServer; + mbsi = lastSystemMBSF.getMBeanServer()) { + lastSystemMBSF = (MBeanServerForwarder) mbsi; + } + userMBeanServer = mbs; + if (lastSystemMBSF == null) + systemMBeanServer = mbs; + else + lastSystemMBSF.setMBeanServer(mbs); + } + + /** + *

      Returns the first item in the chain of system and then user + * forwarders. In the simplest case, a {@code JMXConnectorServer} + * is connected directly to an {@code MBeanServer}. But there can + * also be a chain of {@link MBeanServerForwarder}s between the two. + * This chain consists of two sub-chains: first the system chain + * and then the user chain. Incoming requests are given to the + * first forwarder in the system chain. Each forwarder can handle + * a request itself, or more usually forward it to the next forwarder, + * perhaps with some extra behavior such as logging or security + * checking before or after the forwarding. The last forwarder in + * the system chain is followed by the first forwarder in the user + * chain.

      + * + *

      The system chain is usually + * defined by a connector server based on the environment Map; + * see {@link JMXConnectorServerFactory#newJMXConnectorServer}. Allowing the + * connector server to define its forwarders in this way ensures that + * they are in the correct order - some forwarders need to be inserted + * before others for correct behavior. It is possible to modify the + * system chain, for example using {@link #setSystemMBeanServerForwarder} or + * {@link #removeMBeanServerForwarder}, but in that case the system + * chain is no longer guaranteed to be correct.

      + * + *

      The user chain is defined by calling {@link + * #setMBeanServerForwarder} to insert forwarders at the head of the user + * chain.

      + * + *

      If there are no forwarders in either chain, then both + * {@link #getMBeanServer()} and {@code getSystemMBeanServer()} will + * return the {@code MBeanServer} for this connector server. If there + * are forwarders in the user chain but not the system chain, then + * both methods will return the first forwarder in the user chain. + * If there are forwarders in the system chain but not the user chain, + * then {@code getSystemMBeanServer()} will return the first forwarder + * in the system chain, and {@code getMBeanServer()} will return the + * {@code MBeanServer} for this connector server. Finally, if there + * are forwarders in each chain then {@code getSystemMBeanServer()} + * will return the first forwarder in the system chain, and {@code + * getMBeanServer()} will return the first forwarder in the user chain.

      + * + *

      This code illustrates how the chains can be traversed:

      + * + *
      +     * JMXConnectorServer cs;
      +     * System.out.println("system chain:");
      +     * MBeanServer mbs = cs.getSystemMBeanServer();
      +     * while (true) {
      +     *     if (mbs == cs.getMBeanServer())
      +     *         System.out.println("user chain:");
      +     *     if (!(mbs instanceof MBeanServerForwarder))
      +     *         break;
      +     *     MBeanServerForwarder mbsf = (MBeanServerForwarder) mbs;
      +     *     System.out.println("--forwarder: " + mbsf);
      +     *     mbs = mbsf.getMBeanServer();
      +     * }
      +     * System.out.println("--MBean Server");
      +     * 
      + * + * @return the first item in the system chain of forwarders. + * + * @see #setSystemMBeanServerForwarder + */ + public synchronized MBeanServer getSystemMBeanServer() { + return systemMBeanServer; + } + + /** + *

      Inserts an object that intercepts requests for the MBean server + * that arrive through this connector server. This object will be + * supplied as the MBeanServer for any new connection + * created by this connector server. Existing connections are + * unaffected.

      + * + *

      This method can be called more than once with different + * {@link MBeanServerForwarder} objects. The result is a chain + * of forwarders. The last forwarder added is the first in the chain.

      + * + *

      This method modifies the system chain of {@link MBeanServerForwarder}s. + * Usually user code should change the user chain instead, via + * {@link #setMBeanServerForwarder}.

      + * + *

      Not all connector servers support a system chain of forwarders. + * Calling this method on a connector server that does not will produce an + * {@link UnsupportedOperationException}.

      + * + *

      Suppose {@code mbs} is the result of {@link #getSystemMBeanServer()} + * before calling this method. If {@code mbs} is not null, then + * {@code mbsf.setMBeanServer(mbs)} will be called. If doing so + * produces an exception, this method throws the same exception without + * any other effect. If {@code mbs} is null, or if the call to + * {@code mbsf.setMBeanServer(mbs)} succeeds, then this method will + * return normally and {@code getSystemMBeanServer()} will then return + * {@code mbsf}.

      + * + *

      The result of {@link #getMBeanServer()} is unchanged by this method.

      + * + * @param mbsf the new MBeanServerForwarder. + * + * @throws IllegalArgumentException if the call to {@link + * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails + * with IllegalArgumentException, or if + * mbsf is null. + * + * @throws UnsupportedOperationException if + * {@link #supportsSystemMBeanServerForwarder} returns false. + * + * @see #getSystemMBeanServer() + */ + public synchronized void setSystemMBeanServerForwarder( + MBeanServerForwarder mbsf) { + if (mbsf == null) + throw new IllegalArgumentException("Invalid null argument: mbsf"); + mustSupportSystemMBSF(); + + if (systemMBeanServer != null) + mbsf.setMBeanServer(systemMBeanServer); + systemMBeanServer = mbsf; + } + + /** + *

      Returns true if this connector server supports a system chain of + * {@link MBeanServerForwarder}s. The default implementation of this + * method returns false. Connector servers that do support the system + * chain must override this method to return true. + * + * @return true if this connector server supports the system chain of + * forwarders. + */ + public boolean supportsSystemMBeanServerForwarder() { + return false; + } + + private void mustSupportSystemMBSF() { + if (!supportsSystemMBeanServerForwarder()) { + throw new UnsupportedOperationException( + "System MBeanServerForwarder not supported by this " + + "connector server"); + } + } + + /** + *

      Install {@link MBeanServerForwarder}s in the system chain + * based on the attributes in the given {@code Map}. A connector + * server that {@linkplain #supportsSystemMBeanServerForwarder supports} + * a system chain of {@code MBeanServerForwarder}s can call this method + * to add forwarders to that chain based on the contents of {@code env}. + * In order:

      + * + *
        + * + *
      • If {@link #EVENT_CLIENT_DELEGATE_FORWARDER} is absent, or is + * present with the value {@code "true"}, then a forwarder with the + * functionality of {@link EventClientDelegate#newForwarder} is inserted + * at the start of the system chain.
      • + * + *
      + * + *

      For {@code EVENT_CLIENT_DELEGATE_FORWARDER}, if the + * attribute is absent from the {@code Map} and a system property + * of the same name is defined, then the value of the system + * property is used as if it were in the {@code Map}. + * + *

      Attributes in {@code env} that are not listed above are ignored + * by this method.

      + * + * @throws UnsupportedOperationException if {@link + * #supportsSystemMBeanServerForwarder} is false. + */ + protected void installStandardForwarders(Map env) { + mustSupportSystemMBSF(); + + // Remember that forwarders must be added in reverse order! + + boolean ecd = EnvHelp.computeBooleanFromString( + env, EVENT_CLIENT_DELEGATE_FORWARDER, false, true); + + if (ecd) { + MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(); + setSystemMBeanServerForwarder(mbsf); + } } public String[] getConnectionIds() { @@ -359,8 +645,8 @@ public abstract class JMXConnectorServer ObjectName name) { if (mbs == null || name == null) throw new NullPointerException("Null MBeanServer or ObjectName"); - if (mbeanServer == null) { - mbeanServer = mbs; + if (userMBeanServer == null) { + insertUserMBeanServer(mbs); myName = name; } return name; @@ -394,10 +680,53 @@ public abstract class JMXConnectorServer myName = null; } - /** - * The MBeanServer used by this server to execute a client request. + /* + * Fields describing the chains of forwarders (MBeanServerForwarders). + * In the general case, the forwarders look something like this: + * + * systemMBeanServer userMBeanServer + * | | + * v v + * mbsf1 -> mbsf2 -> mbsf3 -> mbsf4 -> mbsf5 -> mbs + * + * Here, each mbsfi is an MBeanServerForwarder, and the arrows + * illustrate its getMBeanServer() method. The last MBeanServerForwarder + * can point to an MBeanServer that is not instanceof MBeanServerForwarder, + * here mbs. + * + * Initially, the chain can be empty if this JMXConnectorServer was + * constructed without an MBeanServer. In this case, both systemMBS + * and userMBS will be null. If there is initially an MBeanServer, + * then both systemMBS and userMBS will point to it. + * + * Whenever userMBS is changed, the system chain must be updated. If there + * are forwarders in the system chain (between systemMBS and userMBS in the + * picture above), then the last one must point to the old value of userMBS + * (possibly null). It must be updated to point to the new value. If there + * are no forwarders in the system chain, then systemMBS must be updated to + * the new value of userMBS. The invariant is that starting from systemMBS + * and repeatedly calling MBSF.getMBeanServer() you will end up at + * userMBS. The implication is that you will not see any MBeanServer + * object on the way that is not also an MBeanServerForwarder. + * + * The method insertUserMBeanServer contains the logic to change userMBS + * and adjust the system chain appropriately. + * + * If userMBS is null and this JMXConnectorServer is registered in an + * MBeanServer, then userMBS becomes that MBeanServer, and the system + * chain must be updated as just described. + * + * When systemMBS is updated, there is no effect on userMBS. The system + * chain may contain forwarders even though the user chain is empty + * (there is no MBeanServer). In that case an attempt to forward an + * incoming request through the chain will fall off the end and fail with a + * NullPointerException. Usually a connector server will refuse to start() + * if it is not attached to an MBS, so this situation should not arise. */ - private MBeanServer mbeanServer = null; + + private MBeanServer userMBeanServer; + + private MBeanServer systemMBeanServer; /** * The name used to registered this server in an MBeanServer. diff --git a/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java b/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java index a641f3c98d943f5825504cafccb3b4b5ec9dcc4f..4de8cbf5e26859a0580d5a3792a1f26e18bd4514 100644 --- a/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java +++ b/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java @@ -35,10 +35,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.ServiceLoader; import javax.management.MBeanServer; -import javax.management.ObjectName; /** *

      Factory to create JMX API connector servers. There @@ -172,7 +170,8 @@ public class JMXConnectorServerFactory { * loader MBean name. This class loader is used to deserialize objects in * requests received from the client, possibly after consulting an * MBean-specific class loader. The value associated with this - * attribute is an instance of {@link ObjectName}.

      + * attribute is an instance of {@link javax.management.ObjectName + * ObjectName}.

      */ public static final String DEFAULT_CLASS_LOADER_NAME = "jmx.remote.default.class.loader.name"; diff --git a/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java b/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java index 048e5a92192d679a94c2d68742da5d94710fb53c..fb6f883a2b74f63bd110ea59b1ce24fe8d7196ac 100644 --- a/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java +++ b/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 @@ -105,23 +105,34 @@ public interface JMXConnectorServerMBean { public boolean isActive(); /** - *

      Adds an object that intercepts requests for the MBean server + *

      Inserts an object that intercepts requests for the MBean server * that arrive through this connector server. This object will be * supplied as the MBeanServer for any new connection * created by this connector server. Existing connections are * unaffected.

      * - *

      If this connector server is already associated with an + *

      This method can be called more than once with different + * {@link MBeanServerForwarder} objects. The result is a chain + * of forwarders. The last forwarder added is the first in the chain. + * In more detail:

      + * + *
        + *
      • If this connector server is already associated with an * MBeanServer object, then that object is given to * {@link MBeanServerForwarder#setMBeanServer * mbsf.setMBeanServer}. If doing so produces an exception, this * method throws the same exception without any other effect.

        * - *

        If this connector is not already associated with an + *

      • If this connector is not already associated with an * MBeanServer object, or if the * mbsf.setMBeanServer call just mentioned succeeds, * then mbsf becomes this connector server's * MBeanServer.

        + *
      + * + *

      A connector server may support two chains of forwarders, + * a system chain and a user chain. See {@link + * JMXConnectorServer#setSystemMBeanServerForwarder} for details.

      * * @param mbsf the new MBeanServerForwarder. * @@ -129,6 +140,8 @@ public interface JMXConnectorServerMBean { * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails * with IllegalArgumentException. This includes the * case where mbsf is null. + * + * @see JMXConnectorServer#setSystemMBeanServerForwarder */ public void setMBeanServerForwarder(MBeanServerForwarder mbsf); diff --git a/src/share/classes/javax/management/remote/JMXServiceURL.java b/src/share/classes/javax/management/remote/JMXServiceURL.java index f2b19c5ef0befd50e78ba73bc037f9a9d189b81e..06b3b92f91a69fcd4615a7b74a3105f1dc7e3f9d 100644 --- a/src/share/classes/javax/management/remote/JMXServiceURL.java +++ b/src/share/classes/javax/management/remote/JMXServiceURL.java @@ -30,13 +30,14 @@ package javax.management.remote; 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 @@ public class JMXServiceURL implements Serializable { * 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 @@ public class JMXServiceURL implements Serializable { 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 --git a/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java b/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java index bff48451f9a8fce1ecb770fd2d6bb73bb14e5d79..a87d146e94ef2b52b1a7023929cf4ae707354354 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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,10 +25,12 @@ package javax.management.remote.rmi; +import com.sun.jmx.mbeanserver.Util; import static com.sun.jmx.mbeanserver.Util.cast; import com.sun.jmx.remote.internal.ServerCommunicatorAdmin; import com.sun.jmx.remote.internal.ServerNotifForwarder; import com.sun.jmx.remote.security.JMXSubjectDomainCombiner; +import com.sun.jmx.remote.security.NotificationAccessController; import com.sun.jmx.remote.security.SubjectDelegator; import com.sun.jmx.remote.util.ClassLoaderWithRepository; import com.sun.jmx.remote.util.ClassLogger; @@ -36,6 +38,7 @@ import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.OrderClassLoaders; import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; import java.rmi.MarshalledObject; import java.rmi.UnmarshalException; import java.rmi.server.Unreferenced; @@ -56,19 +59,25 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.InvalidAttributeValueException; +import javax.management.JMX; 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.Notification; import javax.management.NotificationFilter; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; -import javax.management.loading.ClassLoaderRepository; +import javax.management.event.EventClientDelegate; +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; @@ -149,28 +158,16 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { new PrivilegedAction() { public ClassLoaderWithRepository run() { return new ClassLoaderWithRepository( - getClassLoaderRepository(), - dcl); + mbeanServer.getClassLoaderRepository(), + dcl); } }); - serverCommunicatorAdmin = new RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env)); this.env = env; } - private synchronized ServerNotifForwarder getServerNotifFwd() { - // Lazily created when first use. Mainly when - // addNotificationListener is first called. - if (serverNotifForwarder == null) - serverNotifForwarder = - new ServerNotifForwarder(mbeanServer, - env, - rmiServer.getNotifBuffer(), - connectionId); - return serverNotifForwarder; - } public String getConnectionId() throws IOException { // We should call reqIncomming() here... shouldn't we? @@ -181,6 +178,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { final boolean debug = logger.debugOn(); final String idstr = (debug?"["+this.toString()+"]":null); + final SubscriptionManager mgr; synchronized (this) { if (terminated) { if (debug) logger.debug("close",idstr + " already terminated."); @@ -195,11 +193,12 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { serverCommunicatorAdmin.terminate(); } - if (serverNotifForwarder != null) { - serverNotifForwarder.terminate(); - } + mgr = subscriptionManager; + subscriptionManager = null; } + if (mgr != null) mgr.terminate(); + rmiServer.clientClosed(this); if (debug) logger.debug("close",idstr + " closed."); @@ -955,8 +954,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { int i=0; ClassLoader targetCl; NotificationFilter[] filterValues = - new NotificationFilter[names.length]; - Object params[]; + new NotificationFilter[names.length]; Integer[] ids = new Integer[names.length]; final boolean debug=logger.debugOn(); @@ -991,8 +989,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { // remove all registered listeners for (int j=0; j action = - new PrivilegedAction() { - public NotificationResult run() { - return getServerNotifFwd().fetchNotifs(csn, t, mn); + + final PrivilegedExceptionAction action = + new PrivilegedExceptionAction() { + public NotificationResult run() throws IOException { + return doFetchNotifs(csn, t, mn); } }; - if (acc == null) - return action.run(); - else - return AccessController.doPrivileged(action, acc); + try { + if (acc == null) + return action.run(); + else + return AccessController.doPrivileged(action, acc); + } catch (IOException x) { + throw x; + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + // should not happen + throw new UndeclaredThrowableException(x); + } + } finally { serverCommunicatorAdmin.rspOutgoing(); } } + /** + * This is an abstraction class that let us use the legacy + * ServerNotifForwarder and the new EventClientDelegateMBean + * indifferently. + **/ + private static interface SubscriptionManager { + public void removeNotificationListener(ObjectName name, Integer id) + throws InstanceNotFoundException, ListenerNotFoundException, IOException; + public void removeNotificationListener(ObjectName name, Integer[] ids) + throws Exception; + public NotificationResult fetchNotifications(long csn, long timeout, int maxcount) + throws IOException; + public Integer addNotificationListener(ObjectName name, NotificationFilter filter) + throws InstanceNotFoundException, IOException; + public void terminate() + throws IOException; + } + + /** + * A SubscriptionManager that uses a ServerNotifForwarder. + **/ + private static class LegacySubscriptionManager implements SubscriptionManager { + private final ServerNotifForwarder forwarder; + LegacySubscriptionManager(ServerNotifForwarder forwarder) { + this.forwarder = forwarder; + } + + 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); + } + + public NotificationResult fetchNotifications(long csn, long timeout, int maxcount) { + return forwarder.fetchNotifs(csn,timeout,maxcount); + } + + 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); + } + + public void terminate() { + forwarder.terminate(); + } + } + + /** + * A SubscriptionManager that uses an EventClientDelegateMBean. + **/ + private static class EventSubscriptionManager + implements SubscriptionManager { + private final MBeanServer mbeanServer; + private final EventClientDelegateMBean delegate; + private final NotificationAccessController notifAC; + private final boolean checkNotificationEmission; + private final String clientId; + private final String connectionId; + private volatile String mbeanServerName; + + EventSubscriptionManager( + MBeanServer mbeanServer, + EventClientDelegateMBean delegate, + Map env, + String clientId, + String connectionId) { + this.mbeanServer = mbeanServer; + this.delegate = delegate; + this.notifAC = EnvHelp.getNotificationAccessController(env); + this.checkNotificationEmission = + EnvHelp.computeBooleanFromString( + env, "jmx.remote.x.check.notification.emission", false); + this.clientId = clientId; + 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; + private final ObjectName name; + + AccessControlFilter(ObjectName name, NotificationFilter wrapped) { + this.name = name; + this.wrapped = wrapped; + } + + public boolean isNotificationEnabled(Notification notification) { + try { + if (checkNotificationEmission) { + ServerNotifForwarder.checkMBeanPermission( + mbeanServerName(), mbeanServer, name, + "addNotificationListener"); + } + notifAC.fetchNotification( + connectionId, name, notification, getSubject()); + return (wrapped == null) ? true : + wrapped.isNotificationEnabled(notification); + } catch (InstanceNotFoundException e) { + return false; + } catch (SecurityException e) { + return false; + } + } + + } + + public Integer addNotificationListener( + ObjectName name, NotificationFilter filter) + throws InstanceNotFoundException, IOException { + if (notifAC != null) { + notifAC.addNotificationListener(connectionId, name, getSubject()); + filter = new AccessControlFilter(name, filter); + } + try { + return delegate.addListener(clientId,name,filter); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + } + + public void removeNotificationListener(ObjectName name, Integer id) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + if (notifAC != null) + notifAC.removeNotificationListener(connectionId, name, getSubject()); + try { + delegate.removeListenerOrSubscriber(clientId, id); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + } + + public void removeNotificationListener(ObjectName name, Integer[] ids) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + if (notifAC != null) + notifAC.removeNotificationListener(connectionId, name, getSubject()); + try { + for (Integer id : ids) + delegate.removeListenerOrSubscriber(clientId, id); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + } + + public NotificationResult fetchNotifications(long csn, long timeout, + int maxcount) + throws IOException { + try { + // For some reason the delegate doesn't accept a negative + // sequence number. However legacy clients will always call + // fetchNotifications with a negative sequence number, when + // they call it for the first time. + // In that case, we will use 0 instead. + // + return delegate.fetchNotifications( + clientId, Math.max(csn, 0), maxcount, timeout); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + } + + public void terminate() + throws IOException { + try { + delegate.removeClient(clientId); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + } + + private static Subject getSubject() { + return Subject.getSubject(AccessController.getContext()); + } + } + + /** + * Creates a SubscriptionManager that uses either the legacy notifications + * mechanism (ServerNotifForwarder) or the new event service + * (EventClientDelegateMBean) depending on which option was passed in + * the connector's map. + **/ + private SubscriptionManager createSubscriptionManager() + throws IOException { + if (EnvHelp.delegateToEventService(env) && + mbeanServer.isRegistered(EventClientDelegate.OBJECT_NAME)) { + final EventClientDelegateMBean mbean = + JMX.newMBeanProxy(mbeanServer, + EventClientDelegate.OBJECT_NAME, + EventClientDelegateMBean.class); + String clientId; + try { + clientId = + mbean.addClient( + FetchingEventForwarder.class.getName(), + new Object[] {EnvHelp.getNotifBufferSize(env)}, + new String[] {int.class.getName()}); + } catch (Exception e) { + if (e instanceof IOException) + throw (IOException) e; + else + throw new IOException(e); + } + + // we're going to call remove client... + try { + mbean.lease(clientId, Long.MAX_VALUE); + } catch (EventClientNotFoundException x) { + throw new IOException("Unknown clientId: "+clientId,x); + } + return new EventSubscriptionManager(mbeanServer, mbean, env, + clientId, connectionId); + } else { + final ServerNotifForwarder serverNotifForwarder = + new ServerNotifForwarder(mbeanServer, + env, + rmiServer.getNotifBuffer(), + connectionId); + return new LegacySubscriptionManager(serverNotifForwarder); + } + } + + /** + * Lazy creation of a SubscriptionManager. + **/ + private synchronized SubscriptionManager getSubscriptionManager() + throws IOException { + // Lazily created when first use. Mainly when + // addNotificationListener is first called. + + if (subscriptionManager == null) { + subscriptionManager = createSubscriptionManager(); + } + return subscriptionManager; + } + + // calls SubscriptionManager. + private void doRemoveListener(ObjectName name, Integer id) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + getSubscriptionManager().removeNotificationListener(name,id); + } + + // calls SubscriptionManager. + private void doRemoveListener(ObjectName name, Integer[] ids) + throws Exception { + getSubscriptionManager().removeNotificationListener(name,ids); + } + + // calls SubscriptionManager. + private NotificationResult doFetchNotifs(long csn, long timeout, int maxcount) + throws IOException { + return getSubscriptionManager().fetchNotifications(csn, timeout, maxcount); + } + + // calls SubscriptionManager. + private Integer doAddListener(ObjectName name, NotificationFilter filter) + throws InstanceNotFoundException, IOException { + return getSubscriptionManager().addNotificationListener(name,filter); + } + + /** *

      Returns a string representation of this object. In general, * the toString method returns a string that @@ -1313,16 +1618,6 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { // private methods //------------------------------------------------------------------------ - private ClassLoaderRepository getClassLoaderRepository() { - return - AccessController.doPrivileged( - new PrivilegedAction() { - public ClassLoaderRepository run() { - return mbeanServer.getClassLoaderRepository(); - } - }); - } - private ClassLoader getClassLoader(final ObjectName name) throws InstanceNotFoundException { try { @@ -1482,9 +1777,8 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { return null; case ADD_NOTIFICATION_LISTENERS: - return getServerNotifFwd().addNotificationListener( - (ObjectName)params[0], - (NotificationFilter)params[1]); + return doAddListener((ObjectName)params[0], + (NotificationFilter)params[1]); case ADD_NOTIFICATION_LISTENER_OBJECTNAME: mbeanServer.addNotificationListener((ObjectName)params[0], @@ -1494,9 +1788,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { return null; case REMOVE_NOTIFICATION_LISTENER: - getServerNotifFwd().removeNotificationListener( - (ObjectName)params[0], - (Integer[])params[1]); + doRemoveListener((ObjectName)params[0],(Integer[])params[1]); return null; case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME: @@ -1607,6 +1899,15 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { 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]; @@ -1709,23 +2010,21 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { private final static int REMOVE_NOTIFICATION_LISTENER = 19; private final static int - REMOVE_NOTIFICATION_LISTENER_FILTER_HANDBACK = 20; - private final static int - REMOVE_NOTIFICATION_LISTENER_OBJECTNAME = 21; + REMOVE_NOTIFICATION_LISTENER_OBJECTNAME = 20; private final static int - REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 22; + REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21; private final static int - SET_ATTRIBUTE = 23; + SET_ATTRIBUTE = 22; private final static int - SET_ATTRIBUTES = 24; + SET_ATTRIBUTES = 23; private final static int - UNREGISTER_MBEAN = 25; + UNREGISTER_MBEAN = 24; // SERVER NOTIFICATION //-------------------- - private ServerNotifForwarder serverNotifForwarder; - private Map env; + private SubscriptionManager subscriptionManager; + private Map env; // TRACES & DEBUG //--------------- diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/src/share/classes/javax/management/remote/rmi/RMIConnector.java index 2f5f234eac1b9138f9ce8741f4cbd1cab55642b6..a620235ac139f8302732a3d30b41d2d5dfa1b7ae 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -25,6 +25,9 @@ package javax.management.remote.rmi; +import com.sun.jmx.event.DaemonThreadFactory; +import com.sun.jmx.event.EventConnection; +import com.sun.jmx.mbeanserver.PerThreadGroupPool; import com.sun.jmx.remote.internal.ClientCommunicatorAdmin; import com.sun.jmx.remote.internal.ClientListenerInfo; import com.sun.jmx.remote.internal.ClientNotifForwarder; @@ -68,6 +71,12 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.WeakHashMap; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; @@ -75,6 +84,7 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.InvalidAttributeValueException; +import javax.management.JMX; import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanInfo; @@ -92,6 +102,8 @@ import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.ReflectionException; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegateMBean; import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; @@ -280,8 +292,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable // client-side environment property is set to "true". // boolean checkStub = EnvHelp.computeBooleanFromString( - usemap, - "jmx.remote.x.check.stub"); + usemap, + "jmx.remote.x.check.stub",false); if (checkStub) checkStub(stub, rmiServerImplStubClass); // Connect IIOP Stub if needed. @@ -318,6 +330,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable // connectionId = getConnectionId(); + eventServiceEnabled = EnvHelp.eventServiceEnabled(env); + Notification connectedNotif = new JMXConnectionNotification(JMXConnectionNotification.OPENED, this, @@ -327,6 +341,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable null); sendNotification(connectedNotif); + // whether or not event service + if (tracing) logger.trace("connect",idstr + " done..."); } catch (IOException e) { if (tracing) @@ -378,13 +394,42 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable throw new IOException("Not connected"); } - MBeanServerConnection mbsc = rmbscMap.get(delegationSubject); - if (mbsc != null) - return mbsc; + MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject); + if (rmbsc != null) { + return rmbsc; + } + + rmbsc = new RemoteMBeanServerConnection(delegationSubject); + if (eventServiceEnabled) { + EventClientDelegateMBean ecd = JMX.newMBeanProxy( + rmbsc, EventClientDelegateMBean.OBJECT_NAME, + EventClientDelegateMBean.class); + EventClient ec = new EventClient(ecd, null, defaultExecutor(), null, + EventClient.DEFAULT_LEASE_TIMEOUT); - mbsc = new RemoteMBeanServerConnection(delegationSubject); - rmbscMap.put(delegationSubject, mbsc); - return mbsc; + rmbsc = EventConnection.Factory.make(rmbsc, ec); + ec.addEventClientListener( + lostNotifListener, null, null); + } + rmbscMap.put(delegationSubject, rmbsc); + return rmbsc; + } + + private static Executor defaultExecutor() { + PerThreadGroupPool.Create create = + new PerThreadGroupPool.Create() { + public ThreadPoolExecutor createThreadPool(ThreadGroup group) { + ThreadFactory daemonThreadFactory = new DaemonThreadFactory( + "JMX RMIConnector listener dispatch %d"); + ThreadPoolExecutor exec = new ThreadPoolExecutor( + 1, 10, 1, TimeUnit.SECONDS, + new LinkedBlockingDeque(), + daemonThreadFactory); + exec.allowCoreThreadTimeOut(true); + return exec; + } + }; + return listenerDispatchThreadPool.getThreadPoolExecutor(create); } public void @@ -466,6 +511,17 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable communicatorAdmin.terminate(); } + // close all EventClient + for (MBeanServerConnection rmbsc : rmbscMap.values()) { + if (rmbsc instanceof EventConnection) { + try { + ((EventConnection)rmbsc).getEventClient().close(); + } catch (Exception e) { + // OK + } + } + } + if (rmiNotifClient != null) { try { rmiNotifClient.terminate(); @@ -592,18 +648,19 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable } if (debug) logger.debug("addListenersWithSubjects","registered " - + listenerIDs.length + " listener(s)"); + + ((listenerIDs==null)?0:listenerIDs.length) + + " listener(s)"); return listenerIDs; } //-------------------------------------------------------------------- // Implementation of MBeanServerConnection //-------------------------------------------------------------------- - private class RemoteMBeanServerConnection - implements MBeanServerConnection { - + private class RemoteMBeanServerConnection implements MBeanServerConnection { private Subject delegationSubject; + public EventClient eventClient = null; + public RemoteMBeanServerConnection() { this(null); } @@ -1205,6 +1262,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable IOException { final boolean debug = logger.debugOn(); + if (debug) logger.debug("addNotificationListener" + "(ObjectName,NotificationListener,"+ @@ -1226,8 +1284,9 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable public void removeNotificationListener(ObjectName name, NotificationListener listener) throws InstanceNotFoundException, - ListenerNotFoundException, - IOException { + ListenerNotFoundException, + IOException { + final boolean debug = logger.debugOn(); if (debug) logger.debug("removeNotificationListener"+ @@ -1804,6 +1863,26 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable terminated = false; connectionBroadcaster = new NotificationBroadcasterSupport(); + + lostNotifListener = + new NotificationListener() { + public void handleNotification(Notification n, Object hb) { + if (n != null && EventClient.NOTIFS_LOST.equals(n.getType())) { + Long lost = (Long)n.getUserData(); + final String msg = + "May have lost up to " + lost + + " notification" + (lost.longValue() == 1 ? "" : "s"); + sendNotification(new JMXConnectionNotification( + JMXConnectionNotification.NOTIFS_LOST, + RMIConnector.this, + connectionId, + clientNotifCounter++, + msg, + lost)); + + } + } + }; } //-------------------------------------------------------------------- @@ -2528,6 +2607,11 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable private transient ClientCommunicatorAdmin communicatorAdmin; + private boolean eventServiceEnabled; +// private transient EventRelay eventRelay; + + private transient NotificationListener lostNotifListener; + /** * A static WeakReference to an {@link org.omg.CORBA.ORB ORB} to * connect unconnected stubs. @@ -2546,4 +2630,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable private static String strings(final String[] strs) { return objects(strs); } + + private static final PerThreadGroupPool listenerDispatchThreadPool = + PerThreadGroupPool.make(); } diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index 28015461b2b5d448b9020b04b2710c6a0671e48e..2cbe315bfdd1115983a23b73069f86ba2b212a59 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -230,6 +230,8 @@ public class RMIConnectorServer extends JMXConnectorServer { this.address = url; this.rmiServerImpl = rmiServerImpl; + + installStandardForwarders(this.attributes); } /** @@ -380,8 +382,8 @@ public class RMIConnectorServer extends JMXConnectorServer { try { if (tracing) logger.trace("start", "setting default class loader"); - defaultClassLoader = - EnvHelp.resolveServerClassLoader(attributes, getMBeanServer()); + defaultClassLoader = EnvHelp.resolveServerClassLoader( + attributes, getSystemMBeanServer()); } catch (InstanceNotFoundException infc) { IllegalArgumentException x = new IllegalArgumentException("ClassLoader not found: "+infc); @@ -396,7 +398,7 @@ public class RMIConnectorServer extends JMXConnectorServer { else rmiServer = newServer(); - rmiServer.setMBeanServer(getMBeanServer()); + rmiServer.setMBeanServer(getSystemMBeanServer()); rmiServer.setDefaultClassLoader(defaultClassLoader); rmiServer.setRMIConnectorServer(this); rmiServer.export(); @@ -413,7 +415,7 @@ public class RMIConnectorServer extends JMXConnectorServer { final boolean rebind = EnvHelp.computeBooleanFromString( attributes, - JNDI_REBIND_ATTRIBUTE); + JNDI_REBIND_ATTRIBUTE,false); if (tracing) logger.trace("start", JNDI_REBIND_ATTRIBUTE + "=" + rebind); @@ -590,11 +592,39 @@ public class RMIConnectorServer extends JMXConnectorServer { return Collections.unmodifiableMap(map); } - public synchronized - void setMBeanServerForwarder(MBeanServerForwarder mbsf) { + @Override + public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) { + MBeanServer oldSMBS = getSystemMBeanServer(); super.setMBeanServerForwarder(mbsf); + if (oldSMBS != getSystemMBeanServer()) + updateMBeanServer(); + // If the system chain of MBeanServerForwarders is not empty, then + // there is no need to call rmiServerImpl.setMBeanServer, because + // it is pointing to the head of the system chain and that has not + // changed. (The *end* of the system chain will have been changed + // to point to mbsf.) + } + + private void updateMBeanServer() { if (rmiServerImpl != null) - rmiServerImpl.setMBeanServer(getMBeanServer()); + rmiServerImpl.setMBeanServer(getSystemMBeanServer()); + } + + @Override + public synchronized void setSystemMBeanServerForwarder( + MBeanServerForwarder mbsf) { + super.setSystemMBeanServerForwarder(mbsf); + updateMBeanServer(); + } + + /** + * {@inheritDoc} + * @return true, since this connector server does support a system chain + * of forwarders. + */ + @Override + public boolean supportsSystemMBeanServerForwarder() { + return true; } /* We repeat the definitions of connection{Opened,Closed,Failed} diff --git a/src/share/classes/javax/net/ssl/SSLServerSocket.java b/src/share/classes/javax/net/ssl/SSLServerSocket.java index cdeef2baf75a5af0b23021c205a671627943ef7b..8232c1d5306e74aa62b367bd6e25c416f26578f2 100644 --- a/src/share/classes/javax/net/ssl/SSLServerSocket.java +++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java @@ -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 @@ -108,9 +108,12 @@ public abstract class SSLServerSocket extends ServerSocket *

      * A port number of 0 creates a socket on any free port. *

      - * The backlog argument must be a positive - * value greater than 0. If the value passed if equal or less - * than 0, then the default value will be assumed. + * The backlog argument is the requested 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. The value provided + * should be greater than 0. If it is less than or equal to + * 0, then an implementation specific default will be used. *

      * If there is a security manager, its checkListen * method is called with the port argument as its @@ -118,8 +121,8 @@ public abstract class SSLServerSocket extends ServerSocket * in a SecurityException. * * @param port the port on which to listen - * @param backlog how many connections may be pending before - * the system should start rejecting new requests + * @param backlog requested maximum length of the queue of incoming + * connections. * @throws IOException if an I/O error occurs when creating the socket * @throws SecurityException if a security manager exists and its * checkListen method doesn't allow the operation. @@ -150,16 +153,19 @@ public abstract class SSLServerSocket extends ServerSocket *

      * A port number of 0 creates a socket on any free port. *

      - *

      The backlog argument must be a positive - * value greater than 0. If the value passed if equal or less - * than 0, then the default value will be assumed. + * The backlog argument is the requested 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. The value provided + * should be greater than 0. If it is less than or equal to + * 0, then an implementation specific default will be used. *

      * If address is null, it will default accepting connections * on any/all local addresses. * * @param port the port on which to listen - * @param backlog how many connections may be pending before - * the system should start rejecting new requests + * @param backlog requested maximum length of the queue of incoming + * connections. * @param address the address of the network interface through * which connections will be accepted * @throws IOException if an I/O error occurs when creating the socket diff --git a/src/share/classes/javax/swing/Popup.java b/src/share/classes/javax/swing/Popup.java index 2b55aadcf6251a712e19d1b1f7e08a62ccf4556f..0d1f2d53f196d152b81ee536e86bcade1626205d 100644 --- a/src/share/classes/javax/swing/Popup.java +++ b/src/share/classes/javax/swing/Popup.java @@ -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 @@ public class Popup { 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 --git a/src/share/classes/sun/awt/EmbeddedFrame.java b/src/share/classes/sun/awt/EmbeddedFrame.java index 63a12b7f83a7b4f8dd214f101a3e6d6babce59af..d7450bebe1df9354d89b72cdb38b32a10330a491 100644 --- a/src/share/classes/sun/awt/EmbeddedFrame.java +++ b/src/share/classes/sun/awt/EmbeddedFrame.java @@ -257,21 +257,27 @@ public abstract class EmbeddedFrame extends Frame 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 --git a/src/solaris/native/sun/awt/awt_Menu.h b/src/share/classes/sun/awt/EventQueueItem.java similarity index 80% rename from src/solaris/native/sun/awt/awt_Menu.h rename to src/share/classes/sun/awt/EventQueueItem.java index 97a12c05270242b9be34f265a051fdd69938cafe..17c871db426e402345ae1caf4242c44cc44a5ff2 100644 --- a/src/solaris/native/sun/awt/awt_Menu.h +++ b/src/share/classes/sun/awt/EventQueueItem.java @@ -1,5 +1,5 @@ /* - * Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -23,10 +23,15 @@ * have any questions. */ -#include +package sun.awt; -/* fieldIDs for Menu fields that may be accessed from C */ -struct MenuIDs { - jfieldID tearOff; - jfieldID isHelpMenu; -}; +import java.awt.AWTEvent; + +public class EventQueueItem { + public AWTEvent event; + public EventQueueItem next; + + public EventQueueItem(AWTEvent evt) { + event = evt; + } +} diff --git a/src/share/classes/sun/awt/SunToolkit.java b/src/share/classes/sun/awt/SunToolkit.java index 64b13e923bc8b0df77c64921a794a1dffd473dd9..20da8ffe76654f20ef60ec7f97951b848fecf0b7 100644 --- a/src/share/classes/sun/awt/SunToolkit.java +++ b/src/share/classes/sun/awt/SunToolkit.java @@ -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 @@ public abstract class SunToolkit extends Toolkit 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 @@ class PostEventQueue { SunToolkit.wakeupEventQueue(eventQueue, event.getSource() == AWTAutoShutdown.getInstance()); } } // class PostEventQueue - -class EventQueueItem { - AWTEvent event; - EventQueueItem next; - - EventQueueItem(AWTEvent evt) { - event = evt; - } -} // class EventQueueItem diff --git a/src/share/classes/sun/font/NullFontScaler.java b/src/share/classes/sun/font/NullFontScaler.java index 3d80f6d9b2eb800a36a99416285de9b4c620311d..b662b7d20196534c22b62b1eb074b8e435d2d954 100644 --- a/src/share/classes/sun/font/NullFontScaler.java +++ b/src/share/classes/sun/font/NullFontScaler.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalMonitoredVm.java b/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalMonitoredVm.java index ef06f49f05458e96d640df63550a93783d992708..c2f250686b0bf3d908374713b2188fac04e927a6 100644 --- a/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalMonitoredVm.java +++ b/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalMonitoredVm.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 diff --git a/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/MonitoredHostProvider.java b/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/MonitoredHostProvider.java index 30d4285bb64885434d2f4d5d090d1d3d2e28a929..6bfb571bde795d53d372cd627d72c6a034b7b18b 100644 --- a/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/MonitoredHostProvider.java +++ b/src/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/MonitoredHostProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 diff --git a/src/share/classes/sun/management/ClassLoadingImpl.java b/src/share/classes/sun/management/ClassLoadingImpl.java index 2f4b6ed07317e147a589f6d9093c741f1cd8949a..9eda58380879e1fca7c42314866e1d79a078b901 100644 --- a/src/share/classes/sun/management/ClassLoadingImpl.java +++ b/src/share/classes/sun/management/ClassLoadingImpl.java @@ -71,6 +71,6 @@ class ClassLoadingImpl implements ClassLoadingMXBean { native static void setVerboseClass(boolean value); public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.CLASS_LOADING_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/CompilationImpl.java b/src/share/classes/sun/management/CompilationImpl.java index d69d9cc641e8508b8f44923d184096e373443547..9c13e67ebd71d24c8c90bbac2b63f6070c2eecf9 100644 --- a/src/share/classes/sun/management/CompilationImpl.java +++ b/src/share/classes/sun/management/CompilationImpl.java @@ -70,7 +70,7 @@ class CompilationImpl implements CompilationMXBean { } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.COMPILATION_MXBEAN_NAME); } diff --git a/src/share/classes/sun/management/HotSpotDiagnostic.java b/src/share/classes/sun/management/HotSpotDiagnostic.java index f42188ff135532c94bec8601d454e11f7e410a87..d33337fcf9fee530664c99a8aa942f50d16ec4fe 100644 --- a/src/share/classes/sun/management/HotSpotDiagnostic.java +++ b/src/share/classes/sun/management/HotSpotDiagnostic.java @@ -117,6 +117,6 @@ public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean { } public ObjectName getObjectName() { - return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic"); + return ObjectName.valueOf("com.sun.management:type=HotSpotDiagnostic"); } } diff --git a/src/share/classes/sun/management/HotspotInternal.java b/src/share/classes/sun/management/HotspotInternal.java index 7006699a4d9a37bd73e7f21db0db229d14652183..88f9a82680cbd55fd838b5a29c0e6baaa93b2926 100644 --- a/src/share/classes/sun/management/HotspotInternal.java +++ b/src/share/classes/sun/management/HotspotInternal.java @@ -41,7 +41,7 @@ public class HotspotInternal private final static String HOTSPOT_INTERNAL_MBEAN_NAME = "sun.management:type=HotspotInternal"; - private static ObjectName objName = Util.newObjectName(HOTSPOT_INTERNAL_MBEAN_NAME); + private static ObjectName objName = ObjectName.valueOf(HOTSPOT_INTERNAL_MBEAN_NAME); private MBeanServer server = null; /** diff --git a/src/share/classes/sun/management/ManagementFactoryHelper.java b/src/share/classes/sun/management/ManagementFactoryHelper.java index 9bb4785d7ee1209a505274bcd5480cc8fe71f122..c07acfdbc61706e1114a354e863c8b86839a1be7 100644 --- a/src/share/classes/sun/management/ManagementFactoryHelper.java +++ b/src/share/classes/sun/management/ManagementFactoryHelper.java @@ -220,7 +220,7 @@ public class ManagementFactoryHelper { */ private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) { try { - final ObjectName objName = Util.newObjectName(mbeanName); + final ObjectName objName = ObjectName.valueOf(mbeanName); // inner class requires these fields to be final final MBeanServer mbs0 = mbs; @@ -280,7 +280,7 @@ public class ManagementFactoryHelper { private static void unregisterMBean(MBeanServer mbs, String mbeanName) { try { - final ObjectName objName = Util.newObjectName(mbeanName); + final ObjectName objName = ObjectName.valueOf(mbeanName); // inner class requires these fields to be final final MBeanServer mbs0 = mbs; diff --git a/src/share/classes/sun/management/MemoryImpl.java b/src/share/classes/sun/management/MemoryImpl.java index 29da467ce0b8ebae7b33b4d3c0e0ab97cdbecd44..aa56186ae5959ec35cfc9cd5c0f527bf60d8e642 100644 --- a/src/share/classes/sun/management/MemoryImpl.java +++ b/src/share/classes/sun/management/MemoryImpl.java @@ -177,7 +177,7 @@ class MemoryImpl extends NotificationEmitterSupport } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.MEMORY_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/OperatingSystemImpl.java b/src/share/classes/sun/management/OperatingSystemImpl.java index cfe729688a7d45f19f7bd82011f0494902e02320..9ab8b5695ceff1e52a42d57bc6b4d2badfdce590 100644 --- a/src/share/classes/sun/management/OperatingSystemImpl.java +++ b/src/share/classes/sun/management/OperatingSystemImpl.java @@ -74,7 +74,7 @@ public class OperatingSystemImpl implements OperatingSystemMXBean { } } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/RuntimeImpl.java b/src/share/classes/sun/management/RuntimeImpl.java index e58040e838802e648b8d53afc9bfd19ccad6123d..55bcbdc85f415d0c7ac6cb7513f656162a781770 100644 --- a/src/share/classes/sun/management/RuntimeImpl.java +++ b/src/share/classes/sun/management/RuntimeImpl.java @@ -149,7 +149,7 @@ class RuntimeImpl implements RuntimeMXBean { } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.RUNTIME_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/ThreadImpl.java b/src/share/classes/sun/management/ThreadImpl.java index d12258b9ea581c484c76f782a71e0e328c1550b3..565966e9ddd8fb91083a90fff8fa621a32660f2b 100644 --- a/src/share/classes/sun/management/ThreadImpl.java +++ b/src/share/classes/sun/management/ThreadImpl.java @@ -415,7 +415,7 @@ class ThreadImpl implements ThreadMXBean { private static native void resetContentionTimes0(long tid); public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/Util.java b/src/share/classes/sun/management/Util.java index 3c0997531c4261dc1e0cf1aa1d594b9b510a0e1c..1da8083005863a293ec7b4021bc73587a2fe735e 100644 --- a/src/share/classes/sun/management/Util.java +++ b/src/share/classes/sun/management/Util.java @@ -43,12 +43,8 @@ class Util { return (String[]) list.toArray(EMPTY_STRING_ARRAY); } - static ObjectName newObjectName(String name) { - return com.sun.jmx.mbeanserver.Util.newObjectName(name); - } - public static ObjectName newObjectName(String domainAndType, String name) { - return newObjectName(domainAndType + ",name=" + name); + return ObjectName.valueOf(domainAndType + ",name=" + name); } private static ManagementPermission monitorPermission = diff --git a/src/solaris/native/sun/awt/awt_MenuBar.h b/src/share/classes/sun/misc/JavaNioAccess.java similarity index 84% rename from src/solaris/native/sun/awt/awt_MenuBar.h rename to src/share/classes/sun/misc/JavaNioAccess.java index 8d2cf8bf541ac7cc339d6a36bd9894149a1f9e7c..4781cb7b4438a17d925da95a410ef710b61f73c0 100644 --- a/src/solaris/native/sun/awt/awt_MenuBar.h +++ b/src/share/classes/sun/misc/JavaNioAccess.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-1999 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,10 @@ * have any questions. */ -/* fieldIDs for MMenuBarPeer fields that may be accessed from C */ -struct MMenuBarPeerIDs { - jfieldID pData; - jfieldID graphicsConfig; -}; +package sun.misc; + +import java.nio.BufferPoolMXBean; + +public interface JavaNioAccess { + BufferPoolMXBean getDirectBufferPoolMXBean(); +} diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java index 3a9db2364fcefbc985724fb637e7c9332b1b1cb7..938e54c6c503a96fc788bc3260610545924332ae 100644 --- a/src/share/classes/sun/misc/SharedSecrets.java +++ b/src/share/classes/sun/misc/SharedSecrets.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 @@ -46,6 +46,7 @@ public class SharedSecrets { 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 @@ public class SharedSecrets { 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 --git a/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java b/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java index f53d40e5ee619da1b767bda3b19314f0b4124a6e..48ce80ebea7bb18de8cf9a11d8890d982b65ff6d 100644 --- a/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java +++ b/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java @@ -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 @@ -73,6 +73,7 @@ class ChunkedOutputStream extends FilterOutputStream if (count == CHUNK_SIZE) { writeChunk(); } + assert count < CHUNK_SIZE; } public void write (byte[]b, int off, int len) throws IOException { @@ -86,20 +87,22 @@ class ChunkedOutputStream extends FilterOutputStream writeChunk(); len -= remain; off += remain; - while (len > CHUNK_SIZE) { + while (len >= CHUNK_SIZE) { System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE); len -= CHUNK_SIZE; off += CHUNK_SIZE; count = CHUNK_SIZE; writeChunk(); } - pos = OFFSET; } if (len > 0) { System.arraycopy (b,off,buf,pos,len); count += len; pos += len; } + if (count == CHUNK_SIZE) { + writeChunk(); + } } /** diff --git a/src/share/classes/sun/net/httpserver/ServerImpl.java b/src/share/classes/sun/net/httpserver/ServerImpl.java index a9658d4b351030ca0f130db9fe6de642d0dd1ae2..a6d4b07976309f2c092a65a41ecfc00bfdf203af 100644 --- a/src/share/classes/sun/net/httpserver/ServerImpl.java +++ b/src/share/classes/sun/net/httpserver/ServerImpl.java @@ -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 diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 029ab3e11689daa132450eed713045590015cf88..54cbfba16c33320e7110104088c61425f4eda21b 100644 --- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 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 @@ -31,7 +31,7 @@ import java.net.*; 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl // 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 @@ class DatagramChannelImpl // 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl } } + @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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl } } - 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 @@ class DatagramChannelImpl } public DatagramChannel connect(SocketAddress sa) throws IOException { - int trafficClass = 0; int localPort = 0; synchronized(readLock) { @@ -545,10 +709,10 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 @@ class DatagramChannelImpl 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 --git a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java index 79a0d41b469b3a5b1d47c9d0e5c34e586c3da893..7e515bab344820d621f7e1b0fc7eb9c4fa098d60 100644 --- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 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 @@ -45,16 +45,9 @@ public class DatagramSocketAdaptor // 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 @@ public class DatagramSocketAdaptor 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 class DatagramSocketAdaptor } 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 @@ public class DatagramSocketAdaptor // 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 class DatagramSocketAdaptor 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 @@ public class DatagramSocketAdaptor 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 --git a/src/share/classes/sun/nio/ch/ExtendedSocketOption.java b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java new file mode 100644 index 0000000000000000000000000000000000000000..86e787ef80558f1a45deaa55f983fdd219f23464 --- /dev/null +++ b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java @@ -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 --git a/src/share/classes/sun/nio/ch/FileChannelImpl.java b/src/share/classes/sun/nio/ch/FileChannelImpl.java index c4ac22c04a2adad652658a3b87ce4b588706083a..894c489cd85bef90a03857b0690e203c008ed5c2 100644 --- a/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -32,6 +32,7 @@ import java.io.RandomAccessFile; 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.ref.ReferenceQueue; 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 @@ public class FileChannelImpl 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 @@ public class FileChannelImpl return; unmap0(address, size); address = 0; - } + synchronized (Unmapper.class) { + count--; + totalSize -= size; + totalCapacity -= cap; + } + } } private static void unmap(MappedByteBuffer bb) { @@ -786,7 +806,7 @@ public class FileChannelImpl 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 @@ public class FileChannelImpl } } + /** + * 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 --git a/src/share/classes/sun/nio/ch/MembershipKeyImpl.java b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..687f79c009509e41acdbce3d53472987ba7ebb74 --- /dev/null +++ b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java @@ -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 --git a/src/share/classes/sun/nio/ch/MembershipRegistry.java b/src/share/classes/sun/nio/ch/MembershipRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..5a2a8ef7447e6f970f062037a7aa69b714906432 --- /dev/null +++ b/src/share/classes/sun/nio/ch/MembershipRegistry.java @@ -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 --git a/src/share/classes/sun/nio/ch/Net.java b/src/share/classes/sun/nio/ch/Net.java index 295e4f5c49e4acfbdf4ad3b1ed64c19b59e5ed8a..ba0ba0bdcdecd83964f2c2fa093e28f5e807e528 100644 --- a/src/share/classes/sun/nio/ch/Net.java +++ b/src/share/classes/sun/nio/ch/Net.java @@ -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 @@ -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 @@ class Net { // package-private 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 @@ class Net { // package-private 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)); } - static int localPortNumber(FileDescriptor fd) { - try { - return localPort(fd); - } catch (IOException x) { - throw new Error(x); // Can't happen - } + 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)); + } + + 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); + } + + /** + * 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 getIntOption0(FileDescriptor fd, int opt) + 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 + { + return blockOrUnblock6(true, fd, group, index, source); + } + + /** + * Unblock IPv6 source + */ + static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException { - setIntOption0(fd, opt, arg); + 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 --git a/src/share/classes/sun/nio/ch/OptionAdaptor.java b/src/share/classes/sun/nio/ch/OptionAdaptor.java deleted file mode 100644 index 95a2711764ffa0ca09cce52b5fe4b426f73ff44d..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/OptionAdaptor.java +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_TextArea.h b/src/share/classes/sun/nio/ch/OptionKey.java similarity index 74% rename from src/solaris/native/sun/awt/awt_TextArea.h rename to src/share/classes/sun/nio/ch/OptionKey.java index bf59017034a8155514e379559f7843a21a1b77e8..70ba8a6fa7144e6463348e95104c06dce3589607 100644 --- a/src/solaris/native/sun/awt/awt_TextArea.h +++ b/src/share/classes/sun/nio/ch/OptionKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,26 @@ * have any questions. */ -#include "jni_util.h" +package sun.nio.ch; -/* fieldIDs for TextArea fields that may be accessed from C */ -static struct TextAreaIDs { - jfieldID scrollbarVisibility; -}; +/** + * 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; + } -/* fieldIDs for MTextAreaPeer fields that may be accessed from C */ -struct MTextAreaPeerIDs { - jfieldID firstChangeSkipped; -}; + int name() { + return name; + } +} diff --git a/src/share/classes/sun/nio/ch/SelectorImpl.java b/src/share/classes/sun/nio/ch/SelectorImpl.java index ce6e39b08e97e204d965c23180a72cd553bd75b6..4319d789978c688819f55a2d89c4a88869d3c386 100644 --- a/src/share/classes/sun/nio/ch/SelectorImpl.java +++ b/src/share/classes/sun/nio/ch/SelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2004 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 diff --git a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java index 367785564addd703edf1a0df08e2fe70bc4f45f2..f07041930b8ad9b2d3b2e6340e13dfc1c07502ad 100644 --- a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java +++ b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 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 @@ -29,6 +29,7 @@ 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.nio.channels.spi.*; @@ -41,6 +42,10 @@ public abstract class SelectorProviderImpl 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 abstract class SelectorProviderImpl public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } - } diff --git a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java index 1077ae4bdad14f4b9c33f3ca1929e68549227351..490c3286a09c178ca9998b565c68831dae774b0b 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java @@ -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 @@ -44,9 +44,6 @@ public class ServerSocketAdaptor // package-private // 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 @@ public class ServerSocketAdaptor // package-private 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 class ServerSocketAdaptor // package-private } 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 --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 7f91cf3b89743209f360a29c175db2ce87586063..fd532980b0b7d1923da051131908a99a9147323f 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -33,8 +33,7 @@ import java.nio.channels.*; 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 @@ class ServerSocketChannelImpl 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 @@ class ServerSocketChannelImpl localAddress = Net.localAddress(fd); } - public ServerSocket socket() { synchronized (stateLock) { if (socket == null) @@ -112,6 +107,69 @@ class ServerSocketChannelImpl } } + @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 @@ class ServerSocketChannelImpl } } - 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 @@ class ServerSocketChannelImpl 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 @@ class ServerSocketChannelImpl // -- 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 --git a/src/share/classes/sun/nio/ch/SocketAdaptor.java b/src/share/classes/sun/nio/ch/SocketAdaptor.java index dbf79620303c9587b600a45cbfa91ca564128dc0..8d74663bf8b7c8af1351a97c0bb9cf028b0de72c 100644 --- a/src/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java @@ -54,16 +54,9 @@ public class SocketAdaptor // 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 class SocketAdaptor 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 class SocketAdaptor } 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 @@ public class SocketAdaptor 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 class SocketAdaptor } 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 class SocketAdaptor } 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 class SocketAdaptor } public boolean isBound() { - return sc.isBound(); + return sc.localAddress() != null; } public boolean isClosed() { diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 2c67270aa2fa2a76d476f630b37f496193d28c69..11567ba2ab7e1ec2586dfd9621028c3c0f08eee5 100644 --- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -31,6 +31,7 @@ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; +import java.util.*; /** @@ -78,19 +79,16 @@ class SocketChannelImpl 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 @@ class SocketChannelImpl this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_CONNECTED; + this.localAddress = Net.localAddress(fd); this.remoteAddress = remote; } @@ -125,6 +124,98 @@ class SocketChannelImpl } } + @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 @@ class SocketChannelImpl 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 @@ class SocketChannelImpl } } - 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 @@ class SocketChannelImpl } public boolean connect(SocketAddress sa) throws IOException { - int trafficClass = 0; // ## Pick up from options int localPort = 0; synchronized (readLock) { @@ -524,13 +585,24 @@ class SocketChannelImpl 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 @@ class SocketChannelImpl } } - 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 @@ class SocketChannelImpl boolean block, boolean ready) throws IOException; - private static native void shutdown(FileDescriptor fd, int how) - throws IOException; - static { Util.load(); nd = new SocketDispatcher(); diff --git a/src/share/classes/sun/nio/ch/SocketOpts.java b/src/share/classes/sun/nio/ch/SocketOpts.java deleted file mode 100644 index 52ef58d8dc79b1aa81822988923060c7fad489d0..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/SocketOpts.java +++ /dev/null @@ -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 --git a/src/share/classes/sun/nio/ch/SocketOptsImpl.java b/src/share/classes/sun/nio/ch/SocketOptsImpl.java deleted file mode 100644 index 183747de16d25c9a398cca448aac8d496696df6a..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/SocketOptsImpl.java +++ /dev/null @@ -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 --git a/src/share/classes/sun/nio/cs/UTF_8.java b/src/share/classes/sun/nio/cs/UTF_8.java index b665b4f56a5b029f3658955f15fd813a7dd12d2f..589e3679511d6a270033d5843b861584889dbe3e 100644 --- a/src/share/classes/sun/nio/cs/UTF_8.java +++ b/src/share/classes/sun/nio/cs/UTF_8.java @@ -25,34 +25,36 @@ package sun.nio.cs; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - -/* - * # Bits Bit pattern - * 1 7 0xxxxxxx - * 2 11 110xxxxx 10xxxxxx - * 3 16 1110xxxx 10xxxxxx 10xxxxxx - * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +/* Legal UTF-8 Byte Sequences + * + * # Code Points Bits Bit/Byte pattern + * 1 7 0xxxxxxx + * U+0000..U+007F 00..7F + * + * 2 11 110xxxxx 10xxxxxx + * U+0080..U+07FF C2..DF 80..BF + * + * 3 16 1110xxxx 10xxxxxx 10xxxxxx + * U+0800..U+0FFF E0 A0..BF 80..BF + * U+1000..U+FFFF E1..EF 80..BF 80..BF + * + * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + * U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + * U+100000..U10FFFF F4 80..8F 80..BF 80..BF * - * UCS-2 uses 1-3, UTF-16 uses 1-4, UCS-4 uses 1-6 */ class UTF_8 extends Unicode { - public UTF_8() { super("UTF-8", StandardCharsets.aliases_UTF_8); } @@ -69,304 +71,250 @@ class UTF_8 extends Unicode return new Encoder(this); } + static final void updatePositions(Buffer src, int sp, + Buffer dst, int dp) { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } private static class Decoder extends CharsetDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } - private boolean isContinuation(int b) { - return ((b & 0xc0) == 0x80); + private static boolean isNotContinuation(int b) { + return (b & 0xc0) != 0x80; + } + + // [C2..DF] [80..BF] + private static boolean isMalformed2(int b1, int b2) { + return (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80; + } + + // [E0] [A0..BF] [80..BF] + // [E1..EF] [80..BF] [80..BF] + private static boolean isMalformed3(int b1, int b2, int b3) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; + } + + // [F0] [90..BF] [80..BF] [80..BF] + // [F1..F3] [80..BF] [80..BF] [80..BF] + // [F4] [80..8F] [80..BF] [80..BF] + // only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...] + // will be checked by Surrogate.neededFor(uc) + private static boolean isMalformed4(int b2, int b3, int b4) { + return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || + (b4 & 0xc0) != 0x80; + } + + private static CoderResult lookupN(ByteBuffer src, int n) + { + for (int i = 1; i < n; i++) { + if (isNotContinuation(src.get())) + return CoderResult.malformedForLength(i); + } + return CoderResult.malformedForLength(n); + } + + private static CoderResult malformedN(ByteBuffer src, int nb) { + switch (nb) { + case 1: + int b1 = src.get(); + if ((b1 >> 2) == -2) { + // 5 bytes 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + if (src.remaining() < 4) + return CoderResult.UNDERFLOW; + return lookupN(src, 5); + } + if ((b1 >> 1) == -2) { + // 6 bytes 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + if (src.remaining() < 5) + return CoderResult.UNDERFLOW; + return lookupN(src, 6); + } + return CoderResult.malformedForLength(1); + case 2: // always 1 + return CoderResult.malformedForLength(1); + case 3: + b1 = src.get(); + int b2 = src.get(); // no need to lookup b3 + return CoderResult.malformedForLength( + ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + isNotContinuation(b2))?1:2); + case 4: // we don't care the speed here + b1 = src.get() & 0xff; + b2 = src.get() & 0xff; + if (b1 > 0xf4 || + (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || + isNotContinuation(b2)) + return CoderResult.malformedForLength(1); + if (isNotContinuation(src.get())) + return CoderResult.malformedForLength(2); + return CoderResult.malformedForLength(3); + default: + assert false; + return null; + } } - private final Surrogate.Generator sgg = new Surrogate.Generator(); + private static CoderResult malformed(ByteBuffer src, int sp, + CharBuffer dst, int dp, + int nb) + { + src.position(sp - src.arrayOffset()); + CoderResult cr = malformedN(src, nb); + updatePositions(src, sp, dst, dp); + return cr; + } + + private static CoderResult malformed(ByteBuffer src, + int mark, int nb) + { + src.position(mark); + CoderResult cr = malformedN(src, nb); + src.position(mark); + return cr; + } + + private static CoderResult xflow(Buffer src, int sp, int sl, + Buffer dst, int dp, int nb) { + updatePositions(src, sp, dst, dp); + return (nb == 0 || sl - sp < nb) + ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; + } + + private static CoderResult xflow(Buffer src, int mark, int nb) { + CoderResult cr = (nb == 0 || src.remaining() < (nb - 1)) + ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; + src.position(mark); + return cr; + } private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { + // This method is optimized for ASCII input. byte[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); + char[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - int b1 = sa[sp]; - int b2, b3; - switch ((b1 >> 4) & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 1 byte, 7 bits: 0xxxxxxx - if (dl - dp < 1) - return CoderResult.OVERFLOW; - da[dp++] = (char)(b1 & 0x7f); - sp++; - continue; - - case 12: case 13: - // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - if (sl - sp < 2) - return CoderResult.UNDERFLOW; - if (dl - dp < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - da[dp++] = ((char)(((b1 & 0x1f) << 6) | - ((b2 & 0x3f) << 0))); - sp += 2; - continue; - - case 14: - // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (sl - sp < 3) - return CoderResult.UNDERFLOW; - if (dl - dp < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - da[dp++] = ((char)(((b1 & 0x0f) << 12) | - ((b2 & 0x3f) << 06) | - ((b3 & 0x3f) << 0))); - sp += 3; - continue; - - case 15: - // 4, 5, or 6 bytes - - int b4, b5, b6, uc, n; - switch (b1 & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 4 bytes, 21 bits - if (sl - sp < 4) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - uc = (((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - ((b4 & 0x3f) << 00)); - n = 4; - break; - - case 8: case 9: case 10: case 11: - // 5 bytes, 26 bits - if (sl - sp < 5) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = sa[sp + 4])) - return CoderResult.malformedForLength(4); - uc = (((b1 & 0x03) << 24) | - ((b2 & 0x3f) << 18) | - ((b3 & 0x3f) << 12) | - ((b4 & 0x3f) << 06) | - ((b5 & 0x3f) << 00)); - n = 5; - break; - - case 12: case 13: - // 6 bytes, 31 bits - if (sl - sp < 6) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = sa[sp + 4])) - return CoderResult.malformedForLength(4); - if (!isContinuation(b6 = sa[sp + 5])) - return CoderResult.malformedForLength(5); - uc = (((b1 & 0x01) << 30) | - ((b2 & 0x3f) << 24) | - ((b3 & 0x3f) << 18) | - ((b4 & 0x3f) << 12) | - ((b5 & 0x3f) << 06) | - ((b6 & 0x3f))); - n = 6; - break; - - default: - return CoderResult.malformedForLength(1); - - } - - int gn = sgg.generate(uc, n, da, dp, dl); - if (gn < 0) - return sgg.error(); - dp += gn; - sp += n; - continue; - - default: - return CoderResult.malformedForLength(1); - + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + // ASCII only loop + while (dp < dlASCII && sa[sp] >= 0) + da[dp++] = (char)sa[sp++]; + + while (sp < sl) { + int b1 = sa[sp]; + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dp >= dl) + return xflow(src, sp, sl, dst, dp, 1); + da[dp++] = (char)b1; + sp++; + } else if ((b1 >> 5) == -2) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (sl - sp < 2 || dp >= dl) + return xflow(src, sp, sl, dst, dp, 2); + int b2 = sa[sp + 1]; + if (isMalformed2(b1, b2)) + return malformed(src, sp, dst, dp, 2); + da[dp++] = (char) (((b1 << 6) ^ b2) ^ 0x0f80); + sp += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + if (sl - sp < 3 || dp >= dl) + return xflow(src, sp, sl, dst, dp, 3); + int b2 = sa[sp + 1]; + int b3 = sa[sp + 2]; + if (isMalformed3(b1, b2, b3)) + return malformed(src, sp, dst, dp, 3); + da[dp++] = (char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80); + sp += 3; + } else if ((b1 >> 3) == -2) { + // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if (sl - sp < 4 || dl - dp < 2) + return xflow(src, sp, sl, dst, dp, 4); + int b2 = sa[sp + 1]; + int b3 = sa[sp + 2]; + int b4 = sa[sp + 3]; + int uc = ((b1 & 0x07) << 18) | + ((b2 & 0x3f) << 12) | + ((b3 & 0x3f) << 06) | + (b4 & 0x3f); + if (isMalformed4(b2, b3, b4) || + !Surrogate.neededFor(uc)) { + return malformed(src, sp, dst, dp, 4); } - - } - - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); + da[dp++] = Surrogate.high(uc); + da[dp++] = Surrogate.low(uc); + sp += 4; + } else + return malformed(src, sp, dst, dp, 1); } + return xflow(src, sp, sl, dst, dp, 0); } private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { int mark = src.position(); - try { - while (src.hasRemaining()) { - int b1 = src.get(); - int b2, b3; - switch ((b1 >> 4) & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 1 byte, 7 bits: 0xxxxxxx - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - dst.put((char)b1); - mark++; - continue; - - case 12: case 13: - // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - if (src.remaining() < 1) - return CoderResult.UNDERFLOW; - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - dst.put((char)(((b1 & 0x1f) << 6) | - ((b2 & 0x3f) << 0))); - mark += 2; - continue; - - case 14: - // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (src.remaining() < 2) - return CoderResult.UNDERFLOW; - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - dst.put((char)(((b1 & 0x0f) << 12) | - ((b2 & 0x3f) << 06) | - ((b3 & 0x3f) << 0))); - mark += 3; - continue; - - case 15: - // 4, 5, or 6 bytes - - int b4, b5, b6, uc, n; - switch (b1 & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 4 bytes, 21 bits - if (src.remaining() < 3) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - uc = (((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - ((b4 & 0x3f) << 00)); - n = 4; - break; - - case 8: case 9: case 10: case 11: - // 5 bytes, 26 bits - if (src.remaining() < 4) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = src.get())) - return CoderResult.malformedForLength(4); - uc = (((b1 & 0x03) << 24) | - ((b2 & 0x3f) << 18) | - ((b3 & 0x3f) << 12) | - ((b4 & 0x3f) << 06) | - ((b5 & 0x3f) << 00)); - n = 5; - break; - - case 12: case 13: - // 6 bytes, 31 bits - if (src.remaining() < 5) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = src.get())) - return CoderResult.malformedForLength(4); - if (!isContinuation(b6 = src.get())) - return CoderResult.malformedForLength(5); - uc = (((b1 & 0x01) << 30) | - ((b2 & 0x3f) << 24) | - ((b3 & 0x3f) << 18) | - ((b4 & 0x3f) << 12) | - ((b5 & 0x3f) << 06) | - ((b6 & 0x3f))); - n = 6; - break; - - default: - return CoderResult.malformedForLength(1); - - } - - if (sgg.generate(uc, n, dst) < 0) - return sgg.error(); - mark += n; - continue; - - default: - return CoderResult.malformedForLength(1); - + int limit = src.limit(); + while (mark < limit) { + int b1 = src.get(); + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dst.remaining() < 1) + return xflow(src, mark, 1); //overflow + dst.put((char)b1); + mark++; + } else if ((b1 >> 5) == -2) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (limit - mark < 2|| dst.remaining() < 1) + return xflow(src, mark, 2); + int b2 = src.get(); + if (isMalformed2(b1, b2)) + return malformed(src, mark, 2); + dst.put((char) (((b1 << 6) ^ b2) ^ 0x0f80)); + mark += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + if (limit - mark < 3 || dst.remaining() < 1) + return xflow(src, mark, 3); + int b2 = src.get(); + int b3 = src.get(); + if (isMalformed3(b1, b2, b3)) + return malformed(src, mark, 3); + dst.put((char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80)); + mark += 3; + } else if ((b1 >> 3) == -2) { + // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if (limit - mark < 4 || dst.remaining() < 2) + return xflow(src, mark, 4); + int b2 = src.get(); + int b3 = src.get(); + int b4 = src.get(); + int uc = ((b1 & 0x07) << 18) | + ((b2 & 0x3f) << 12) | + ((b3 & 0x3f) << 06) | + (b4 & 0x3f); + if (isMalformed4(b2, b3, b4) || + !Surrogate.neededFor(uc)) { // shortest form check + return malformed(src, mark, 4); } - + dst.put(Surrogate.high(uc)); + dst.put(Surrogate.low(uc)); + mark += 4; + } else { + return malformed(src, mark, 1); } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); } + return xflow(src, mark, 0); } protected CoderResult decodeLoop(ByteBuffer src, @@ -377,10 +325,8 @@ class UTF_8 extends Unicode else return decodeBufferLoop(src, dst); } - } - private static class Encoder extends CharsetEncoder { private Encoder(Charset cs) { @@ -391,141 +337,126 @@ class UTF_8 extends Unicode return !Surrogate.is(c); } - private final Surrogate.Parser sgp = new Surrogate.Parser(); + public boolean isLegalReplacement(byte[] repl) { + return ((repl.length == 1 && repl[0] >= 0) || + super.isLegalReplacement(repl)); + } + private static CoderResult overflow(CharBuffer src, int sp, + ByteBuffer dst, int dp) { + updatePositions(src, sp, dst, dp); + return CoderResult.OVERFLOW; + } + + private static CoderResult overflow(CharBuffer src, int mark) { + src.position(mark); + return CoderResult.OVERFLOW; + } + + private Surrogate.Parser sgp; private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); + byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - char c = sa[sp]; - - if (c < 0x80) { - // Have at most seven bits - if (dp >= dl) - return CoderResult.OVERFLOW; - da[dp++] = (byte)c; - sp++; - continue; - } - - if (!Surrogate.is(c)) { - // 2 bytes, 11 bits - if (c < 0x800) { - if (dl - dp < 2) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xc0 | ((c >> 06))); - da[dp++] = (byte)(0x80 | ((c >> 00) & 0x3f)); - sp++; - continue; - } - if (c <= '\uFFFF') { - // 3 bytes, 16 bits - if (dl - dp < 3) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xe0 | ((c >> 12))); - da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f)); - da[dp++] = (byte)(0x80 | ((c >> 00) & 0x3f)); - sp++; - continue; - } - } - + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + //ASCII only loop + while (dp < dlASCII && sa[sp] < '\u0080') + da[dp++] = (byte) sa[sp++]; + while (sp < sl) { + int c = sa[sp]; + if (c < 0x80) { + // Have at most seven bits + if (dp >= dl) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)c; + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dl - dp < 2) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xc0 | ((c >> 06))); + da[dp++] = (byte)(0x80 | (c & 0x3f)); + } else if (Surrogate.is(c)) { // Have a surrogate pair - int uc = sgp.parse(c, sa, sp, sl); - if (uc < 0) + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse((char)c, sa, sp, sl); + if (uc < 0) { + updatePositions(src, sp, dst, dp); return sgp.error(); - if (uc < 0x200000) { - if (dl - dp < 4) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xf0 | ((uc >> 18))); - da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 00) & 0x3f)); - sp += sgp.increment(); - continue; } - assert false; - + if (dl - dp < 4) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xf0 | ((uc >> 18))); + da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); + da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | (uc & 0x3f)); + sp++; // 2 chars + } else { + // 3 bytes, 16 bits + if (dl - dp < 3) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xe0 | ((c >> 12))); + da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | (c & 0x3f)); } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); + sp++; } + updatePositions(src, sp, dst, dp); + return CoderResult.UNDERFLOW; } private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - - if (c < 0x80) { - // Have at most seven bits - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - dst.put((byte)c); - mark++; - continue; - } - - if (!Surrogate.is(c)) { - if (c < 0x800) { - // 2 bytes, 11 bits - if (dst.remaining() < 2) - return CoderResult.OVERFLOW; - dst.put((byte)(0xc0 | ((c >> 06)))); - dst.put((byte)(0x80 | ((c >> 00) & 0x3f))); - mark++; - continue; - } - if (c <= '\uFFFF') { - // 3 bytes, 16 bits - if (dst.remaining() < 3) - return CoderResult.OVERFLOW; - dst.put((byte)(0xe0 | ((c >> 12)))); - dst.put((byte)(0x80 | ((c >> 06) & 0x3f))); - dst.put((byte)(0x80 | ((c >> 00) & 0x3f))); - mark++; - continue; - } - } - + while (src.hasRemaining()) { + int c = src.get(); + if (c < 0x80) { + // Have at most seven bits + if (!dst.hasRemaining()) + return overflow(src, mark); + dst.put((byte)c); + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dst.remaining() < 2) + return overflow(src, mark); + dst.put((byte)(0xc0 | ((c >> 06)))); + dst.put((byte)(0x80 | (c & 0x3f))); + } else if (Surrogate.is(c)) { // Have a surrogate pair - int uc = sgp.parse(c, src); - if (uc < 0) + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse((char)c, src); + if (uc < 0) { + src.position(mark); return sgp.error(); - if (uc < 0x200000) { - if (dst.remaining() < 4) - return CoderResult.OVERFLOW; - dst.put((byte)(0xf0 | ((uc >> 18)))); - dst.put((byte)(0x80 | ((uc >> 12) & 0x3f))); - dst.put((byte)(0x80 | ((uc >> 06) & 0x3f))); - dst.put((byte)(0x80 | ((uc >> 00) & 0x3f))); - mark += sgp.increment(); - continue; } - assert false; - + if (dst.remaining() < 4) + return overflow(src, mark); + dst.put((byte)(0xf0 | ((uc >> 18)))); + dst.put((byte)(0x80 | ((uc >> 12) & 0x3f))); + dst.put((byte)(0x80 | ((uc >> 06) & 0x3f))); + dst.put((byte)(0x80 | (uc & 0x3f))); + mark++; //2 chars + } else { + // 3 bytes, 16 bits + if (dst.remaining() < 3) + return overflow(src, mark); + dst.put((byte)(0xe0 | ((c >> 12)))); + dst.put((byte)(0x80 | ((c >> 06) & 0x3f))); + dst.put((byte)(0x80 | (c & 0x3f))); } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); + mark++; } + src.position(mark); + return CoderResult.UNDERFLOW; } protected final CoderResult encodeLoop(CharBuffer src, @@ -536,7 +467,5 @@ class UTF_8 extends Unicode else return encodeBufferLoop(src, dst); } - } - } diff --git a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java index 9c7ae0910fed25a46bb368dce362d1c3d2e8d6af..04434f1f56354c9524f707e89ca896c4983bdf93 100644 --- a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java +++ b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java @@ -916,7 +916,7 @@ public class ExtendedCharsets "ccsid01140", "cp01140", "1140", - // "ebcdic-us-037+euro" + "ebcdic-us-037+euro" }); charset("IBM01141", "IBM1141", @@ -925,7 +925,7 @@ public class ExtendedCharsets "ccsid01141", "cp01141", "1141", - // "ebcdic-de-273+euro" + "ebcdic-de-273+euro" }); charset("IBM01142", "IBM1142", @@ -934,8 +934,8 @@ public class ExtendedCharsets "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 @@ public class ExtendedCharsets "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 @@ public class ExtendedCharsets "ccsid01144", "cp01144", "1144", - // "ebcdic-it-280+euro" + "ebcdic-it-280+euro" }); charset("IBM01145", "IBM1145", @@ -963,7 +963,7 @@ public class ExtendedCharsets "ccsid01145", "cp01145", "1145", - // "ebcdic-es-284+euro" + "ebcdic-es-284+euro" }); charset("IBM01146", "IBM1146", @@ -972,7 +972,7 @@ public class ExtendedCharsets "ccsid01146", "cp01146", "1146", - // "ebcdic-gb-285+euro" + "ebcdic-gb-285+euro" }); charset("IBM01147", "IBM1147", @@ -981,7 +981,7 @@ public class ExtendedCharsets "ccsid01147", "cp01147", "1147", - // "ebcdic-fr-277+euro" + "ebcdic-fr-277+euro" }); charset("IBM01148", "IBM1148", @@ -990,7 +990,7 @@ public class ExtendedCharsets "ccsid01148", "cp01148", "1148", - // "ebcdic-international-500+euro" + "ebcdic-international-500+euro" }); charset("IBM01149", "IBM1149", @@ -999,7 +999,7 @@ public class ExtendedCharsets "ccsid01149", "cp01149", "1149", - // "ebcdic-s-871+euro" + "ebcdic-s-871+euro" }); // Macintosh MacOS/Apple char encodingd diff --git a/src/share/classes/sun/nio/cs/standard-charsets b/src/share/classes/sun/nio/cs/standard-charsets index a3cad5fd941d36c458722b96b1f7699ca618463a..401a4527ca514272b62dfc9d62648484fdd2a0be 100644 --- a/src/share/classes/sun/nio/cs/standard-charsets +++ b/src/share/classes/sun/nio/cs/standard-charsets @@ -1,5 +1,5 @@ # -# Copyright 2000-2007 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 @@ -314,6 +314,7 @@ charset IBM00858 IBM858 alias ccsid00858 alias cp00858 alias 858 + alias PC-Multilingual-850+euro charset IBM862 IBM862 alias cp862 #JDK historical diff --git a/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java b/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java index e3972325dbd5ff2f2a1c0c3ff3764e579f0a13ba..1b1a3d4d24a5f67a7761d2e8e42955aab192f63b 100644 --- a/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java +++ b/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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 class CoreReflectionFactory implements GenericsFactory { } 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 --git a/src/share/classes/sun/security/krb5/Config.java b/src/share/classes/sun/security/krb5/Config.java index 56e5fb1d61e90c3b031843fd7742322a04dc9045..2a16b983f3319a628cb68f0c14f96f53400dca4d 100644 --- a/src/share/classes/sun/security/krb5/Config.java +++ b/src/share/classes/sun/security/krb5/Config.java @@ -803,7 +803,7 @@ public class Config { for (int j = 0; j < line.length(); j++) { if (line.charAt(j) == '=') { int index; - key = line.substring(0, j - 1).trim(); + key = line.substring(0, j).trim(); if (! exists(key, keyVector)) { keyVector.addElement(key); nameVector = new Vector (); diff --git a/src/share/classes/sun/security/provider/certpath/BasicChecker.java b/src/share/classes/sun/security/provider/certpath/BasicChecker.java index e4f7d1f3d74ca52d67755b83a6a2a1142f399777..491dd4711da25041e4212321971ad32e68a6e6fe 100644 --- a/src/share/classes/sun/security/provider/certpath/BasicChecker.java +++ b/src/share/classes/sun/security/provider/certpath/BasicChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -29,12 +29,18 @@ import java.math.BigInteger; import java.util.Collection; import java.util.Date; import java.util.Set; +import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.PublicKey; +import java.security.SignatureException; import java.security.cert.Certificate; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.X509Certificate; import java.security.cert.PKIXCertPathChecker; -import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXReason; import java.security.cert.TrustAnchor; import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPublicKey; @@ -152,11 +158,11 @@ class BasicChecker extends PKIXCertPathChecker { try { cert.verify(prevPubKey, sigProvider); - } catch (Exception e) { - if (debug != null) { - debug.println(e.getMessage()); - e.printStackTrace(); - } + } catch (SignatureException e) { + throw new CertPathValidatorException + (msg + " check failed", e, null, -1, + BasicReason.INVALID_SIGNATURE); + } catch (GeneralSecurityException e) { throw new CertPathValidatorException(msg + " check failed", e); } @@ -176,12 +182,12 @@ class BasicChecker extends PKIXCertPathChecker { try { cert.checkValidity(date); - } catch (Exception e) { - if (debug != null) { - debug.println(e.getMessage()); - e.printStackTrace(); - } - throw new CertPathValidatorException(msg + " check failed", e); + } catch (CertificateExpiredException e) { + throw new CertPathValidatorException + (msg + " check failed", e, null, -1, BasicReason.EXPIRED); + } catch (CertificateNotYetValidException e) { + throw new CertPathValidatorException + (msg + " check failed", e, null, -1, BasicReason.NOT_YET_VALID); } if (debug != null) @@ -204,12 +210,16 @@ class BasicChecker extends PKIXCertPathChecker { // reject null or empty issuer DNs if (X500Name.asX500Name(currIssuer).isEmpty()) { - throw new CertPathValidatorException(msg + " check failed: " + - "empty/null issuer DN in certificate is invalid"); + throw new CertPathValidatorException + (msg + " check failed: " + + "empty/null issuer DN in certificate is invalid", null, + null, -1, PKIXReason.NAME_CHAINING); } if (!(currIssuer.equals(prevSubject))) { - throw new CertPathValidatorException(msg + " check failed"); + throw new CertPathValidatorException + (msg + " check failed", null, null, -1, + PKIXReason.NAME_CHAINING); } if (debug != null) @@ -270,7 +280,7 @@ class BasicChecker extends PKIXCertPathChecker { params.getQ(), params.getG()); usableKey = kf.generatePublic(ks); - } catch (Exception e) { + } catch (GeneralSecurityException e) { throw new CertPathValidatorException("Unable to generate key with" + " inherited parameters: " + e.getMessage(), e); diff --git a/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java b/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java index 40872d7d6fca93d0e2acfc3406ee6d7f4d2ec9e1..7e2783cca063e631a7922e9298746adddab11f2d 100644 --- a/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java +++ b/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -32,9 +32,10 @@ import java.util.HashSet; import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertPathValidatorException; import java.security.cert.X509Certificate; import java.security.cert.PKIXCertPathChecker; -import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXReason; import sun.security.util.Debug; import sun.security.x509.PKIXExtensions; import sun.security.x509.NameConstraintsExtension; @@ -147,7 +148,8 @@ class ConstraintsChecker extends PKIXCertPathChecker { try { if (!prevNC.verify(currCert)) { - throw new CertPathValidatorException(msg + " check failed"); + throw new CertPathValidatorException(msg + " check failed", + null, null, -1, PKIXReason.INVALID_NAME); } } catch (IOException ioe) { throw new CertPathValidatorException(ioe); @@ -228,8 +230,9 @@ class ConstraintsChecker extends PKIXCertPathChecker { if (i < certPathLength) { int pathLenConstraint = currCert.getBasicConstraints(); if (pathLenConstraint == -1) { - throw new CertPathValidatorException(msg + " check failed: " - + "this is not a CA certificate"); + throw new CertPathValidatorException + (msg + " check failed: this is not a CA certificate", null, + null, -1, PKIXReason.NOT_CA_CERT); } if (!X509CertImpl.isSelfIssued(currCert)) { @@ -237,7 +240,8 @@ class ConstraintsChecker extends PKIXCertPathChecker { throw new CertPathValidatorException (msg + " check failed: pathLenConstraint violated - " + "this cert must be the last cert in the " - + "certification path"); + + "certification path", null, null, -1, + PKIXReason.PATH_TOO_LONG); } maxPathLength--; } diff --git a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java index 747ccba402c3d7e33ef94117a105981e656655b5..63ee343175d0b96f736ba73ad6df440f3633b905 100644 --- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java +++ b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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,6 +39,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.*; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.interfaces.DSAPublicKey; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug; @@ -268,7 +269,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { " circular dependency"); } throw new CertPathValidatorException - ("Could not determine revocation status"); + ("Could not determine revocation status", null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } // init the state for this run @@ -324,7 +326,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { return; } else { throw new CertPathValidatorException - ("Could not determine revocation status"); + ("Could not determine revocation status", null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } } @@ -370,7 +373,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { + unresCritExts); } throw new CertPathValidatorException - ("Could not determine revocation status"); + ("Could not determine revocation status", null, null, + -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } } @@ -378,10 +382,11 @@ class CrlRevocationChecker extends PKIXCertPathChecker { if (reasonCode == null) { reasonCode = CRLReason.UNSPECIFIED; } - throw new CertPathValidatorException( - new CertificateRevokedException - (entry.getRevocationDate(), reasonCode, - crl.getIssuerX500Principal(), entry.getExtensions())); + Throwable t = new CertificateRevokedException + (entry.getRevocationDate(), reasonCode, + crl.getIssuerX500Principal(), entry.getExtensions()); + throw new CertPathValidatorException(t.getMessage(), t, + null, -1, BasicReason.REVOKED); } } } @@ -428,7 +433,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { " circular dependency"); } throw new CertPathValidatorException - ("Could not determine revocation status"); + ("Could not determine revocation status", null, null, + -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } // If prevKey wasn't trusted, maybe we just didn't have the right @@ -617,7 +623,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker { return; } catch (CertPathValidatorException cpve) { // If it is revoked, rethrow exception - if (cpve.getCause() instanceof CertificateRevokedException) { + if (cpve.getReason() == BasicReason.REVOKED) { throw cpve; } // Otherwise, ignore the exception and @@ -628,7 +634,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { throw new CertPathValidatorException(iape); } catch (CertPathBuilderException cpbe) { throw new CertPathValidatorException - ("Could not determine revocation status", cpbe); + ("Could not determine revocation status", null, null, + -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } } } diff --git a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java index aa886037312c78f320df5a20d6b1a06d2f04a2e5..d8713cdcac4b5356aa5ff034c30b58e298b5614a 100644 --- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -32,6 +32,7 @@ import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXReason; import java.security.cert.CertStore; import java.security.cert.CertStoreException; import java.security.cert.PKIXBuilderParameters; @@ -732,8 +733,9 @@ class ForwardBuilder extends Builder { PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) - throw new CertificateException("Unrecognized critical " - + "extension(s)"); + throw new CertPathValidatorException + ("Unrecognized critical extension(s)", null, null, -1, + PKIXReason.UNRECOGNIZED_CRIT_EXT); } } diff --git a/src/share/classes/sun/security/provider/certpath/KeyChecker.java b/src/share/classes/sun/security/provider/certpath/KeyChecker.java index 1ed96c567e2017007891a2459cd3fd8a33b6e01a..d12031955ffc16e8eb3d83f085f73284f15dc33b 100644 --- a/src/share/classes/sun/security/provider/certpath/KeyChecker.java +++ b/src/share/classes/sun/security/provider/certpath/KeyChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 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 @@ -27,6 +27,7 @@ package sun.security.provider.certpath; import java.util.*; import java.security.cert.*; +import java.security.cert.PKIXReason; import sun.security.util.Debug; import sun.security.x509.PKIXExtensions; @@ -75,11 +76,12 @@ class KeyChecker extends PKIXCertPathChecker { if (!forward) { remainingCerts = certPathLen; } else { - throw new CertPathValidatorException("forward checking not supported"); + throw new CertPathValidatorException + ("forward checking not supported"); } } - public boolean isForwardCheckingSupported() { + public final boolean isForwardCheckingSupported() { return false; } @@ -155,8 +157,9 @@ class KeyChecker extends PKIXCertPathChecker { // throw an exception if the keyCertSign bit is not set if (!keyUsageBits[keyCertSign]) { - throw new CertPathValidatorException(msg + " check failed: " - + "keyCertSign bit is not set"); + throw new CertPathValidatorException + (msg + " check failed: keyCertSign bit is not set", null, + null, -1, PKIXReason.INVALID_KEY_USAGE); } if (debug != null) { diff --git a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java index adf5ea6897679941929586b0dd0017dec109fe85..35ed85def19ebbffd77662eb5684a5d70bd4e737 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java @@ -33,6 +33,7 @@ import java.security.Principal; import java.security.PrivilegedAction; import java.security.Security; import java.security.cert.*; +import java.security.cert.CertPathValidatorException.BasicReason; import java.net.*; import javax.security.auth.x500.X500Principal; @@ -381,17 +382,18 @@ class OCSPChecker extends PKIXCertPathChecker { } if (certOCSPStatus == OCSPResponse.CERT_STATUS_REVOKED) { - throw new CertPathValidatorException( - new CertificateRevokedException( + Throwable t = new CertificateRevokedException( ocspResponse.getRevocationTime(), ocspResponse.getRevocationReason(), responderCert.getSubjectX500Principal(), - ocspResponse.getSingleExtensions())); + ocspResponse.getSingleExtensions()); + throw new CertPathValidatorException(t.getMessage(), t, + null, -1, BasicReason.REVOKED); } else if (certOCSPStatus == OCSPResponse.CERT_STATUS_UNKNOWN) { throw new CertPathValidatorException( "Certificate's revocation status is unknown", null, cp, - remainingCerts); + remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS); } } catch (Exception e) { throw new CertPathValidatorException(e); diff --git a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java index 73d749465a19d957a04683ecbe504eede3f04294..63335d2342c03d4c25e712b27d0dff51546da1f0 100644 --- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java +++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -38,6 +38,7 @@ import java.security.cert.CertPathValidatorResult; import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathValidatorResult; import java.security.cert.PKIXParameters; +import java.security.cert.PKIXReason; import java.security.cert.PolicyNode; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; @@ -47,7 +48,6 @@ import java.util.List; import java.util.ArrayList; import java.util.Date; import java.util.Set; -import java.util.HashSet; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug; @@ -67,6 +67,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { private List userCheckers; private String sigProvider; private BasicChecker basicChecker; + private String ocspProperty; /** * Default constructor. @@ -126,7 +127,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { // Must copy elements of certList into a new modifiable List before // calling Collections.reverse(). - List certList = new ArrayList + ArrayList certList = new ArrayList ((List)cp.getCertificates()); if (debug != null) { if (certList.isEmpty()) { @@ -201,7 +202,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { } // (b) otherwise, generate new exception throw new CertPathValidatorException - ("Path does not chain with any of the trust anchors"); + ("Path does not chain with any of the trust anchors", + null, null, -1, PKIXReason.NO_TRUST_ANCHOR); } /** @@ -210,7 +212,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { */ private boolean isWorthTrying(X509Certificate trustedCert, X509Certificate firstCert) - throws CertPathValidatorException { if (debug != null) { debug.println("PKIXCertPathValidator.isWorthTrying() checking " @@ -240,7 +241,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { * Internal method to setup the internal state */ private void populateVariables(PKIXParameters pkixParam) - throws CertPathValidatorException { // default value for testDate is current time testDate = pkixParam.getDate(); @@ -250,6 +250,17 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { userCheckers = pkixParam.getCertPathCheckers(); sigProvider = pkixParam.getSigProvider(); + + if (pkixParam.isRevocationEnabled()) { + // Examine OCSP security property + ocspProperty = AccessController.doPrivileged( + new PrivilegedAction() { + public String run() { + return + Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP); + } + }); + } } /** @@ -259,12 +270,9 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { */ private PolicyNode doValidate( TrustAnchor anchor, CertPath cpOriginal, - List certList, PKIXParameters pkixParam, + ArrayList certList, PKIXParameters pkixParam, PolicyNodeImpl rootNode) throws CertPathValidatorException { - List certPathCheckers = - new ArrayList(); - int certPathLen = certList.size(); basicChecker = new BasicChecker(anchor, testDate, sigProvider, false); @@ -281,6 +289,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { pkixParam.getPolicyQualifiersRejected(), rootNode); + ArrayList certPathCheckers = + new ArrayList(); // add standard checkers that we will be using certPathCheckers.add(keyChecker); certPathCheckers.add(constraintsChecker); @@ -290,15 +300,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { // only add a revocationChecker if revocation is enabled if (pkixParam.isRevocationEnabled()) { - // Examine OCSP security property - String ocspProperty = AccessController.doPrivileged( - new PrivilegedAction() { - public String run() { - return - Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP); - } - }); - // Use OCSP if it has been enabled if ("true".equalsIgnoreCase(ocspProperty)) { OCSPChecker ocspChecker = diff --git a/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java b/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java index faa472f84d1f120997f1f5a3dd78ecba0790f573..d5f12168ddab2dbca3df7099544d7a538bd8297d 100644 --- a/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java +++ b/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -30,11 +30,12 @@ import sun.security.util.Debug; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.Iterator; +import java.security.cert.CertificateRevokedException; import java.security.cert.CertPath; import java.security.cert.CertPathValidatorException; -import java.security.cert.CertificateRevokedException; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXReason; import java.security.cert.X509Certificate; /** @@ -153,10 +154,11 @@ class PKIXMasterCertPathValidator { */ CertPathValidatorException currentCause = new CertPathValidatorException(cpve.getMessage(), - cpve.getCause(), cpOriginal, cpSize - (i + 1)); + cpve.getCause(), cpOriginal, cpSize - (i + 1), + cpve.getReason()); // Check if OCSP has confirmed that the cert was revoked - if (cpve.getCause() instanceof CertificateRevokedException) { + if (cpve.getReason() == BasicReason.REVOKED) { throw currentCause; } // Check if it is appropriate to failover @@ -184,7 +186,8 @@ class PKIXMasterCertPathValidator { debug.println("checking for unresolvedCritExts"); if (!unresolvedCritExts.isEmpty()) { throw new CertPathValidatorException("unrecognized " + - "critical extension(s)", null, cpOriginal, cpSize-(i+1)); + "critical extension(s)", null, cpOriginal, cpSize-(i+1), + PKIXReason.UNRECOGNIZED_CRIT_EXT); } if (debug != null) diff --git a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java b/src/share/classes/sun/security/provider/certpath/PolicyChecker.java index 3b76f621ceac890e6e38325d00c05fa95c2b3e7e..26dc1e52ab99e3e70ae81420e59f8bc7a419956f 100644 --- a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java +++ b/src/share/classes/sun/security/provider/certpath/PolicyChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -30,11 +30,12 @@ import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.cert.PKIXCertPathChecker; import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXReason; import java.security.cert.PolicyNode; import java.security.cert.PolicyQualifierInfo; +import java.security.cert.X509Certificate; import sun.security.util.Debug; import sun.security.x509.CertificatePoliciesExtension; @@ -482,8 +483,9 @@ class PolicyChecker extends PKIXCertPathChecker { // the policyQualifiersRejected flag is set in the params if (!pQuals.isEmpty() && rejectPolicyQualifiers && policiesCritical) { - throw new CertPathValidatorException("critical " + - "policy qualifiers present in certificate"); + throw new CertPathValidatorException( + "critical policy qualifiers present in certificate", + null, null, -1, PKIXReason.INVALID_POLICY); } // PKIX: Section 6.1.3: Step (d)(1)(i) @@ -567,7 +569,8 @@ class PolicyChecker extends PKIXCertPathChecker { if ((explicitPolicy == 0) && (rootNode == null)) { throw new CertPathValidatorException - ("non-null policy tree required and policy tree is null"); + ("non-null policy tree required and policy tree is null", + null, null, -1, PKIXReason.INVALID_POLICY); } return rootNode; @@ -776,12 +779,14 @@ class PolicyChecker extends PKIXCertPathChecker { if (issuerDomain.equals(ANY_POLICY)) { throw new CertPathValidatorException - ("encountered an issuerDomainPolicy of ANY_POLICY"); + ("encountered an issuerDomainPolicy of ANY_POLICY", + null, null, -1, PKIXReason.INVALID_POLICY); } if (subjectDomain.equals(ANY_POLICY)) { throw new CertPathValidatorException - ("encountered a subjectDomainPolicy of ANY_POLICY"); + ("encountered a subjectDomainPolicy of ANY_POLICY", + null, null, -1, PKIXReason.INVALID_POLICY); } Set validNodes = diff --git a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java index c3f2b678f2c71fde19a4dccdd33495d96d9c1e03..6f826026cafa45f6ce8957a01b93aa782bdeab81 100644 --- a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 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 @@ -29,14 +29,15 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.security.Principal; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.security.cert.CertPathValidatorException; import java.security.cert.CertStore; import java.security.cert.CertStoreException; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXParameters; +import java.security.cert.PKIXReason; import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; import java.security.cert.X509CertSelector; import java.util.ArrayList; import java.util.Collection; @@ -402,7 +403,8 @@ class ReverseBuilder extends Builder { */ if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) { throw new CertPathValidatorException - ("pathLenConstraint violated, path too long"); + ("pathLenConstraint violated, path too long", null, + null, -1, PKIXReason.PATH_TOO_LONG); } /* @@ -438,7 +440,8 @@ class ReverseBuilder extends Builder { try { if (!currentState.nc.verify(cert)){ throw new CertPathValidatorException - ("name constraints check failed"); + ("name constraints check failed", null, null, -1, + PKIXReason.INVALID_NAME); } } catch (IOException ioe){ throw new CertPathValidatorException(ioe); @@ -483,7 +486,9 @@ class ReverseBuilder extends Builder { unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresolvedCritExts.isEmpty()) - throw new CertificateException("Unrecognized critical extension(s)"); + throw new CertPathValidatorException + ("Unrecognized critical extension(s)", null, null, -1, + PKIXReason.UNRECOGNIZED_CRIT_EXT); } /* diff --git a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java index 14ed5309087d3fa7479517ab3a6bca95a7e3314c..0c439349d3cf47d1322105adb0f9709814688ed1 100644 --- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 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 @@ -30,6 +30,9 @@ import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.Principal; import java.security.PublicKey; +import java.security.cert.*; +import java.security.cert.PKIXReason; +import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -39,10 +42,6 @@ import java.util.Iterator; import java.util.List; import java.util.LinkedList; import java.util.Set; - -import java.security.cert.*; -import java.security.interfaces.DSAPublicKey; - import javax.security.auth.x500.X500Principal; import sun.security.x509.X500Name; @@ -565,8 +564,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { (PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) { - throw new CertPathValidatorException("unrecognized " - + "critical extension(s)"); + throw new CertPathValidatorException + ("unrecognized critical extension(s)", null, + null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT); } } } diff --git a/src/share/classes/sun/security/util/DerIndefLenConverter.java b/src/share/classes/sun/security/util/DerIndefLenConverter.java index 20a574545e1a9800b23cebd168747e6692346548..c94f943b8028ba412cba6587f00dd4ad88388070 100644 --- a/src/share/classes/sun/security/util/DerIndefLenConverter.java +++ b/src/share/classes/sun/security/util/DerIndefLenConverter.java @@ -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 @@ -50,6 +50,7 @@ class DerIndefLenConverter { private byte[] data, newData; private int newDataPos, dataPos, dataSize, index; + private int unresolved = 0; private ArrayList ndefsList = new ArrayList(); @@ -113,6 +114,7 @@ class DerIndefLenConverter { numOfEncapsulatedLenBytes; byte[] sectionLenBytes = getLengthBytes(sectionLen); ndefsList.set(index, sectionLenBytes); + unresolved--; // Add the number of bytes required to represent this section // to the total number of length bytes, @@ -149,6 +151,7 @@ class DerIndefLenConverter { int lenByte = data[dataPos++] & 0xff; if (isIndefinite(lenByte)) { ndefsList.add(new Integer(dataPos)); + unresolved++; return curLen; } if (isLongForm(lenByte)) { @@ -308,15 +311,21 @@ class DerIndefLenConverter { dataPos=0; index=0; dataSize = data.length; int len=0; + int unused = 0; // parse and set up the vectors of all the indefinite-lengths while (dataPos < dataSize) { parseTag(); len = parseLength(); parseValue(len); + if (unresolved == 0) { + unused = dataSize - dataPos; + dataSize = dataPos; + break; + } } - newData = new byte[dataSize + numOfTotalLenBytes]; + newData = new byte[dataSize + numOfTotalLenBytes + unused]; dataPos=0; newDataPos=0; index=0; // write out the new byte array replacing all the indefinite-lengths @@ -325,6 +334,8 @@ class DerIndefLenConverter { writeTag(); writeLengthAndValue(); } + System.arraycopy(indefData, dataSize, + newData, dataSize + numOfTotalLenBytes, unused); return newData; } diff --git a/src/share/classes/sun/text/resources/FormatData_sv.java b/src/share/classes/sun/text/resources/FormatData_sv.java index f02245a55da84c904791f8f4c512824e36414cf1..8d8cba9ed286212186ccefdc4cfc1db7bad264f3 100644 --- a/src/share/classes/sun/text/resources/FormatData_sv.java +++ b/src/share/classes/sun/text/resources/FormatData_sv.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Portions 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 diff --git a/src/share/classes/sun/tools/jconsole/Plotter.java b/src/share/classes/sun/tools/jconsole/Plotter.java index ea9d637ed7a4e779843c7ac23f9f0e24b66e102e..b9474c5db9ab1871154921e5de00adbafcb4be30 100644 --- a/src/share/classes/sun/tools/jconsole/Plotter.java +++ b/src/share/classes/sun/tools/jconsole/Plotter.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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,18 +30,15 @@ import java.awt.event.*; import java.beans.*; import java.io.*; import java.lang.reflect.Array; -import java.text.*; import java.util.*; import javax.accessibility.*; import javax.swing.*; import javax.swing.border.*; -import javax.swing.event.*; import javax.swing.filechooser.*; import javax.swing.filechooser.FileFilter; import com.sun.tools.jconsole.JConsoleContext; -import com.sun.tools.jconsole.JConsoleContext.ConnectionState; import static com.sun.tools.jconsole.JConsoleContext.ConnectionState.*; @@ -130,6 +127,7 @@ public class Plotter extends JComponent private int bottomMargin = 45; private int leftMargin = 65; private int rightMargin = 70; + private final boolean displayLegend; public Plotter() { this(Unit.NONE, 0); @@ -139,15 +137,21 @@ public class Plotter extends JComponent this(unit, 0); } + public Plotter(Unit unit, int decimals) { + this(unit,decimals,true); + } + // Note: If decimals > 0 then values must be decimally shifted left // that many places, i.e. multiplied by Math.pow(10.0, decimals). - public Plotter(Unit unit, int decimals) { + public Plotter(Unit unit, int decimals, boolean displayLegend) { + this.displayLegend = displayLegend; setUnit(unit); setDecimals(decimals); enableEvents(AWTEvent.MOUSE_EVENT_MASK); addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent e) { if (getParent() instanceof PlotterPanel) { getParent().requestFocusInWindow(); @@ -240,6 +244,7 @@ public class Plotter extends JComponent } } + @Override public JPopupMenu getComponentPopupMenu() { if (popupMenu == null) { popupMenu = new JPopupMenu(Resources.getText("Chart:")); @@ -330,6 +335,7 @@ public class Plotter extends JComponent } } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); @@ -670,7 +676,7 @@ public class Plotter extends JComponent curValue += "%"; } int valWidth = fm.stringWidth(curValue); - String legend = seq.name; + String legend = (displayLegend?seq.name:""); int legendWidth = fm.stringWidth(legend); if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) { // Wait for next repaint @@ -986,10 +992,12 @@ public class Plotter extends JComponent } private static class SaveDataFileChooser extends JFileChooser { + private static final long serialVersionUID = -5182890922369369669L; SaveDataFileChooser() { setFileFilter(new FileNameExtensionFilter("CSV file", "csv")); } + @Override public void approveSelection() { File file = getSelectedFile(); if (file != null) { @@ -1034,6 +1042,7 @@ public class Plotter extends JComponent } } + @Override public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessiblePlotter(); @@ -1042,10 +1051,12 @@ public class Plotter extends JComponent } protected class AccessiblePlotter extends AccessibleJComponent { + private static final long serialVersionUID = -3847205410473510922L; protected AccessiblePlotter() { setAccessibleName(getText("Plotter.accessibleName")); } + @Override public String getAccessibleName() { String name = super.getAccessibleName(); @@ -1076,6 +1087,7 @@ public class Plotter extends JComponent return name; } + @Override public AccessibleRole getAccessibleRole() { return AccessibleRole.CANVAS; } diff --git a/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java b/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java index 52c6d15f58e2201bd047f57ece8927158f4779d7..79cec51e38f0ddcf74db39c5df4eb8ed8545e255 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java +++ b/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java @@ -25,71 +25,78 @@ package sun.tools.jconsole.inspector; -import java.util.*; -import java.awt.event.*; -import javax.swing.table.*; -import javax.swing.event.*; // Imports for picking up mouse events from the JTable. -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.InputEvent; +import java.awt.event.MouseListener; +import java.util.Vector; import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumnModel; +import sun.tools.jconsole.JConsole; @SuppressWarnings("serial") public class TableSorter extends DefaultTableModel implements MouseListener { private boolean ascending = true; private TableColumnModel columnModel; private JTable tableView; - private Vector listenerList; + private Vector evtListenerList; private int sortColumn = 0; private int[] invertedIndex; public TableSorter() { super(); - listenerList = new Vector(); + evtListenerList = new Vector(); } public TableSorter(Object[] columnNames, int numRows) { super(columnNames,numRows); - listenerList = new Vector(); + evtListenerList = new Vector(); } + @Override public void newDataAvailable(TableModelEvent e) { super.newDataAvailable(e); invertedIndex = new int[getRowCount()]; - for (int i=0;i viewableAttributes; private WeakHashMap> viewersCache = new WeakHashMap>(); - private TableModelListener attributesListener; + private final TableModelListener attributesListener; private MBeansTab mbeansTab; - private XTable table; private TableCellEditor valueCellEditor = new ValueCellEditor(); private int rowMinHeight = -1; private AttributesMouseListener mouseListener = new AttributesMouseListener(); @@ -89,8 +108,8 @@ public class XMBeanAttributes extends XTable { super(); this.mbeansTab = mbeansTab; ((DefaultTableModel)getModel()).setColumnIdentifiers(columnNames); - getModel().addTableModelListener(attributesListener = - new AttributesListener(this)); + attributesListener = new AttributesListener(this); + getModel().addTableModelListener(attributesListener); getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(40); addMouseListener(mouseListener); @@ -99,6 +118,7 @@ public class XMBeanAttributes extends XTable { addKeyListener(new Utils.CopyKeyAdapter()); } + @Override public synchronized Component prepareRenderer(TableCellRenderer renderer, int row, int column) { //In case we have a repaint thread that is in the process of @@ -124,6 +144,7 @@ public class XMBeanAttributes extends XTable { setRowHeight(row, rowMinHeight); } + @Override public synchronized TableCellRenderer getCellRenderer(int row, int column) { //In case we have a repaint thread that is in the process of @@ -169,26 +190,40 @@ public class XMBeanAttributes extends XTable { } public void cancelCellEditing() { - TableCellEditor editor = getCellEditor(); - if (editor != null) { - editor.cancelCellEditing(); + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("Cancel Editing Row: "+getEditingRow()); + } + final TableCellEditor tableCellEditor = getCellEditor(); + if (tableCellEditor != null) { + tableCellEditor.cancelCellEditing(); } } public void stopCellEditing() { - TableCellEditor editor = getCellEditor(); - if (editor != null) { - editor.stopCellEditing(); + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("Stop Editing Row: "+getEditingRow()); + } + final TableCellEditor tableCellEditor = getCellEditor(); + if (tableCellEditor != null) { + tableCellEditor.stopCellEditing(); } } - public final boolean editCellAt(int row, int column, EventObject e) { + @Override + public final boolean editCellAt(final int row, final int column, EventObject e) { + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("editCellAt(row="+row+", col="+column+ + ", e="+e+")"); + } + if (JConsole.isDebug()) { + System.err.println("edit: "+getValueName(row)+"="+getValue(row)); + } boolean retVal = super.editCellAt(row, column, e); if (retVal) { - TableCellEditor editor = + final TableCellEditor tableCellEditor = getColumnModel().getColumn(column).getCellEditor(); - if (editor == valueCellEditor) { - ((JComponent) editor).requestFocus(); + if (tableCellEditor == valueCellEditor) { + ((JComponent) tableCellEditor).requestFocus(); } } return retVal; @@ -213,6 +248,10 @@ public class XMBeanAttributes extends XTable { public void setValueAt(Object value, int row, int column) { if (!isCellError(row, column) && isColumnEditable(column) && isWritable(row) && Utils.isEditableType(getClassName(row))) { + if (JConsole.isDebug()) { + System.err.println("validating [row="+row+", column="+column+ + "]: "+getValueName(row)+"="+value); + } super.setValueAt(value, row, column); } } @@ -256,12 +295,14 @@ public class XMBeanAttributes extends XTable { } } - public Object getValue(int row) { - return ((DefaultTableModel) getModel()).getValueAt(row, VALUE_COLUMN); + final Object val = ((DefaultTableModel) getModel()) + .getValueAt(row, VALUE_COLUMN); + return val; } //tool tip only for editable column + @Override public String getToolTip(int row, int column) { if (isCellError(row, column)) { return (String) unavailableAttributes.get(getValueName(row)); @@ -302,6 +343,7 @@ public class XMBeanAttributes extends XTable { * Override JTable method in order to make any call to this method * atomic with TableModel elements. */ + @Override public synchronized int getRowCount() { return super.getRowCount(); } @@ -332,24 +374,67 @@ public class XMBeanAttributes extends XTable { return isViewable; } - public void loadAttributes(final XMBean mbean, MBeanInfo mbeanInfo) { + // Call this in EDT + public void loadAttributes(final XMBean mbean, final MBeanInfo mbeanInfo) { + + final SwingWorker load = + new SwingWorker() { + @Override + protected Runnable doInBackground() throws Exception { + return doLoadAttributes(mbean,mbeanInfo); + } + + @Override + protected void done() { + try { + final Runnable updateUI = get(); + if (updateUI != null) updateUI.run(); + } catch (RuntimeException x) { + throw x; + } catch (ExecutionException x) { + if(JConsole.isDebug()) { + System.err.println( + "Exception raised while loading attributes: " + +x.getCause()); + x.printStackTrace(); + } + } catch (InterruptedException x) { + if(JConsole.isDebug()) { + System.err.println( + "Interrupted while loading attributes: "+x); + x.printStackTrace(); + } + } + } + + }; + mbeansTab.workerAdd(load); + } + + // Don't call this in EDT, but execute returned Runnable inside + // EDT - typically in the done() method of a SwingWorker + // This method can return null. + private Runnable doLoadAttributes(final XMBean mbean, MBeanInfo infoOrNull) + throws JMException, IOException { // To avoid deadlock with events coming from the JMX side, // we retrieve all JMX stuff in a non synchronized block. - if(mbean == null) return; - - final MBeanAttributeInfo[] attributesInfo = mbeanInfo.getAttributes(); - final HashMap attributes = - new HashMap(attributesInfo.length); - final HashMap unavailableAttributes = - new HashMap(attributesInfo.length); - final HashMap viewableAttributes = - new HashMap(attributesInfo.length); + if(mbean == null) return null; + final MBeanInfo curMBeanInfo = + (infoOrNull==null)?mbean.getMBeanInfo():infoOrNull; + + final MBeanAttributeInfo[] attrsInfo = curMBeanInfo.getAttributes(); + final HashMap attrs = + new HashMap(attrsInfo.length); + final HashMap unavailableAttrs = + new HashMap(attrsInfo.length); + final HashMap viewableAttrs = + new HashMap(attrsInfo.length); AttributeList list = null; try { - list = mbean.getAttributes(attributesInfo); - } catch (Exception e) { + list = mbean.getAttributes(attrsInfo); + }catch(Exception e) { if (JConsole.isDebug()) { System.err.println("Error calling getAttributes() on MBean \"" + mbean.getObjectName() + "\". JConsole will " + @@ -359,18 +444,18 @@ public class XMBeanAttributes extends XTable { } list = new AttributeList(); //Can't load all attributes, do it one after each other. - for(int i = 0; i < attributesInfo.length; i++) { + for(int i = 0; i < attrsInfo.length; i++) { String name = null; try { - name = attributesInfo[i].getName(); + name = attrsInfo[i].getName(); Object value = - mbean.getMBeanServerConnection().getAttribute(mbean.getObjectName(), name); + mbean.getMBeanServerConnection(). + getAttribute(mbean.getObjectName(), name); list.add(new Attribute(name, value)); }catch(Exception ex) { - if(attributesInfo[i].isReadable()) { - unavailableAttributes.put(name, - Utils.getActualException(ex). - toString()); + if(attrsInfo[i].isReadable()) { + unavailableAttrs.put(name, + Utils.getActualException(ex).toString()); } } } @@ -380,22 +465,22 @@ public class XMBeanAttributes extends XTable { for (int i=0;i stopCellEditing -> setValueAt -> tableChanged + // -> refreshAttributes(false) + // + // Can be called in EDT - as long as the implementation of + // mbeansTab.getCachedMBeanServerConnection() and mbsc.flush() doesn't + // change + // + private void refreshAttributes(final boolean stopCellEditing) { + SwingWorker sw = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + SnapshotMBeanServerConnection mbsc = + mbeansTab.getSnapshotMBeanServerConnection(); + mbsc.flush(); + return null; + } + + @Override + protected void done() { + try { + get(); + if (stopCellEditing) stopCellEditing(); + loadAttributes(mbean, mbeanInfo); + } catch (Exception x) { + if (JConsole.isDebug()) { + x.printStackTrace(); + } + } + } + }; + mbeansTab.workerAdd(sw); } + // We need to call stop editing here - otherwise edits are lost + // when resizing the table. + // + @Override + public void columnMarginChanged(ChangeEvent e) { + if (isEditing()) stopCellEditing(); + super.columnMarginChanged(e); + } + + // We need to call stop editing here - otherwise the edited value + // is transferred to the wrong row... + // + @Override + void sortRequested(int column) { + if (isEditing()) stopCellEditing(); + super.sortRequested(column); + } - public void emptyTable() { - synchronized(this) { - ((DefaultTableModel) getModel()). - removeTableModelListener(attributesListener); - super.emptyTable(); - } + @Override + public synchronized void emptyTable() { + emptyTable((DefaultTableModel)getModel()); } + // Call this in synchronized block. + private void emptyTable(DefaultTableModel model) { + model.removeTableModelListener(attributesListener); + super.emptyTable(); + } + private boolean isViewable(Attribute attribute) { Object data = attribute.getValue(); return XDataViewer.isViewableValue(data); @@ -659,6 +795,7 @@ public class XMBeanAttributes extends XTable { class AttributesMouseListener extends MouseAdapter { + @Override public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON1) { if(e.getClickCount() >= 2) { @@ -674,8 +811,10 @@ public class XMBeanAttributes extends XTable { } } + @SuppressWarnings("serial") class ValueCellEditor extends XTextFieldEditor { // implements javax.swing.table.TableCellEditor + @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, @@ -727,15 +866,17 @@ public class XMBeanAttributes extends XTable { } } + @SuppressWarnings("serial") class MaximizedCellRenderer extends DefaultTableCellRenderer { Component comp; MaximizedCellRenderer(Component comp) { this.comp = comp; Dimension d = comp.getPreferredSize(); - if (d.getHeight() > 200) { - comp.setPreferredSize(new Dimension((int) d.getWidth(), 200)); + if (d.getHeight() > 220) { + comp.setPreferredSize(new Dimension((int) d.getWidth(), 220)); } } + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, @@ -818,6 +959,7 @@ public class XMBeanAttributes extends XTable { return minHeight; } + @Override public String toString() { if(value == null) return null; @@ -854,45 +996,82 @@ public class XMBeanAttributes extends XTable { this.component = component; } + // Call this in EDT public void tableChanged(final TableModelEvent e) { - final TableModel model = (TableModel)e.getSource(); // only post changes to the draggable column if (isColumnEditable(e.getColumn())) { - mbeansTab.workerAdd(new Runnable() { - public void run() { - try { - Object tableValue = - model.getValueAt(e.getFirstRow(), - e.getColumn()); - // if it's a String, try construct new value - // using the defined type. - if (tableValue instanceof String) { - tableValue = - Utils.createObjectFromString(getClassName(e.getFirstRow()), // type - (String)tableValue);// value - } - String attributeName = - getValueName(e.getFirstRow()); - Attribute attribute = - new Attribute(attributeName,tableValue); - mbean.setAttribute(attribute); - } - catch (Throwable ex) { - if (JConsole.isDebug()) { - ex.printStackTrace(); - } - ex = Utils.getActualException(ex); - - String message = (ex.getMessage() != null) ? ex.getMessage() : ex.toString(); - EventQueue.invokeLater(new ThreadDialog(component, - message+"\n", - Resources.getText("Problem setting attribute"), - JOptionPane.ERROR_MESSAGE)); - } - refreshAttributes(); - } - }); + final TableModel model = (TableModel)e.getSource(); + Object tableValue = model.getValueAt(e.getFirstRow(), + e.getColumn()); + + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("tableChanged: firstRow="+e.getFirstRow()+ + ", lastRow="+e.getLastRow()+", column="+e.getColumn()+ + ", value="+tableValue); + } + // if it's a String, try construct new value + // using the defined type. + if (tableValue instanceof String) { + try { + tableValue = + Utils.createObjectFromString(getClassName(e.getFirstRow()), // type + (String)tableValue);// value + } catch (Throwable ex) { + popupAndLog(ex,"tableChanged", + "Problem setting attribute"); + } + } + final String attributeName = getValueName(e.getFirstRow()); + final Attribute attribute = + new Attribute(attributeName,tableValue); + setAttribute(attribute, "tableChanged"); } } + + // Call this in EDT + private void setAttribute(final Attribute attribute, final String method) { + final SwingWorker setAttribute = + new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + try { + if (JConsole.isDebug()) { + System.err.println("setAttribute("+ + attribute.getName()+ + "="+attribute.getValue()+")"); + } + mbean.setAttribute(attribute); + } catch (Throwable ex) { + popupAndLog(ex,method,"Problem setting attribute"); + } + return null; + } + @Override + protected void done() { + try { + get(); + } catch (Exception x) { + if (JConsole.isDebug()) + x.printStackTrace(); + } + refreshAttributes(false); + } + + }; + mbeansTab.workerAdd(setAttribute); + } + + // Call this outside EDT + private void popupAndLog(Throwable ex, String method, String key) { + ex = Utils.getActualException(ex); + if (JConsole.isDebug()) ex.printStackTrace(); + + String message = (ex.getMessage() != null) ? ex.getMessage() + : ex.toString(); + EventQueue.invokeLater( + new ThreadDialog(component, message+"\n", + Resources.getText(key), + JOptionPane.ERROR_MESSAGE)); + } } } diff --git a/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java b/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java index a30dd08af46e49071fe594da88f3ecbdf2646eaa..8be8c5ca898f7ed5c4e3c4e45a9bded36f4e388c 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java @@ -34,9 +34,10 @@ public class XPlotter extends Plotter { JTable table; public XPlotter(JTable table, Plotter.Unit unit) { - super(unit); + super(unit,0,false); this.table = table; } + @Override public void addValues(long time, long... values) { super.addValues(time, values); table.repaint(); diff --git a/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java b/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java index 7da7576b552393b2b6220bc99a6c78ecebf9a6c8..0c074a5599e6f558ed0379bd6a14ca11c3396209 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java @@ -27,14 +27,10 @@ package sun.tools.jconsole.inspector; import java.awt.*; import java.awt.event.*; -import java.io.*; import java.util.*; import java.util.Timer; -import javax.management.*; import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; import sun.tools.jconsole.*; @@ -127,6 +123,7 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { setBackground(g.getColor()); plotter.paintComponent(g); }*/ + @Override public void actionPerformed(ActionEvent evt) { plotterCache.remove(key); Timer t = timerCache.remove(key); @@ -141,9 +138,11 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { JTable table) { final Plotter plotter = new XPlotter(table, Plotter.Unit.NONE) { Dimension prefSize = new Dimension(400, 170); + @Override public Dimension getPreferredSize() { return prefSize; } + @Override public Dimension getMinimumSize() { return prefSize; } @@ -183,42 +182,40 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { return plotter; } - //Create Plotter display private void setupDisplay(Plotter plotter) { - //setLayout(new GridLayout(2,0)); - GridBagLayout gbl = new GridBagLayout(); - setLayout(gbl); + final JPanel buttonPanel = new JPanel(); + final GridBagLayout gbl = new GridBagLayout(); + buttonPanel.setLayout(gbl); + setLayout(new BorderLayout()); plotButton = new JButton(Resources.getText("Discard chart")); plotButton.addActionListener(this); plotButton.setEnabled(true); - // Add the display to the top four cells GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.gridx = 0; buttonConstraints.gridy = 0; buttonConstraints.fill = GridBagConstraints.VERTICAL; buttonConstraints.anchor = GridBagConstraints.CENTER; gbl.setConstraints(plotButton, buttonConstraints); - add(plotButton); - - GridBagConstraints plotterConstraints = new GridBagConstraints(); - plotterConstraints.gridx = 0; - plotterConstraints.gridy = 1; - plotterConstraints.weightx = 1; - //plotterConstraints.gridwidth = (int) plotter.getPreferredSize().getWidth(); - //plotterConstraints.gridheight = (int) plotter.getPreferredSize().getHeight(); - plotterConstraints.fill = GridBagConstraints.VERTICAL; - gbl.setConstraints(plotter, plotterConstraints); - - - //bordered = new JPanel(); - //bordered.setPreferredSize(new Dimension(400, 250)); - //bordered.add(plotButton); - //bordered.add(plotter); - - //add(bordered); - + buttonPanel.add(plotButton); + + if (attributeName != null && attributeName.length()!=0) { + final JPanel plotterLabelPanel = new JPanel(); + final JLabel label = new JLabel(attributeName); + final GridBagLayout gbl2 = new GridBagLayout(); + plotterLabelPanel.setLayout(gbl2); + final GridBagConstraints labelConstraints = new GridBagConstraints(); + labelConstraints.gridx = 0; + labelConstraints.gridy = 0; + labelConstraints.fill = GridBagConstraints.VERTICAL; + labelConstraints.anchor = GridBagConstraints.CENTER; + labelConstraints.ipady = 10; + gbl2.setConstraints(label, labelConstraints); + plotterLabelPanel.add(label); + add(plotterLabelPanel, BorderLayout.NORTH); + } setPlotter(plotter); + add(buttonPanel, BorderLayout.SOUTH); repaint(); } diff --git a/src/share/classes/sun/tools/jconsole/inspector/XSheet.java b/src/share/classes/sun/tools/jconsole/inspector/XSheet.java index 1f2104a17d09df78c6ea3037c3fb3190687972bf..813ede1dabcfac78728b4eb327dc25ecedaafd28 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XSheet.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XSheet.java @@ -25,18 +25,39 @@ package sun.tools.jconsole.inspector; -import java.awt.*; -import java.awt.event.*; -import java.io.*; -import javax.management.*; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; + +import javax.management.IntrospectionException; +import javax.management.NotificationListener; +import javax.management.MBeanInfo; +import javax.management.InstanceNotFoundException; +import javax.management.ReflectionException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingWorker; +import javax.swing.border.LineBorder; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + import sun.tools.jconsole.*; import sun.tools.jconsole.inspector.XNodeInfo.Type; import static sun.tools.jconsole.Resources.*; -import static sun.tools.jconsole.Utilities.*; @SuppressWarnings("serial") public class XSheet extends JPanel @@ -344,34 +365,41 @@ public class XSheet extends JPanel return; } mbean = (XMBean) uo.getData(); - SwingWorker sw = new SwingWorker() { + final XMBean xmb = mbean; + SwingWorker sw = new SwingWorker() { @Override - public Void doInBackground() throws InstanceNotFoundException, + public MBeanInfo doInBackground() throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException { - mbeanAttributes.loadAttributes(mbean, mbean.getMBeanInfo()); - return null; + MBeanInfo mbi = xmb.getMBeanInfo(); + return mbi; } @Override protected void done() { try { - get(); - if (!isSelectedNode(node, currentNode)) { - return; + MBeanInfo mbi = get(); + if (mbi != null && mbi.getAttributes() != null && + mbi.getAttributes().length > 0) { + + mbeanAttributes.loadAttributes(xmb, mbi); + + if (!isSelectedNode(node, currentNode)) { + return; + } + invalidate(); + mainPanel.removeAll(); + JPanel borderPanel = new JPanel(new BorderLayout()); + borderPanel.setBorder(BorderFactory.createTitledBorder( + Resources.getText("Attribute values"))); + borderPanel.add(new JScrollPane(mbeanAttributes)); + mainPanel.add(borderPanel, BorderLayout.CENTER); + // add the refresh button to the south panel + southPanel.removeAll(); + southPanel.add(refreshButton, BorderLayout.SOUTH); + southPanel.setVisible(true); + refreshButton.setEnabled(true); + validate(); + repaint(); } - invalidate(); - mainPanel.removeAll(); - JPanel borderPanel = new JPanel(new BorderLayout()); - borderPanel.setBorder(BorderFactory.createTitledBorder( - Resources.getText("Attribute values"))); - borderPanel.add(new JScrollPane(mbeanAttributes)); - mainPanel.add(borderPanel, BorderLayout.CENTER); - // add the refresh button to the south panel - southPanel.removeAll(); - southPanel.add(refreshButton, BorderLayout.SOUTH); - southPanel.setVisible(true); - refreshButton.setEnabled(true); - validate(); - repaint(); } catch (Exception e) { Throwable t = Utils.getActualException(e); if (JConsole.isDebug()) { @@ -704,13 +732,7 @@ public class XSheet extends JPanel JButton button = (JButton) e.getSource(); // Refresh button if (button == refreshButton) { - new SwingWorker() { - @Override - public Void doInBackground() { - refreshAttributes(); - return null; - } - }.execute(); + refreshAttributes(); return; } // Clear button diff --git a/src/share/classes/sun/tools/jconsole/inspector/XTable.java b/src/share/classes/sun/tools/jconsole/inspector/XTable.java index 7a3cca2600fbca8809622c3d4776b3adf511e696..133112fb8bf78e79c3e88afe3e3e189c4b0c90ff 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XTable.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XTable.java @@ -25,10 +25,13 @@ package sun.tools.jconsole.inspector; -import javax.swing.*; -import javax.swing.table.*; -import java.awt.*; -import java.io.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; public abstract class XTable extends JTable { static final int NAME_COLUMN = 0; @@ -38,8 +41,9 @@ public abstract class XTable extends JTable { public XTable () { super(); - TableSorter sorter; - setModel(sorter = new TableSorter()); + @SuppressWarnings("serial") + final TableSorter sorter = new TableSorter(); + setModel(sorter); sorter.addMouseListenerToHeaderInTable(this); setRowSelectionAllowed(false); setColumnSelectionAllowed(false); @@ -54,6 +58,14 @@ public abstract class XTable extends JTable { return editableColor; } + /** + * Called by TableSorter if a mouse event requests to sort the rows. + * @param column the column against which the rows are sorted + */ + void sortRequested(int column) { + // This is a hook for subclasses + } + /** * This returns the select index as the table was at initialization */ @@ -67,7 +79,7 @@ public abstract class XTable extends JTable { public int convertRowToIndex(int row) { if (row == -1) return row; if (getModel() instanceof TableSorter) { - return (((TableSorter) getModel()).getInvertedIndex()[row]); + return ((TableSorter) getModel()).getIndexOfRow(row); } else { return row; } @@ -97,6 +109,7 @@ public abstract class XTable extends JTable { //JTable re-implementation //attribute can be editable even if unavailable + @Override public boolean isCellEditable(int row, int col) { return ((isTableEditable() && isColumnEditable(col) && isWritable(row) @@ -118,6 +131,7 @@ public abstract class XTable extends JTable { * This method sets read write rows to be blue, and other rows to be their * default rendered colour. */ + @Override public TableCellRenderer getCellRenderer(int row, int column) { DefaultTableCellRenderer tcr = (DefaultTableCellRenderer) super.getCellRenderer(row,column); @@ -146,6 +160,7 @@ public abstract class XTable extends JTable { return tcr; } + @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component comp = super.prepareRenderer(renderer, row, column); diff --git a/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java b/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java index 31743aaa429c1635184472f5200978428f232cd4..6adf00e3bc67038879bc301f8274c2d37be0e0ce 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XTextFieldEditor.java @@ -26,22 +26,30 @@ package sun.tools.jconsole.inspector; import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; import java.util.EventObject; -import java.awt.event.*; -import java.awt.dnd.DragSourceDropEvent; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.table.*; +import javax.swing.JMenuItem; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.EventListenerList; +import javax.swing.table.TableCellEditor; @SuppressWarnings("serial") public class XTextFieldEditor extends XTextField implements TableCellEditor { - protected EventListenerList listenerList = new EventListenerList(); + protected EventListenerList evtListenerList = new EventListenerList(); protected ChangeEvent changeEvent = new ChangeEvent(this); private FocusListener editorFocusListener = new FocusAdapter() { + @Override public void focusLost(FocusEvent e) { - fireEditingStopped(); + // fireEditingStopped(); + // must not call fireEditingStopped() here! } }; @@ -51,6 +59,7 @@ public class XTextFieldEditor extends XTextField implements TableCellEditor { } //edition stopped ou JMenuItem selection & JTextField selection + @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); if ((e.getSource() instanceof JMenuItem) || @@ -67,16 +76,16 @@ public class XTextFieldEditor extends XTextField implements TableCellEditor { //TableCellEditor implementation public void addCellEditorListener(CellEditorListener listener) { - listenerList.add(CellEditorListener.class,listener); + evtListenerList.add(CellEditorListener.class,listener); } public void removeCellEditorListener(CellEditorListener listener) { - listenerList.remove(CellEditorListener.class, listener); + evtListenerList.remove(CellEditorListener.class, listener); } protected void fireEditingStopped() { CellEditorListener listener; - Object[] listeners = listenerList.getListenerList(); + Object[] listeners = evtListenerList.getListenerList(); for (int i=0;i< listeners.length;i++) { if (listeners[i] == CellEditorListener.class) { listener = (CellEditorListener) listeners[i+1]; @@ -87,7 +96,7 @@ public class XTextFieldEditor extends XTextField implements TableCellEditor { protected void fireEditingCanceled() { CellEditorListener listener; - Object[] listeners = listenerList.getListenerList(); + Object[] listeners = evtListenerList.getListenerList(); for (int i=0;i< listeners.length;i++) { if (listeners[i] == CellEditorListener.class) { listener = (CellEditorListener) listeners[i+1]; diff --git a/src/share/classes/sun/tools/jmap/JMap.java b/src/share/classes/sun/tools/jmap/JMap.java index b770c4cd8e6170150b311a87af56f4392bcd5bdf..ee4a981002477530e5ab4c09571b5f4e581e6eee 100644 --- a/src/share/classes/sun/tools/jmap/JMap.java +++ b/src/share/classes/sun/tools/jmap/JMap.java @@ -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 @@ -56,7 +56,7 @@ public class JMap { private static String FORCE_SA_OPTION = "-F"; // Default option (if nothing provided) - private static String DEFAULT_OPTION = "-heap"; + private static String DEFAULT_OPTION = "-pmap"; public static void main(String[] args) throws Exception { if (args.length == 0) { @@ -147,6 +147,7 @@ public class JMap { // Invoke SA tool with the given arguments private static void runTool(String option, String args[]) throws Exception { String[][] tools = { + { "-pmap", "sun.jvm.hotspot.tools.PMap" }, { "-heap", "sun.jvm.hotspot.tools.HeapSummary" }, { "-heap:format=b", "sun.jvm.hotspot.tools.HeapDumper" }, { "-histo", "sun.jvm.hotspot.tools.ObjectHistogram" }, diff --git a/src/share/demo/jvmti/hprof/hprof_io.c b/src/share/demo/jvmti/hprof/hprof_io.c index 2f679825521484f303e348ba077c846e4a530392..fe4eebeb0c5f3143e7fa8e9686624c8ea1e13580 100644 --- a/src/share/demo/jvmti/hprof/hprof_io.c +++ b/src/share/demo/jvmti/hprof/hprof_io.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 diff --git a/src/share/demo/jvmti/hprof/hprof_util.c b/src/share/demo/jvmti/hprof/hprof_util.c index 6685a6cc1829b3caa654ff1807fca5f32349bdeb..b25e5636e703dbaa743361e74e7b254316f6eab2 100644 --- a/src/share/demo/jvmti/hprof/hprof_util.c +++ b/src/share/demo/jvmti/hprof/hprof_util.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 diff --git a/src/share/instrument/InstrumentationImplNativeMethods.c b/src/share/instrument/InstrumentationImplNativeMethods.c index f4a1239699614a6fecc06e15f904dea02592c2e7..7acd7298bd39ec65951559eb9fb099437e59e41c 100644 --- a/src/share/instrument/InstrumentationImplNativeMethods.c +++ b/src/share/instrument/InstrumentationImplNativeMethods.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,14 @@ * have any questions. */ - #include #include "JPLISAgent.h" #include "JPLISAssert.h" #include "Utilities.h" #include "JavaExceptions.h" +#include "FileSystemSupport.h" /* For uintptr_t */ #include "sun_instrument_InstrumentationImpl.h" -#include "typedefs.h" /* * Copyright 2003 Wily Technology, Inc. diff --git a/src/share/instrument/JPLISAgent.c b/src/share/instrument/JPLISAgent.c index 9e1a0b0983010a4452eba93f99c0353912ce6a6b..e34beac794b18ca824369de1e4d117db6577c4e5 100644 --- a/src/share/instrument/JPLISAgent.c +++ b/src/share/instrument/JPLISAgent.c @@ -38,10 +38,9 @@ #include "JavaExceptions.h" #include "EncodingSupport.h" -#include "FileSystemSupport.h" /* MAXPATHLEN */ +#include "FileSystemSupport.h" /* For MAXPATHLEN & uintptr_t */ #include "sun_instrument_InstrumentationImpl.h" -#include "typedefs.h" /* * The JPLISAgent manages the initialization all of the Java programming language Agents. diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h index 3778d43093e13dbc00698d280680ccdcaf7f98e5..df8f27e6602eaf6d68f43018fcb3b15ce653fe6e 100644 --- a/src/share/javavm/export/jvm.h +++ b/src/share/javavm/export/jvm.h @@ -948,90 +948,8 @@ JVM_ReleaseUTF(const char *utf); JNIEXPORT jboolean JNICALL JVM_IsSameClassPackage(JNIEnv *env, jclass class1, jclass class2); -/* Constants in class files */ - -#define JVM_ACC_PUBLIC 0x0001 /* visible to everyone */ -#define JVM_ACC_PRIVATE 0x0002 /* visible only to the defining class */ -#define JVM_ACC_PROTECTED 0x0004 /* visible to subclasses */ -#define JVM_ACC_STATIC 0x0008 /* instance variable is static */ -#define JVM_ACC_FINAL 0x0010 /* no further subclassing, overriding */ -#define JVM_ACC_SYNCHRONIZED 0x0020 /* wrap method call in monitor lock */ -#define JVM_ACC_SUPER 0x0020 /* funky handling of invokespecial */ -#define JVM_ACC_VOLATILE 0x0040 /* can not cache in registers */ -#define JVM_ACC_BRIDGE 0x0040 /* bridge method generated by compiler */ -#define JVM_ACC_TRANSIENT 0x0080 /* not persistant */ -#define JVM_ACC_VARARGS 0x0080 /* method declared with variable number of args */ -#define JVM_ACC_NATIVE 0x0100 /* implemented in C */ -#define JVM_ACC_INTERFACE 0x0200 /* class is an interface */ -#define JVM_ACC_ABSTRACT 0x0400 /* no definition provided */ -#define JVM_ACC_STRICT 0x0800 /* strict floating point */ -#define JVM_ACC_SYNTHETIC 0x1000 /* compiler-generated class, method or field */ - -#define JVM_ACC_ANNOTATION 0x2000 /* annotation type */ -#define JVM_ACC_ENUM 0x4000 /* field is declared as element of enum */ - -#define JVM_ACC_PUBLIC_BIT 0 -#define JVM_ACC_PRIVATE_BIT 1 -#define JVM_ACC_PROTECTED_BIT 2 -#define JVM_ACC_STATIC_BIT 3 -#define JVM_ACC_FINAL_BIT 4 -#define JVM_ACC_SYNCHRONIZED_BIT 5 -#define JVM_ACC_SUPER_BIT 5 -#define JVM_ACC_VOLATILE_BIT 6 -#define JVM_ACC_BRIDGE_BIT 6 -#define JVM_ACC_TRANSIENT_BIT 7 -#define JVM_ACC_VARARGS_BIT 7 -#define JVM_ACC_NATIVE_BIT 8 -#define JVM_ACC_INTERFACE_BIT 9 -#define JVM_ACC_ABSTRACT_BIT 10 -#define JVM_ACC_STRICT_BIT 11 -#define JVM_ACC_SYNTHETIC_BIT 12 -#define JVM_ACC_ANNOTATION_BIT 13 -#define JVM_ACC_ENUM_BIT 14 - -enum { - JVM_CONSTANT_Utf8 = 1, - JVM_CONSTANT_Unicode, /* unused */ - JVM_CONSTANT_Integer, - JVM_CONSTANT_Float, - JVM_CONSTANT_Long, - JVM_CONSTANT_Double, - JVM_CONSTANT_Class, - JVM_CONSTANT_String, - JVM_CONSTANT_Fieldref, - JVM_CONSTANT_Methodref, - JVM_CONSTANT_InterfaceMethodref, - JVM_CONSTANT_NameAndType -}; - -/* Used in the newarray instruction. */ - -#define JVM_T_BOOLEAN 4 -#define JVM_T_CHAR 5 -#define JVM_T_FLOAT 6 -#define JVM_T_DOUBLE 7 -#define JVM_T_BYTE 8 -#define JVM_T_SHORT 9 -#define JVM_T_INT 10 -#define JVM_T_LONG 11 - -/* JVM method signatures */ - -#define JVM_SIGNATURE_ARRAY '[' -#define JVM_SIGNATURE_BYTE 'B' -#define JVM_SIGNATURE_CHAR 'C' -#define JVM_SIGNATURE_CLASS 'L' -#define JVM_SIGNATURE_ENDCLASS ';' -#define JVM_SIGNATURE_ENUM 'E' -#define JVM_SIGNATURE_FLOAT 'F' -#define JVM_SIGNATURE_DOUBLE 'D' -#define JVM_SIGNATURE_FUNC '(' -#define JVM_SIGNATURE_ENDFUNC ')' -#define JVM_SIGNATURE_INT 'I' -#define JVM_SIGNATURE_LONG 'J' -#define JVM_SIGNATURE_SHORT 'S' -#define JVM_SIGNATURE_VOID 'V' -#define JVM_SIGNATURE_BOOLEAN 'Z' +/* Get classfile constants */ +#include "classfile_constants.h" /* * A function defined by the byte-code verifier and called by the VM. @@ -1329,23 +1247,6 @@ JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen); JNIEXPORT jint JNICALL JVM_SetSockOpt(jint fd, int level, int optname, const char *optval, int optlen); -/* - * These routines are only reentrant on Windows - */ - -#ifdef WIN32 - -JNIEXPORT struct protoent * JNICALL -JVM_GetProtoByName(char* name); - -JNIEXPORT struct hostent* JNICALL -JVM_GetHostByAddr(const char* name, int len, int type); - -JNIEXPORT struct hostent* JNICALL -JVM_GetHostByName(char* name); - -#endif /* _WINDOWS */ - JNIEXPORT int JNICALL JVM_GetHostName(char* name, int namelen); diff --git a/src/share/javavm/include/opcodes.h b/src/share/javavm/include/opcodes.h deleted file mode 100644 index e13a4b2030b7c51c6859a60512c2b67cb9807463..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.h +++ /dev/null @@ -1,268 +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. - */ - -#ifndef _JAVASOFT_OPCODES_H_ -#define _JAVASOFT_OPCODES_H_ - -typedef enum { - opc_nop = 0, - opc_aconst_null = 1, - opc_iconst_m1 = 2, - opc_iconst_0 = 3, - opc_iconst_1 = 4, - opc_iconst_2 = 5, - opc_iconst_3 = 6, - opc_iconst_4 = 7, - opc_iconst_5 = 8, - opc_lconst_0 = 9, - opc_lconst_1 = 10, - opc_fconst_0 = 11, - opc_fconst_1 = 12, - opc_fconst_2 = 13, - opc_dconst_0 = 14, - opc_dconst_1 = 15, - opc_bipush = 16, - opc_sipush = 17, - opc_ldc = 18, - opc_ldc_w = 19, - opc_ldc2_w = 20, - opc_iload = 21, - opc_lload = 22, - opc_fload = 23, - opc_dload = 24, - opc_aload = 25, - opc_iload_0 = 26, - opc_iload_1 = 27, - opc_iload_2 = 28, - opc_iload_3 = 29, - opc_lload_0 = 30, - opc_lload_1 = 31, - opc_lload_2 = 32, - opc_lload_3 = 33, - opc_fload_0 = 34, - opc_fload_1 = 35, - opc_fload_2 = 36, - opc_fload_3 = 37, - opc_dload_0 = 38, - opc_dload_1 = 39, - opc_dload_2 = 40, - opc_dload_3 = 41, - opc_aload_0 = 42, - opc_aload_1 = 43, - opc_aload_2 = 44, - opc_aload_3 = 45, - opc_iaload = 46, - opc_laload = 47, - opc_faload = 48, - opc_daload = 49, - opc_aaload = 50, - opc_baload = 51, - opc_caload = 52, - opc_saload = 53, - opc_istore = 54, - opc_lstore = 55, - opc_fstore = 56, - opc_dstore = 57, - opc_astore = 58, - opc_istore_0 = 59, - opc_istore_1 = 60, - opc_istore_2 = 61, - opc_istore_3 = 62, - opc_lstore_0 = 63, - opc_lstore_1 = 64, - opc_lstore_2 = 65, - opc_lstore_3 = 66, - opc_fstore_0 = 67, - opc_fstore_1 = 68, - opc_fstore_2 = 69, - opc_fstore_3 = 70, - opc_dstore_0 = 71, - opc_dstore_1 = 72, - opc_dstore_2 = 73, - opc_dstore_3 = 74, - opc_astore_0 = 75, - opc_astore_1 = 76, - opc_astore_2 = 77, - opc_astore_3 = 78, - opc_iastore = 79, - opc_lastore = 80, - opc_fastore = 81, - opc_dastore = 82, - opc_aastore = 83, - opc_bastore = 84, - opc_castore = 85, - opc_sastore = 86, - opc_pop = 87, - opc_pop2 = 88, - opc_dup = 89, - opc_dup_x1 = 90, - opc_dup_x2 = 91, - opc_dup2 = 92, - opc_dup2_x1 = 93, - opc_dup2_x2 = 94, - opc_swap = 95, - opc_iadd = 96, - opc_ladd = 97, - opc_fadd = 98, - opc_dadd = 99, - opc_isub = 100, - opc_lsub = 101, - opc_fsub = 102, - opc_dsub = 103, - opc_imul = 104, - opc_lmul = 105, - opc_fmul = 106, - opc_dmul = 107, - opc_idiv = 108, - opc_ldiv = 109, - opc_fdiv = 110, - opc_ddiv = 111, - opc_irem = 112, - opc_lrem = 113, - opc_frem = 114, - opc_drem = 115, - opc_ineg = 116, - opc_lneg = 117, - opc_fneg = 118, - opc_dneg = 119, - opc_ishl = 120, - opc_lshl = 121, - opc_ishr = 122, - opc_lshr = 123, - opc_iushr = 124, - opc_lushr = 125, - opc_iand = 126, - opc_land = 127, - opc_ior = 128, - opc_lor = 129, - opc_ixor = 130, - opc_lxor = 131, - opc_iinc = 132, - opc_i2l = 133, - opc_i2f = 134, - opc_i2d = 135, - opc_l2i = 136, - opc_l2f = 137, - opc_l2d = 138, - opc_f2i = 139, - opc_f2l = 140, - opc_f2d = 141, - opc_d2i = 142, - opc_d2l = 143, - opc_d2f = 144, - opc_i2b = 145, - opc_i2c = 146, - opc_i2s = 147, - opc_lcmp = 148, - opc_fcmpl = 149, - opc_fcmpg = 150, - opc_dcmpl = 151, - opc_dcmpg = 152, - opc_ifeq = 153, - opc_ifne = 154, - opc_iflt = 155, - opc_ifge = 156, - opc_ifgt = 157, - opc_ifle = 158, - opc_if_icmpeq = 159, - opc_if_icmpne = 160, - opc_if_icmplt = 161, - opc_if_icmpge = 162, - opc_if_icmpgt = 163, - opc_if_icmple = 164, - opc_if_acmpeq = 165, - opc_if_acmpne = 166, - opc_goto = 167, - opc_jsr = 168, - opc_ret = 169, - opc_tableswitch = 170, - opc_lookupswitch = 171, - opc_ireturn = 172, - opc_lreturn = 173, - opc_freturn = 174, - opc_dreturn = 175, - opc_areturn = 176, - opc_return = 177, - opc_getstatic = 178, - opc_putstatic = 179, - opc_getfield = 180, - opc_putfield = 181, - opc_invokevirtual = 182, - opc_invokespecial = 183, - opc_invokestatic = 184, - opc_invokeinterface = 185, - opc_xxxunusedxxx = 186, - opc_new = 187, - opc_newarray = 188, - opc_anewarray = 189, - opc_arraylength = 190, - opc_athrow = 191, - opc_checkcast = 192, - opc_instanceof = 193, - opc_monitorenter = 194, - opc_monitorexit = 195, - opc_wide = 196, - opc_multianewarray = 197, - opc_ifnull = 198, - opc_ifnonnull = 199, - opc_goto_w = 200, - opc_jsr_w = 201, - opc_breakpoint = 202, - opc_ldc_quick = 203, - opc_ldc_w_quick = 204, - opc_ldc2_w_quick = 205, - opc_getfield_quick = 206, - opc_putfield_quick = 207, - opc_getfield2_quick = 208, - opc_putfield2_quick = 209, - opc_getstatic_quick = 210, - opc_putstatic_quick = 211, - opc_getstatic2_quick = 212, - opc_putstatic2_quick = 213, - opc_invokevirtual_quick = 214, - opc_invokenonvirtual_quick = 215, - opc_invokesuper_quick = 216, - opc_invokestatic_quick = 217, - opc_invokeinterface_quick = 218, - opc_invokevirtualobject_quick = 219, - opc_invokeignored_quick = 220, - opc_new_quick = 221, - opc_anewarray_quick = 222, - opc_multianewarray_quick = 223, - opc_checkcast_quick = 224, - opc_instanceof_quick = 225, - opc_invokevirtual_quick_w = 226, - opc_getfield_quick_w = 227, - opc_putfield_quick_w = 228, - opc_nonnull_quick = 229, - opc_first_unused_index = 230, - opc_software = 254, - opc_hardware = 255, - opc_dummy = (int)0xF0000000U /* portability change, opc_invokeinit in the - * verifier requires more than 8 bits. - */ -} opcode_type; - -#endif /* !_JAVASOFT_OPCODES_H_ */ diff --git a/src/share/javavm/include/opcodes.length b/src/share/javavm/include/opcodes.length deleted file mode 100644 index 6e93ec63828169ca6ce824e35261a20ff80a9360..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.length +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 1998-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. - */ - -const short opcode_length[256] = { - 1, /* nop */ - 1, /* aconst_null */ - 1, /* iconst_m1 */ - 1, /* iconst_0 */ - 1, /* iconst_1 */ - 1, /* iconst_2 */ - 1, /* iconst_3 */ - 1, /* iconst_4 */ - 1, /* iconst_5 */ - 1, /* lconst_0 */ - 1, /* lconst_1 */ - 1, /* fconst_0 */ - 1, /* fconst_1 */ - 1, /* fconst_2 */ - 1, /* dconst_0 */ - 1, /* dconst_1 */ - 2, /* bipush */ - 3, /* sipush */ - 2, /* ldc */ - 3, /* ldc_w */ - 3, /* ldc2_w */ - 2, /* iload */ - 2, /* lload */ - 2, /* fload */ - 2, /* dload */ - 2, /* aload */ - 1, /* iload_0 */ - 1, /* iload_1 */ - 1, /* iload_2 */ - 1, /* iload_3 */ - 1, /* lload_0 */ - 1, /* lload_1 */ - 1, /* lload_2 */ - 1, /* lload_3 */ - 1, /* fload_0 */ - 1, /* fload_1 */ - 1, /* fload_2 */ - 1, /* fload_3 */ - 1, /* dload_0 */ - 1, /* dload_1 */ - 1, /* dload_2 */ - 1, /* dload_3 */ - 1, /* aload_0 */ - 1, /* aload_1 */ - 1, /* aload_2 */ - 1, /* aload_3 */ - 1, /* iaload */ - 1, /* laload */ - 1, /* faload */ - 1, /* daload */ - 1, /* aaload */ - 1, /* baload */ - 1, /* caload */ - 1, /* saload */ - 2, /* istore */ - 2, /* lstore */ - 2, /* fstore */ - 2, /* dstore */ - 2, /* astore */ - 1, /* istore_0 */ - 1, /* istore_1 */ - 1, /* istore_2 */ - 1, /* istore_3 */ - 1, /* lstore_0 */ - 1, /* lstore_1 */ - 1, /* lstore_2 */ - 1, /* lstore_3 */ - 1, /* fstore_0 */ - 1, /* fstore_1 */ - 1, /* fstore_2 */ - 1, /* fstore_3 */ - 1, /* dstore_0 */ - 1, /* dstore_1 */ - 1, /* dstore_2 */ - 1, /* dstore_3 */ - 1, /* astore_0 */ - 1, /* astore_1 */ - 1, /* astore_2 */ - 1, /* astore_3 */ - 1, /* iastore */ - 1, /* lastore */ - 1, /* fastore */ - 1, /* dastore */ - 1, /* aastore */ - 1, /* bastore */ - 1, /* castore */ - 1, /* sastore */ - 1, /* pop */ - 1, /* pop2 */ - 1, /* dup */ - 1, /* dup_x1 */ - 1, /* dup_x2 */ - 1, /* dup2 */ - 1, /* dup2_x1 */ - 1, /* dup2_x2 */ - 1, /* swap */ - 1, /* iadd */ - 1, /* ladd */ - 1, /* fadd */ - 1, /* dadd */ - 1, /* isub */ - 1, /* lsub */ - 1, /* fsub */ - 1, /* dsub */ - 1, /* imul */ - 1, /* lmul */ - 1, /* fmul */ - 1, /* dmul */ - 1, /* idiv */ - 1, /* ldiv */ - 1, /* fdiv */ - 1, /* ddiv */ - 1, /* irem */ - 1, /* lrem */ - 1, /* frem */ - 1, /* drem */ - 1, /* ineg */ - 1, /* lneg */ - 1, /* fneg */ - 1, /* dneg */ - 1, /* ishl */ - 1, /* lshl */ - 1, /* ishr */ - 1, /* lshr */ - 1, /* iushr */ - 1, /* lushr */ - 1, /* iand */ - 1, /* land */ - 1, /* ior */ - 1, /* lor */ - 1, /* ixor */ - 1, /* lxor */ - 3, /* iinc */ - 1, /* i2l */ - 1, /* i2f */ - 1, /* i2d */ - 1, /* l2i */ - 1, /* l2f */ - 1, /* l2d */ - 1, /* f2i */ - 1, /* f2l */ - 1, /* f2d */ - 1, /* d2i */ - 1, /* d2l */ - 1, /* d2f */ - 1, /* i2b */ - 1, /* i2c */ - 1, /* i2s */ - 1, /* lcmp */ - 1, /* fcmpl */ - 1, /* fcmpg */ - 1, /* dcmpl */ - 1, /* dcmpg */ - 3, /* ifeq */ - 3, /* ifne */ - 3, /* iflt */ - 3, /* ifge */ - 3, /* ifgt */ - 3, /* ifle */ - 3, /* if_icmpeq */ - 3, /* if_icmpne */ - 3, /* if_icmplt */ - 3, /* if_icmpge */ - 3, /* if_icmpgt */ - 3, /* if_icmple */ - 3, /* if_acmpeq */ - 3, /* if_acmpne */ - 3, /* goto */ - 3, /* jsr */ - 2, /* ret */ - 99, /* tableswitch */ - 99, /* lookupswitch */ - 1, /* ireturn */ - 1, /* lreturn */ - 1, /* freturn */ - 1, /* dreturn */ - 1, /* areturn */ - 1, /* return */ - 3, /* getstatic */ - 3, /* putstatic */ - 3, /* getfield */ - 3, /* putfield */ - 3, /* invokevirtual */ - 3, /* invokespecial */ - 3, /* invokestatic */ - 5, /* invokeinterface */ - 0, /* xxxunusedxxx */ - 3, /* new */ - 2, /* newarray */ - 3, /* anewarray */ - 1, /* arraylength */ - 1, /* athrow */ - 3, /* checkcast */ - 3, /* instanceof */ - 1, /* monitorenter */ - 1, /* monitorexit */ - 0, /* wide */ - 4, /* multianewarray */ - 3, /* ifnull */ - 3, /* ifnonnull */ - 5, /* goto_w */ - 5, /* jsr_w */ - 1, /* breakpoint */ - 2, /* ldc_quick */ - 3, /* ldc_w_quick */ - 3, /* ldc2_w_quick */ - 3, /* getfield_quick */ - 3, /* putfield_quick */ - 3, /* getfield2_quick */ - 3, /* putfield2_quick */ - 3, /* getstatic_quick */ - 3, /* putstatic_quick */ - 3, /* getstatic2_quick */ - 3, /* putstatic2_quick */ - 3, /* invokevirtual_quick */ - 3, /* invokenonvirtual_quick */ - 3, /* invokesuper_quick */ - 3, /* invokestatic_quick */ - 5, /* invokeinterface_quick */ - 3, /* invokevirtualobject_quick */ - 3, /* invokeignored_quick */ - 3, /* new_quick */ - 3, /* anewarray_quick */ - 4, /* multianewarray_quick */ - 3, /* checkcast_quick */ - 3, /* instanceof_quick */ - 3, /* invokevirtual_quick_w */ - 3, /* getfield_quick_w */ - 3, /* putfield_quick_w */ - 1, /* nonnull_quick */ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, -}; diff --git a/src/share/javavm/include/opcodes.list b/src/share/javavm/include/opcodes.list deleted file mode 100644 index db546070ac66dc5538f98c302e459bc04554928c..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.list +++ /dev/null @@ -1,301 +0,0 @@ -# Copyright 1994-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. -# - -# Any line that doesn't have a-z in the 1st column is a comment. -# -# The first column is the name of the opcodes. The second column is the -# total length of the instruction. We use 99 for tableswitch and -# tablelookup, which must always be treated as special cases. -# -# The third and fourth colum give what the opcode pops off the stack, and -# what it then pushes back onto the stack -# - -# I integer -# L long integer -# F float -# D double float -# A address [array or object] -# O object only -# R return address (for jsr) -# a integer, array, or object -# ? unknown -# [I], [L], [F], [D], [A], [B], [C], [?] -# array of integer, long, float, double, address, bytes, -# chars, or anything -# 1,2,3,4,+ used by stack duplicating/popping routines. -# -# 1,2,3,4 represent >>any<< stack type except long or double. Two numbers -# separated by a + (in the third column) indicate that the two, together, can -# be used for a double or long. (Or they can represent two non-long items). -# -# The fifth column provides an *approximate* relative cost of executing the -# opcode. It is used by the instruction profiler. See profiler.h for -# blurb. - -nop 1 - - 1 /* nop */ -aconst_null 1 - A 1 /* push null object */ -iconst_m1 1 - I 1 /* push integer constant -1 */ -iconst_0 1 - I 1 /* push integer constant 0 */ -iconst_1 1 - I 1 /* push integer constant 1 */ -iconst_2 1 - I 1 /* push integer constant 2 */ -iconst_3 1 - I 1 /* push integer constant 3 */ -iconst_4 1 - I 1 /* push integer constant 4 */ -iconst_5 1 - I 1 /* push integer constant 5 */ -lconst_0 1 - L 1 /* push long 0L */ -lconst_1 1 - L 1 /* push long 1L */ -fconst_0 1 - F 1 /* push float constant 0.0 */ -fconst_1 1 - F 1 /* push float constant 1.0 */ -fconst_2 1 - F 1 /* push float constant 2.0 */ -dconst_0 1 - D 1 /* push double float constant 0.0d */ -dconst_1 1 - D 1 /* push double float constant 1.0d */ -bipush 2 - I 1 /* push byte-sized value */ -sipush 3 - I 1 /* push two-byte value */ -ldc 2 - ? 1 /* load a const from constant table */ -ldc_w 3 - ? 1 -ldc2_w 3 - ? 1 /* load a 2-word constant . . . */ -iload 2 - I 1 /* load local integer variable */ -lload 2 - L 1 /* load local long variable */ -fload 2 - F 1 /* load local floating variable */ -dload 2 - D 1 /* load local double variable */ -aload 2 - A 1 /* load local object variable */ -iload_0 1 - I 1 /* load local integer variable #0 */ -iload_1 1 - I 1 /* load local integer variable #1 */ -iload_2 1 - I 1 /* load local integer variable #2 */ -iload_3 1 - I 1 /* load local integer variable #3 */ -lload_0 1 - L 1 /* load local long variable #0 */ -lload_1 1 - L 1 /* load local long variable #1 */ -lload_2 1 - L 1 /* load local long variable #2 */ -lload_3 1 - L 1 /* load local long variable #3 */ -fload_0 1 - F 1 /* load local float variable #0 */ -fload_1 1 - F 1 /* load local float variable #1 */ -fload_2 1 - F 1 /* load local float variable #2 */ -fload_3 1 - F 1 /* load local float variable #3 */ -dload_0 1 - D 1 /* load lcl double float variable #0 */ -dload_1 1 - D 1 /* load lcl double float variable #1 */ -dload_2 1 - D 1 /* load lcl double float variable #2 */ -dload_3 1 - D 1 /* load lcl double float variable #3 */ -aload_0 1 - A 1 /* load local object variable #0 */ -aload_1 1 - A 1 /* load local object variable #1 */ -aload_2 1 - A 1 /* load local object variable #2 */ -aload_3 1 - A 1 /* load local object variable #3 */ -iaload 1 [I]I I 1 /* load from array of integer */ -laload 1 [L]I L 1 /* load from array of long */ -faload 1 [F]I F 1 /* load from array of float */ -daload 1 [D]I D 1 /* load from array of double */ -aaload 1 [A]I A 1 /* load from array of object */ -baload 1 [B]I I 1 /* load from array of (signed) bytes */ -caload 1 [C]I I 1 /* load from array of chars */ -saload 1 [S]I I 1 /* load from array of (signed) shorts */ -istore 2 I - 1 /* store local integer variable */ -lstore 2 L - 1 /* store local long variable */ -fstore 2 F - 1 /* store local float variable */ -dstore 2 D - 1 /* store local double variable */ -astore 2 A - 1 /* store local object variable */ -istore_0 1 I - 1 /* store local integer variable #0 */ -istore_1 1 I - 1 /* store local integer variable #1 */ -istore_2 1 I - 1 /* store local integer variable #2 */ -istore_3 1 I - 1 /* store local integer variable #3 */ -lstore_0 1 L - 1 /* store local long variable #0 */ -lstore_1 1 L - 1 /* store local long variable #1 */ -lstore_2 1 L - 1 /* store local long variable #2 */ -lstore_3 1 L - 1 /* store local long variable #3 */ -fstore_0 1 F - 1 /* store local float variable #0 */ -fstore_1 1 F - 1 /* store local float variable #1 */ -fstore_2 1 F - 1 /* store local float variable #2 */ -fstore_3 1 F - 1 /* store local float variable #3 */ -dstore_0 1 D - 1 /* store lcl double float variable #0 */ -dstore_1 1 D - 1 /* store lcl double float variable #1 */ -dstore_2 1 D - 1 /* store lcl double float variable #2 */ -dstore_3 1 D - 1 /* store lcl double float variable #3 */ -astore_0 1 A - 1 /* store local object variable #0 */ -astore_1 1 A - 1 /* store local object variable #1 */ -astore_2 1 A - 1 /* store local object variable #2 */ -astore_3 1 A - 1 /* store local object variable #3 */ -iastore 1 [I]II - 1 /* store into array of int */ -lastore 1 [L]IL - 1 /* store into array of long */ -fastore 1 [F]IF - 1 /* store into array of float */ -dastore 1 [D]ID - 1 /* store into array of double float */ -aastore 1 [A]IA - 1 /* store into array of object */ -bastore 1 [B]II - 1 /* store into array of (signed) bytes */ -castore 1 [C]II - 1 /* store into array of chars */ -sastore 1 [S]II - 1 /* store into array of (signed) shorts*/ -pop 1 1 - 1 /* pop top element */ -pop2 1 2+1 - 1 /* pop top two elements */ -dup 1 1 11 1 /* dup top element */ -dup_x1 1 21 121 1 /* dup top element. Skip one */ -dup_x2 1 3+21 1321 1 /* dup top element. Skip two */ -dup2 1 2+1 2121 1 /* dup top two elements. */ -dup2_x1 1 32+1 21321 1 /* dup top two elements. Skip one */ -dup2_x2 1 4+32+1 214321 1 /* dup top two elements. Skip two */ -swap 1 21 12 1 /* swap top two elements of stack. */ -iadd 1 II I 1 /* integer add */ -ladd 1 LL L 1 /* long add */ -fadd 1 FF F 1 /* floating add */ -dadd 1 DD D 1 /* double float add */ -isub 1 II I 1 /* integer subtract */ -lsub 1 LL L 1 /* long subtract */ -fsub 1 FF F 1 /* floating subtract */ -dsub 1 DD D 1 /* floating double subtract */ -imul 1 II I 1 /* integer multiply */ -lmul 1 LL L 1 /* long multiply */ -fmul 1 FF F 1 /* floating multiply */ -dmul 1 DD D 1 /* double float multiply */ -idiv 1 II I 1 /* integer divide */ -ldiv 1 LL L 1 /* long divide */ -fdiv 1 FF F 1 /* floating divide */ -ddiv 1 DD D 1 /* double float divide */ -irem 1 II I 1 /* integer mod */ -lrem 1 LL L 1 /* long mod */ -frem 1 FF F 1 /* floating mod */ -drem 1 DD D 1 /* double float mod */ -ineg 1 I I 1 /* integer negate */ -lneg 1 L L 1 /* long negate */ -fneg 1 F F 1 /* floating negate */ -dneg 1 D D 1 /* double float negate */ -ishl 1 II I 1 /* shift left */ -lshl 1 LI L 1 /* long shift left */ -ishr 1 II I 1 /* shift right */ -lshr 1 LI L 1 /* long shift right */ -iushr 1 II I 1 /* unsigned shift right */ -lushr 1 LI L 1 /* long unsigned shift right */ -iand 1 II I 1 /* boolean and */ -land 1 LL L 1 /* long boolean and */ -ior 1 II I 1 /* boolean or */ -lor 1 LL L 1 /* long boolean or */ -ixor 1 II I 1 /* boolean xor */ -lxor 1 LL L 1 /* long boolean xor */ -iinc 3 - - 1 /* increment lcl variable by constant */ -i2l 1 I L 1 /* integer to long */ -i2f 1 I F 1 /* integer to float */ -i2d 1 I D 1 /* integer to double */ -l2i 1 L I 1 /* long to integer */ -l2f 1 L F 1 /* long to float */ -l2d 1 L D 1 /* long to double */ -f2i 1 F I 1 /* float to integer */ -f2l 1 F L 1 /* float to long */ -f2d 1 F D 1 /* float to double */ -d2i 1 D I 1 /* double to integer */ -d2l 1 D L 1 /* double to long */ -d2f 1 D F 1 /* double to float */ -i2b 1 I I 1 /* integer to byte */ -i2c 1 I I 1 /* integer to character */ -i2s 1 I I 1 /* integer to signed short */ -lcmp 1 LL I 1 /* long compare */ -fcmpl 1 FF I 1 /* float compare. -1 on incomparable */ -fcmpg 1 FF I 1 /* float compare. 1 on incomparable */ -dcmpl 1 DD I 1 /* dbl floating cmp. -1 on incomp */ -dcmpg 1 DD I 1 /* dbl floating cmp. 1 on incomp */ -ifeq 3 I - 1 /* goto if equal */ -ifne 3 I - 1 /* goto if not equal */ -iflt 3 I - 1 /* goto if less than */ -ifge 3 I - 1 /* goto if greater than or equal */ -ifgt 3 I - 1 /* goto if greater than */ -ifle 3 I - 1 /* goto if less than or equal */ -if_icmpeq 3 II - 1 /* compare top two elements of stack */ -if_icmpne 3 II - 1 /* compare top two elements of stack */ -if_icmplt 3 II - 1 /* compare top two elements of stack */ -if_icmpge 3 II - 1 /* compare top two elements of stack */ -if_icmpgt 3 II - 1 /* compare top two elements of stack */ -if_icmple 3 II - 1 /* compare top two elements of stack */ -if_acmpeq 3 AA - 1 /* compare top two objects of stack */ -if_acmpne 3 AA - 1 /* compare top two objects of stack */ -goto 3 - - 1 /* unconditional goto */ -jsr 3 - R 1 /* jump subroutine */ -ret 2 - - 1 /* return from subroutine */ -tableswitch 99 I - 1 /* goto (case) */ -lookupswitch 99 I - 1 /* goto (case) */ -ireturn 1 I - 1 /* return integer from procedure */ -lreturn 1 L - 1 /* return long from procedure */ -freturn 1 F - 1 /* return float from procedure */ -dreturn 1 D - 1 /* return double from procedure */ -areturn 1 A - 1 /* return object from procedure */ -return 1 - - 1 /* return (void) from procedure */ -getstatic 3 - ? 1 /* get static field value. */ -putstatic 3 ? - 1 /* assign static field value */ -getfield 3 A ? 1 /* get field value from object. */ -putfield 3 ? - 1 /* assign field value to object. */ -invokevirtual 3 ? ? 1 /* call method, based on object. */ -invokespecial 3 ? ? 1 /* call method, not based on object. */ -invokestatic 3 ? ? 1 /* call a static method. */ -invokeinterface 5 ? ? 1 /* call an interface method */ -xxxunusedxxx 0 ? ? 1 /* was newfromname */ -new 3 - A 1 /* Create a new object */ -newarray 2 I A 1 /* Create a new array of non-objects*/ -anewarray 3 I A 1 /* Create a new array of objects */ -arraylength 1 [?] I 1 /* get length of array */ -athrow 1 O - 1 /* throw an exception */ -checkcast 3 A A 1 /* error if object not of given type */ -instanceof 3 A I 1 /* is object of given type? */ -monitorenter 1 A - 1 /* enter a monitored region of code */ -monitorexit 1 A - 1 /* exit a monitored region of code */ -wide 0 - - 1 /* prefix operation. */ -multianewarray 4 ? A 1 /* create multidimensional array */ -ifnull 3 A - 1 /* goto if null */ -ifnonnull 3 A - 1 /* goto if not null */ - -# The following instructions are "long" versions. They allow access to -# variables with index greater than 255. - -goto_w 5 - - 1 /* unconditional goto. 4byte offset */ -jsr_w 5 - R 1 /* jump subroutine. 4byte offset */ - -breakpoint 1 - - 1 /* call breakpoint handler */ - -# The compiler will not generate any of the following instructions. That -# are created by the interpreter from the non _quick versions of the -# instructions. - -ldc_quick 2 - ? 1 -ldc_w_quick 3 - ? 1 -ldc2_w_quick 3 - ? 1 -getfield_quick 3 A ? 1 -putfield_quick 3 ? - 1 -getfield2_quick 3 A ? 1 -putfield2_quick 3 ? - 1 -getstatic_quick 3 - ? 1 -putstatic_quick 3 ? - 1 -getstatic2_quick 3 - ? 1 -putstatic2_quick 3 ? _ 1 -invokevirtual_quick 3 ? ? 1 -invokenonvirtual_quick 3 ? ? 1 -invokesuper_quick 3 ? ? 1 -invokestatic_quick 3 ? ? 1 -invokeinterface_quick 5 ? ? 1 -invokevirtualobject_quick 3 ? ? 1 -invokeignored_quick 3 ? ? 1 -new_quick 3 - A 1 -anewarray_quick 3 I A 1 -multianewarray_quick 4 ? A 1 -checkcast_quick 3 A A 1 -instanceof_quick 3 A I 1 - -# The following are generated when the offset is bigger than 255 - -invokevirtual_quick_w 3 ? ? 1 -getfield_quick_w 3 A ? 1 -putfield_quick_w 3 ? - 1 - -# used for simplification - -nonnull_quick 1 A - 1 /* throw exception if stacktop null */ diff --git a/src/share/javavm/include/opcodes.weight b/src/share/javavm/include/opcodes.weight deleted file mode 100644 index e1a2d6d51dcb8fe2ebb7dbcd76e80480430c196a..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.weight +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 1998-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. - */ - -char const opcode_weight[256] = { - 1, /* nop */ - 1, /* aconst_null */ - 1, /* iconst_m1 */ - 1, /* iconst_0 */ - 1, /* iconst_1 */ - 1, /* iconst_2 */ - 1, /* iconst_3 */ - 1, /* iconst_4 */ - 1, /* iconst_5 */ - 1, /* lconst_0 */ - 1, /* lconst_1 */ - 1, /* fconst_0 */ - 1, /* fconst_1 */ - 1, /* fconst_2 */ - 1, /* dconst_0 */ - 1, /* dconst_1 */ - 1, /* bipush */ - 1, /* sipush */ - 1, /* ldc */ - 1, /* ldc_w */ - 1, /* ldc2_w */ - 1, /* iload */ - 1, /* lload */ - 1, /* fload */ - 1, /* dload */ - 1, /* aload */ - 1, /* iload_0 */ - 1, /* iload_1 */ - 1, /* iload_2 */ - 1, /* iload_3 */ - 1, /* lload_0 */ - 1, /* lload_1 */ - 1, /* lload_2 */ - 1, /* lload_3 */ - 1, /* fload_0 */ - 1, /* fload_1 */ - 1, /* fload_2 */ - 1, /* fload_3 */ - 1, /* dload_0 */ - 1, /* dload_1 */ - 1, /* dload_2 */ - 1, /* dload_3 */ - 1, /* aload_0 */ - 1, /* aload_1 */ - 1, /* aload_2 */ - 1, /* aload_3 */ - 1, /* iaload */ - 1, /* laload */ - 1, /* faload */ - 1, /* daload */ - 1, /* aaload */ - 1, /* baload */ - 1, /* caload */ - 1, /* saload */ - 1, /* istore */ - 1, /* lstore */ - 1, /* fstore */ - 1, /* dstore */ - 1, /* astore */ - 1, /* istore_0 */ - 1, /* istore_1 */ - 1, /* istore_2 */ - 1, /* istore_3 */ - 1, /* lstore_0 */ - 1, /* lstore_1 */ - 1, /* lstore_2 */ - 1, /* lstore_3 */ - 1, /* fstore_0 */ - 1, /* fstore_1 */ - 1, /* fstore_2 */ - 1, /* fstore_3 */ - 1, /* dstore_0 */ - 1, /* dstore_1 */ - 1, /* dstore_2 */ - 1, /* dstore_3 */ - 1, /* astore_0 */ - 1, /* astore_1 */ - 1, /* astore_2 */ - 1, /* astore_3 */ - 1, /* iastore */ - 1, /* lastore */ - 1, /* fastore */ - 1, /* dastore */ - 1, /* aastore */ - 1, /* bastore */ - 1, /* castore */ - 1, /* sastore */ - 1, /* pop */ - 1, /* pop2 */ - 1, /* dup */ - 1, /* dup_x1 */ - 1, /* dup_x2 */ - 1, /* dup2 */ - 1, /* dup2_x1 */ - 1, /* dup2_x2 */ - 1, /* swap */ - 1, /* iadd */ - 1, /* ladd */ - 1, /* fadd */ - 1, /* dadd */ - 1, /* isub */ - 1, /* lsub */ - 1, /* fsub */ - 1, /* dsub */ - 1, /* imul */ - 1, /* lmul */ - 1, /* fmul */ - 1, /* dmul */ - 1, /* idiv */ - 1, /* ldiv */ - 1, /* fdiv */ - 1, /* ddiv */ - 1, /* irem */ - 1, /* lrem */ - 1, /* frem */ - 1, /* drem */ - 1, /* ineg */ - 1, /* lneg */ - 1, /* fneg */ - 1, /* dneg */ - 1, /* ishl */ - 1, /* lshl */ - 1, /* ishr */ - 1, /* lshr */ - 1, /* iushr */ - 1, /* lushr */ - 1, /* iand */ - 1, /* land */ - 1, /* ior */ - 1, /* lor */ - 1, /* ixor */ - 1, /* lxor */ - 1, /* iinc */ - 1, /* i2l */ - 1, /* i2f */ - 1, /* i2d */ - 1, /* l2i */ - 1, /* l2f */ - 1, /* l2d */ - 1, /* f2i */ - 1, /* f2l */ - 1, /* f2d */ - 1, /* d2i */ - 1, /* d2l */ - 1, /* d2f */ - 1, /* i2b */ - 1, /* i2c */ - 1, /* i2s */ - 1, /* lcmp */ - 1, /* fcmpl */ - 1, /* fcmpg */ - 1, /* dcmpl */ - 1, /* dcmpg */ - 1, /* ifeq */ - 1, /* ifne */ - 1, /* iflt */ - 1, /* ifge */ - 1, /* ifgt */ - 1, /* ifle */ - 1, /* if_icmpeq */ - 1, /* if_icmpne */ - 1, /* if_icmplt */ - 1, /* if_icmpge */ - 1, /* if_icmpgt */ - 1, /* if_icmple */ - 1, /* if_acmpeq */ - 1, /* if_acmpne */ - 1, /* goto */ - 1, /* jsr */ - 1, /* ret */ - 1, /* tableswitch */ - 1, /* lookupswitch */ - 1, /* ireturn */ - 1, /* lreturn */ - 1, /* freturn */ - 1, /* dreturn */ - 1, /* areturn */ - 1, /* return */ - 1, /* getstatic */ - 1, /* putstatic */ - 1, /* getfield */ - 1, /* putfield */ - 1, /* invokevirtual */ - 1, /* invokespecial */ - 1, /* invokestatic */ - 1, /* invokeinterface */ - 1, /* xxxunusedxxx */ - 1, /* new */ - 1, /* newarray */ - 1, /* anewarray */ - 1, /* arraylength */ - 1, /* athrow */ - 1, /* checkcast */ - 1, /* instanceof */ - 1, /* monitorenter */ - 1, /* monitorexit */ - 1, /* wide */ - 1, /* multianewarray */ - 1, /* ifnull */ - 1, /* ifnonnull */ - 1, /* goto_w */ - 1, /* jsr_w */ - 1, /* breakpoint */ - 1, /* ldc_quick */ - 1, /* ldc_w_quick */ - 1, /* ldc2_w_quick */ - 1, /* getfield_quick */ - 1, /* putfield_quick */ - 1, /* getfield2_quick */ - 1, /* putfield2_quick */ - 1, /* getstatic_quick */ - 1, /* putstatic_quick */ - 1, /* getstatic2_quick */ - 1, /* putstatic2_quick */ - 1, /* invokevirtual_quick */ - 1, /* invokenonvirtual_quick */ - 1, /* invokesuper_quick */ - 1, /* invokestatic_quick */ - 1, /* invokeinterface_quick */ - 1, /* invokevirtualobject_quick */ - 1, /* invokeignored_quick */ - 1, /* new_quick */ - 1, /* anewarray_quick */ - 1, /* multianewarray_quick */ - 1, /* checkcast_quick */ - 1, /* instanceof_quick */ - 1, /* invokevirtual_quick_w */ - 1, /* getfield_quick_w */ - 1, /* putfield_quick_w */ - 1, /* nonnull_quick */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; diff --git a/src/share/javavm/include/opcodes.wide b/src/share/javavm/include/opcodes.wide deleted file mode 100644 index ed33d819b441ef2bcfee3d1a06ed05d26a7ec2f8..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.wide +++ /dev/null @@ -1,256 +0,0 @@ -NoWideOpcode(nop) -NoWideOpcode(aconst_null) -NoWideOpcode(iconst_m1) -NoWideOpcode(iconst_0) -NoWideOpcode(iconst_1) -NoWideOpcode(iconst_2) -NoWideOpcode(iconst_3) -NoWideOpcode(iconst_4) -NoWideOpcode(iconst_5) -NoWideOpcode(lconst_0) -NoWideOpcode(lconst_1) -NoWideOpcode(fconst_0) -NoWideOpcode(fconst_1) -NoWideOpcode(fconst_2) -NoWideOpcode(dconst_0) -NoWideOpcode(dconst_1) -NoWideOpcode(bipush) -NoWideOpcode(sipush) -NoWideOpcode(ldc) -NoWideOpcode(ldc_w) -NoWideOpcode(ldc2_w) -WideOpcode(iload) -WideOpcode(lload) -WideOpcode(fload) -WideOpcode(dload) -WideOpcode(aload) -NoWideOpcode(iload_0) -NoWideOpcode(iload_1) -NoWideOpcode(iload_2) -NoWideOpcode(iload_3) -NoWideOpcode(lload_0) -NoWideOpcode(lload_1) -NoWideOpcode(lload_2) -NoWideOpcode(lload_3) -NoWideOpcode(fload_0) -NoWideOpcode(fload_1) -NoWideOpcode(fload_2) -NoWideOpcode(fload_3) -NoWideOpcode(dload_0) -NoWideOpcode(dload_1) -NoWideOpcode(dload_2) -NoWideOpcode(dload_3) -NoWideOpcode(aload_0) -NoWideOpcode(aload_1) -NoWideOpcode(aload_2) -NoWideOpcode(aload_3) -NoWideOpcode(iaload) -NoWideOpcode(laload) -NoWideOpcode(faload) -NoWideOpcode(daload) -NoWideOpcode(aaload) -NoWideOpcode(baload) -NoWideOpcode(caload) -NoWideOpcode(saload) -WideOpcode(istore) -WideOpcode(lstore) -WideOpcode(fstore) -WideOpcode(dstore) -WideOpcode(astore) -NoWideOpcode(istore_0) -NoWideOpcode(istore_1) -NoWideOpcode(istore_2) -NoWideOpcode(istore_3) -NoWideOpcode(lstore_0) -NoWideOpcode(lstore_1) -NoWideOpcode(lstore_2) -NoWideOpcode(lstore_3) -NoWideOpcode(fstore_0) -NoWideOpcode(fstore_1) -NoWideOpcode(fstore_2) -NoWideOpcode(fstore_3) -NoWideOpcode(dstore_0) -NoWideOpcode(dstore_1) -NoWideOpcode(dstore_2) -NoWideOpcode(dstore_3) -NoWideOpcode(astore_0) -NoWideOpcode(astore_1) -NoWideOpcode(astore_2) -NoWideOpcode(astore_3) -NoWideOpcode(iastore) -NoWideOpcode(lastore) -NoWideOpcode(fastore) -NoWideOpcode(dastore) -NoWideOpcode(aastore) -NoWideOpcode(bastore) -NoWideOpcode(castore) -NoWideOpcode(sastore) -NoWideOpcode(pop) -NoWideOpcode(pop2) -NoWideOpcode(dup) -NoWideOpcode(dup_x1) -NoWideOpcode(dup_x2) -NoWideOpcode(dup2) -NoWideOpcode(dup2_x1) -NoWideOpcode(dup2_x2) -NoWideOpcode(swap) -NoWideOpcode(iadd) -NoWideOpcode(ladd) -NoWideOpcode(fadd) -NoWideOpcode(dadd) -NoWideOpcode(isub) -NoWideOpcode(lsub) -NoWideOpcode(fsub) -NoWideOpcode(dsub) -NoWideOpcode(imul) -NoWideOpcode(lmul) -NoWideOpcode(fmul) -NoWideOpcode(dmul) -NoWideOpcode(idiv) -NoWideOpcode(ldiv) -NoWideOpcode(fdiv) -NoWideOpcode(ddiv) -NoWideOpcode(irem) -NoWideOpcode(lrem) -NoWideOpcode(frem) -NoWideOpcode(drem) -NoWideOpcode(ineg) -NoWideOpcode(lneg) -NoWideOpcode(fneg) -NoWideOpcode(dneg) -NoWideOpcode(ishl) -NoWideOpcode(lshl) -NoWideOpcode(ishr) -NoWideOpcode(lshr) -NoWideOpcode(iushr) -NoWideOpcode(lushr) -NoWideOpcode(iand) -NoWideOpcode(land) -NoWideOpcode(ior) -NoWideOpcode(lor) -NoWideOpcode(ixor) -NoWideOpcode(lxor) -WideOpcode(iinc) -NoWideOpcode(i2l) -NoWideOpcode(i2f) -NoWideOpcode(i2d) -NoWideOpcode(l2i) -NoWideOpcode(l2f) -NoWideOpcode(l2d) -NoWideOpcode(f2i) -NoWideOpcode(f2l) -NoWideOpcode(f2d) -NoWideOpcode(d2i) -NoWideOpcode(d2l) -NoWideOpcode(d2f) -NoWideOpcode(i2b) -NoWideOpcode(i2c) -NoWideOpcode(i2s) -NoWideOpcode(lcmp) -NoWideOpcode(fcmpl) -NoWideOpcode(fcmpg) -NoWideOpcode(dcmpl) -NoWideOpcode(dcmpg) -NoWideOpcode(ifeq) -NoWideOpcode(ifne) -NoWideOpcode(iflt) -NoWideOpcode(ifge) -NoWideOpcode(ifgt) -NoWideOpcode(ifle) -NoWideOpcode(if_icmpeq) -NoWideOpcode(if_icmpne) -NoWideOpcode(if_icmplt) -NoWideOpcode(if_icmpge) -NoWideOpcode(if_icmpgt) -NoWideOpcode(if_icmple) -NoWideOpcode(if_acmpeq) -NoWideOpcode(if_acmpne) -NoWideOpcode(goto) -NoWideOpcode(jsr) -WideOpcode(ret) -NoWideOpcode(tableswitch) -NoWideOpcode(lookupswitch) -NoWideOpcode(ireturn) -NoWideOpcode(lreturn) -NoWideOpcode(freturn) -NoWideOpcode(dreturn) -NoWideOpcode(areturn) -NoWideOpcode(return) -NoWideOpcode(getstatic) -NoWideOpcode(putstatic) -NoWideOpcode(getfield) -NoWideOpcode(putfield) -NoWideOpcode(invokevirtual) -NoWideOpcode(invokespecial) -NoWideOpcode(invokestatic) -NoWideOpcode(invokeinterface) -NoWideOpcode(xxxunusedxxx) -NoWideOpcode(new) -NoWideOpcode(newarray) -NoWideOpcode(anewarray) -NoWideOpcode(arraylength) -NoWideOpcode(athrow) -NoWideOpcode(checkcast) -NoWideOpcode(instanceof) -NoWideOpcode(monitorenter) -NoWideOpcode(monitorexit) -NoWideOpcode(wide) -NoWideOpcode(multianewarray) -NoWideOpcode(ifnull) -NoWideOpcode(ifnonnull) -NoWideOpcode(goto_w) -NoWideOpcode(jsr_w) -NoWideOpcode(breakpoint) -NoWideOpcode(ldc_quick) -NoWideOpcode(ldc_w_quick) -NoWideOpcode(ldc2_w_quick) -NoWideOpcode(getfield_quick) -NoWideOpcode(putfield_quick) -NoWideOpcode(getfield2_quick) -NoWideOpcode(putfield2_quick) -NoWideOpcode(getstatic_quick) -NoWideOpcode(putstatic_quick) -NoWideOpcode(getstatic2_quick) -NoWideOpcode(putstatic2_quick) -NoWideOpcode(invokevirtual_quick) -NoWideOpcode(invokenonvirtual_quick) -NoWideOpcode(invokesuper_quick) -NoWideOpcode(invokestatic_quick) -NoWideOpcode(invokeinterface_quick) -NoWideOpcode(invokevirtualobject_quick) -NoWideOpcode(invokeignored_quick) -NoWideOpcode(new_quick) -NoWideOpcode(anewarray_quick) -NoWideOpcode(multianewarray_quick) -NoWideOpcode(checkcast_quick) -NoWideOpcode(instanceof_quick) -NoWideOpcode(invokevirtual_quick_w) -NoWideOpcode(getfield_quick_w) -NoWideOpcode(putfield_quick_w) -NoWideOpcode(nonnull_quick) -NoWideOpcode(Illegal230) -NoWideOpcode(Illegal231) -NoWideOpcode(Illegal232) -NoWideOpcode(Illegal233) -NoWideOpcode(Illegal234) -NoWideOpcode(Illegal235) -NoWideOpcode(Illegal236) -NoWideOpcode(Illegal237) -NoWideOpcode(Illegal238) -NoWideOpcode(Illegal239) -NoWideOpcode(Illegal240) -NoWideOpcode(Illegal241) -NoWideOpcode(Illegal242) -NoWideOpcode(Illegal243) -NoWideOpcode(Illegal244) -NoWideOpcode(Illegal245) -NoWideOpcode(Illegal246) -NoWideOpcode(Illegal247) -NoWideOpcode(Illegal248) -NoWideOpcode(Illegal249) -NoWideOpcode(Illegal250) -NoWideOpcode(Illegal251) -NoWideOpcode(Illegal252) -NoWideOpcode(Illegal253) -NoWideOpcode(Illegal254) -NoWideOpcode(Illegal255) diff --git a/src/share/javavm/include/sys_api.h b/src/share/javavm/include/sys_api.h deleted file mode 100644 index d7856c3f658f2b0d96e394b18dcb49ff3e6473d8..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/sys_api.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 1994-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. - */ - -#ifndef _JAVASOFT_SYS_API_H_ -#define _JAVASOFT_SYS_API_H_ - -#include "hpi.h" - -extern HPI_MemoryInterface *hpi_memory_interface; -extern HPI_LibraryInterface *hpi_library_interface; -extern HPI_SystemInterface *hpi_system_interface; -extern HPI_ThreadInterface *hpi_thread_interface; -extern HPI_FileInterface *hpi_file_interface; -extern HPI_SocketInterface *hpi_socket_interface; - -#define sysMalloc(x) hpi_memory_interface->Malloc(x) -#define sysRealloc(x,y) hpi_memory_interface->Realloc(x,y) -#define sysFree(x) hpi_memory_interface->Free(x) -#define sysCalloc(x,y) hpi_memory_interface->Calloc(x,y) -#define sysStrdup(x) hpi_memory_interface->Strdup(x) -#define sysMapMem(x,y) hpi_memory_interface->MapMem(x,y) -#define sysUnmapMem(x,y,z) hpi_memory_interface->UnmapMem(x,y,z) -#define sysCommitMem(x,y,z) hpi_memory_interface->CommitMem(x,y,z) -#define sysDecommitMem(x,y,z) hpi_memory_interface->DecommitMem(x,y,z) -#define sysAllocBlock(x,y) hpi_memory_interface->AllocBlock(x,y) -#define sysFreeBlock(x) hpi_memory_interface->FreeBlock(x) - -#define sysBuildLibName(a,b,c,d) hpi_library_interface->BuildLibName(a,b,c,d) -#define sysBuildFunName(a,b,c,d) hpi_library_interface->BuildFunName(a,b,c,d) -#define sysLoadLibrary(a,b,c) hpi_library_interface->LoadLibrary(a,b,c) -#define sysUnloadLibrary(a) hpi_library_interface->UnloadLibrary(a) -#define sysFindLibraryEntry(a,b) hpi_library_interface->FindLibraryEntry(a,b) - -#define sysGetSysInfo() hpi_system_interface->GetSysInfo() -#define sysGetMilliTicks() hpi_system_interface->GetMilliTicks() -#define sysTimeMillis() hpi_system_interface->TimeMillis() - -#define sysSignal(a,b) hpi_system_interface->Signal(a,b) -#define sysRaise(a) hpi_system_interface->Raise(a) -#define sysSignalNotify(a) hpi_system_interface->SignalNotify(a) -#define sysSignalWait() hpi_system_interface->SignalWait() -#define sysShutdown() hpi_system_interface->Shutdown() -#define sysSetLoggingLevel(a) hpi_system_interface->SetLoggingLevel(a) -#define sysSetMonitoringOn(a) hpi_system_interface->SetMonitoringOn(a) -#define sysGetLastErrorString(a,b) hpi_system_interface->GetLastErrorString(a,b) - -#define sysThreadBootstrap(a,b,c) hpi_thread_interface->ThreadBootstrap(a,b,c) -#define sysThreadCreate(a,b,c,d) hpi_thread_interface->ThreadCreate(a,b,c,d) -#define sysThreadSelf() hpi_thread_interface->ThreadSelf() -#define sysThreadYield() hpi_thread_interface->ThreadYield() -#define sysThreadSuspend(a) hpi_thread_interface->ThreadSuspend(a) -#define sysThreadResume(a) hpi_thread_interface->ThreadResume(a) -#define sysThreadSetPriority(a,b) hpi_thread_interface->ThreadSetPriority(a,b) -#define sysThreadGetPriority(a,b) hpi_thread_interface->ThreadGetPriority(a,b) -#define sysThreadStackPointer(a) hpi_thread_interface->ThreadStackPointer(a) -#define sysThreadStackTop(a) hpi_thread_interface->ThreadStackTop(a) -#define sysThreadRegs(a,b) hpi_thread_interface->ThreadRegs(a,b) -#define sysThreadSingle() hpi_thread_interface->ThreadSingle() -#define sysThreadMulti() hpi_thread_interface->ThreadMulti() -#define sysThreadCheckStack() hpi_thread_interface->ThreadCheckStack() -#define sysThreadPostException(a,b) \ - hpi_thread_interface->ThreadPostException(a,b) -#define sysThreadInterrupt(a) hpi_thread_interface->ThreadInterrupt(a) -#define sysThreadIsInterrupted(a,b) \ - hpi_thread_interface->ThreadIsInterrupted(a,b) -#define sysThreadAlloc(a) hpi_thread_interface->ThreadAlloc(a) -#define sysThreadFree() hpi_thread_interface->ThreadFree() -#define sysThreadCPUTime() hpi_thread_interface->ThreadCPUTime() -#define sysThreadGetStatus(a,b) hpi_thread_interface->ThreadGetStatus(a,b) -#define sysThreadEnumerateOver(a,b) \ - hpi_thread_interface->ThreadEnumerateOver(a,b) -#define sysThreadIsRunning(a) hpi_thread_interface->ThreadIsRunning(a) -#define sysThreadProfSuspend(a) hpi_thread_interface->ThreadProfSuspend(a) -#define sysThreadProfResume(a) hpi_thread_interface->ThreadProfResume(a) -#define sysAdjustTimeSlice(a) hpi_thread_interface->AdjustTimeSlice(a) - -#define sysMonitorSizeof() hpi_thread_interface->MonitorSizeof() -#define sysMonitorInit(a) hpi_thread_interface->MonitorInit(a) -#define sysMonitorDestroy(a) hpi_thread_interface->MonitorDestroy(a) -#define sysMonitorEnter(a,b) hpi_thread_interface->MonitorEnter(a,b) -#define sysMonitorEntered(a,b) hpi_thread_interface->MonitorEntered(a,b) -#define sysMonitorExit(a,b) hpi_thread_interface->MonitorExit(a,b) -#define sysMonitorNotify(a,b) hpi_thread_interface->MonitorNotify(a,b) -#define sysMonitorNotifyAll(a,b) hpi_thread_interface->MonitorNotifyAll(a,b) -#define sysMonitorWait(a,b,c) hpi_thread_interface->MonitorWait(a,b,c) -#define sysMonitorInUse(a) hpi_thread_interface->MonitorInUse(a) -#define sysMonitorOwner(a) hpi_thread_interface->MonitorOwner(a) -#define sysMonitorGetInfo(a,b) hpi_thread_interface->MonitorGetInfo(a,b) - -#define sysThreadInterruptEvent() hpi_thread_interface->ThreadInterruptEvent() -#define sysThreadNativeID(a) hpi_thread_interface->ThreadNativeID(a) - -#define sysNativePath(a) hpi_file_interface->NativePath(a) -#define sysFileType(a) hpi_file_interface->FileType(a) -#define sysOpen(a,b,c) hpi_file_interface->Open(a,b,c) -#define sysClose(a) hpi_file_interface->Close(a) -#define sysSeek(a,b,c) hpi_file_interface->Seek(a,b,c) -#define sysSetLength(a,b) hpi_file_interface->SetLength(a,b) -#define sysSync(a) hpi_file_interface->Sync(a) -#define sysAvailable(a,b) hpi_file_interface->Available(a,b) -#define sysRead(a,b,c) hpi_file_interface->Read(a,b,c) -#define sysWrite(a,b,c) hpi_file_interface->Write(a,b,c) -#define sysFileSizeFD(a,b) hpi_file_interface->FileSizeFD(a,b) - -#define sysSocketClose(a) hpi_socket_interface->Close(a) -#define sysSocketShutdown(a,b) hpi_socket_interface->SocketShutdown(a,b) -#define sysSocketAvailable(a,b) hpi_socket_interface->Available(a,b) -#define sysConnect(a,b,c) hpi_socket_interface->Connect(a,b,c) -#define sysBind(a,b,c) hpi_socket_interface->Bind(a,b,c) -#define sysAccept(a,b,c) hpi_socket_interface->Accept(a,b,c) -#define sysGetSockName(a,b,c) hpi_socket_interface->GetSocketName(a,b,c) -#define sysSendTo(a,b,c,d,e,f) hpi_socket_interface->SendTo(a,b,c,d,e,f) -#define sysRecvFrom(a,b,c,d,e,f) hpi_socket_interface->RecvFrom(a,b,c,d,e,f) -#define sysListen(a,b) hpi_socket_interface->Listen(a,b) -#define sysRecv(a,b,c,d) hpi_socket_interface->Recv(a,b,c,d) -#define sysSend(a,b,c,d) hpi_socket_interface->Send(a,b,c,d) -#define sysTimeout(a,b) hpi_socket_interface->Timeout(a,b) -#define sysGetHostName(a, b) hpi_socket_interface->GetHostName(a, b) -#define sysGetHostByAddr(a, b, c) hpi_socket_interface->GetHostByAddr(a, b, c) -#define sysGetHostByName(a) hpi_socket_interface->GetHostByName(a) -#define sysSocket(a,b,c) hpi_socket_interface->Socket(a,b,c) -#define sysGetSockOpt(a, b, c, d, e) hpi_socket_interface->SocketGetOption(a, b, c, d, e) -#define sysSetSockOpt(a, b, c, d, e) hpi_socket_interface->SocketSetOption(a, b, c, d, e) -#define sysGetProtoByName(a) hpi_socket_interface->GetProtoByName(a) - -#define SYS_SIG_DFL HPI_SIG_DFL -#define SYS_SIG_ERR HPI_SIG_ERR -#define SYS_SIG_IGN HPI_SIG_IGN - -#define SYS_OK HPI_OK -#define SYS_ERR HPI_ERR -#define SYS_INTRPT HPI_INTRPT -#define SYS_TIMEOUT HPI_TIMEOUT -#define SYS_NOMEM HPI_NOMEM -#define SYS_NORESOURCE HPI_NORESOURCE - -#define SYS_THREAD_RUNNABLE HPI_THREAD_RUNNABLE -#define SYS_THREAD_MONITOR_WAIT HPI_THREAD_MONITOR_WAIT -#define SYS_THREAD_CONDVAR_WAIT HPI_THREAD_CONDVAR_WAIT - -#define MinimumPriority HPI_MINIMUM_PRIORITY -#define MaximumPriority HPI_MAXIMUM_PRIORITY -#define NormalPriority HPI_NORMAL_PRIORITY - -#define SYS_THREAD_SUSPENDED HPI_THREAD_SUSPENDED -#define SYS_THREAD_INTERRUPTED HPI_THREAD_INTERRUPTED - -#define PAGE_ALIGNMENT HPI_PAGE_ALIGNMENT - -#define SYS_TIMEOUT_INFINITY HPI_TIMEOUT_INFINITY - -#define SYS_FILETYPE_REGULAR HPI_FILETYPE_REGULAR -#define SYS_FILETYPE_DIRECTORY HPI_FILETYPE_DIRECTORY -#define SYS_FILETYPE_OTHER HPI_FILETYPE_OTHER - -#endif /* !_JAVASOFT_SYS_API_H_ */ diff --git a/src/share/javavm/include/typedefs.h b/src/share/javavm/include/typedefs.h deleted file mode 100644 index 6c35063bca7a2764a2ffdb8874120b382094f311..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/typedefs.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 1994-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. - */ - -#ifndef _JAVASOFT_TYPEDEFS_H_ -#define _JAVASOFT_TYPEDEFS_H_ - -#include "typedefs_md.h" /* for int64_t */ - -/* - * Macros to deal with the JavaVM's stack alignment. Many machines - * require doublewords to be double aligned. This union is used by - * code in math.h as a more portable way do alingnment on machines - * that require it. This union and the macros that use it came from - * Netscape. - */ - -#ifdef HAVE_ALIGNED_LONGLONGS -#define GET_INT64(_t,_addr) \ - ((((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - (((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (_t).j ) -#define SET_INT64(_t, _addr, _v) \ - ( (_t).j = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_INT64(_t,_addr) (*(int64_t*)(_addr)) -#define SET_INT64(_t, _addr, _v) (*(int64_t*)(_addr) = (_v)) -#endif - -/* If double's must be aligned on doubleword boundaries then define this */ -#ifdef HAVE_ALIGNED_DOUBLES -#define GET_DOUBLE(_t,_addr) \ - ((((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - (((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (_t).d ) -#define SET_DOUBLE(_t, _addr, _v) \ - ( (_t).d = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_DOUBLE(_t,_addr) (*(jdouble*)(_addr)) -#define SET_DOUBLE(_t, _addr, _v) (*(jdouble*)(_addr) = (_v)) -#endif - -/* If pointers are 64bits then define this */ -#ifdef HAVE_64BIT_POINTERS -#define GET_HANDLE(_t,_addr) \ - ( ((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - ((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (void*) (_t).l ) -#define SET_HANDLE(_t, _addr, _v) \ - ( *(void**) &((_t).l) = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_HANDLE(_t,_addr) (*(JHandle*)(_addr)) -#define SET_HANDLE(_t, _addr, _v) (*(JHandle*)(_addr) = (_v)) -#endif - - -/* - * Printf-style formatters for fixed- and variable-width types as pointers and - * integers. - * - * Each platform-specific definitions file "typedefs_md.h" - * must define the macro FORMAT64_MODIFIER, which is the modifier for '%x' or - * '%d' formats to indicate a 64-bit quantity; commonly "l" (in LP64) or "ll" - * (in ILP32). - */ - -/* Format 32-bit quantities. */ -#define INT32_FORMAT "%d" -#define UINT32_FORMAT "%u" -#define PTR32_FORMAT "0x%08x" - -/* Format 64-bit quantities. */ -#define INT64_FORMAT "%" FORMAT64_MODIFIER "d" -#define UINT64_FORMAT "%" FORMAT64_MODIFIER "u" -#define PTR64_FORMAT "0x%016" FORMAT64_MODIFIER "x" - -/* Format pointers and size_t (or size_t-like integer types) which change size - * between 32- and 64-bit. - */ -#if defined(_LP64) || defined(_WIN64) -#define PTR_FORMAT PTR64_FORMAT -#define SIZE_FORMAT UINT64_FORMAT -#define SSIZE_FORMAT INT64_FORMAT -#else -#define PTR_FORMAT PTR32_FORMAT -#define SIZE_FORMAT UINT32_FORMAT -#define SSIZE_FORMAT INT32_FORMAT -#endif - -#define INTPTR_FORMAT PTR_FORMAT - - -#endif /* !_JAVASOFT_TYPEDEFS_H_ */ diff --git a/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/src/share/native/com/sun/java/util/jar/pack/bands.cpp index d900404dec4d958857fb1c72a4badc130904ea65..c78644c289dae8309cef819ac6dc2a823b4de2cc 100644 --- a/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -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 @@ -126,15 +126,15 @@ void band::readData(int expectedLength) { (*save_meta_rp) = (byte) XB; cm.init(u->rp, u->rplimit, u->meta_rp, 0, defc, length, null); (*save_meta_rp) = save_meta_xb; // put it back, just to be tidy - NOT_PRODUCT(cp2 = (u->meta_rp - meta_rp0)); + NOT_PRODUCT(cp2 = (int)(u->meta_rp - meta_rp0)); } rplimit = u->rp; rewind(); #ifndef PRODUCT - printcr(3,"readFrom %s at %p [%d values, %d bytes, cp=%d/%d]", - (name?name:"(band)"), minRP(), length, size(), cp1, cp2); + PRINTCR((3,"readFrom %s at %p [%d values, %d bytes, cp=%d/%d]", + (name?name:"(band)"), minRP(), length, size(), cp1, cp2)); if (u->verbose_bands || u->verbose >= 4) dump(); if (ix != null && u->verbose != 0 && length > 0) { @@ -421,18 +421,22 @@ const band_init all_band_inits[] = { BAND_INIT(file_modtime, DELTA5_spec, 0), BAND_INIT(file_options, UNSIGNED5_spec, 0), //BAND_INIT(file_bits, BYTE1_spec, 0), - {0} +#ifndef PRODUCT + { 0, 0, 0, 0 } +#else + { 0, 0 } +#endif }; #define NUM_BAND_INITS \ (sizeof(all_band_inits)/sizeof(all_band_inits[0])) band* band::makeBands(unpacker* u) { - band* all_bands = U_NEW(band, BAND_LIMIT); + band* tmp_all_bands = U_NEW(band, BAND_LIMIT); for (int i = 0; i < BAND_LIMIT; i++) { assert((byte*)&all_band_inits[i+1] < (byte*)all_band_inits+sizeof(all_band_inits)); const band_init& bi = all_band_inits[i]; - band& b = all_bands[i]; + band& b = tmp_all_bands[i]; coding* defc = coding::findBySpec(bi.defc); assert((defc == null) == (bi.defc == -1)); // no garbage, please assert(defc == null || !defc->isMalloc); @@ -446,13 +450,13 @@ band* band::makeBands(unpacker* u) { b.name = bi.name; #endif } - return all_bands; + return tmp_all_bands; } void band::initIndexes(unpacker* u) { - band* all_bands = u->all_bands; + band* tmp_all_bands = u->all_bands; for (int i = 0; i < BAND_LIMIT; i++) { - band* scan = &all_bands[i]; + band* scan = &tmp_all_bands[i]; uint tag = scan->ixTag; // Cf. #define INDEX(tag) above if (tag != 0 && tag != CONSTANT_Literal && (tag & SUBINDEX_BIT) == 0) { scan->setIndex(u->cp.getIndex(tag)); diff --git a/src/share/native/com/sun/java/util/jar/pack/bytes.cpp b/src/share/native/com/sun/java/util/jar/pack/bytes.cpp index 95c3dde66e941d1d139fa2c85bc9e96d471b075b..ecc45ce2cb560ca15a2a845b51eb090c8f502f28 100644 --- a/src/share/native/com/sun/java/util/jar/pack/bytes.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/bytes.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2003 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 @@ -71,15 +71,17 @@ void bytes::realloc(size_t len_) { void bytes::free() { if (ptr == dummy) return; // escaping from an error - if (ptr != null) mtrace('f', ptr, 0); - if (ptr != null) ::free(ptr); + if (ptr != null) { + mtrace('f', ptr, 0); + ::free(ptr); + } len = 0; ptr = 0; } int bytes::indexOf(byte c) { byte* p = (byte*) memchr(ptr, c, len); - return (p == 0) ? -1 : p - ptr; + return (p == 0) ? -1 : (int)(p - ptr); } byte* bytes::writeTo(byte* bp) { @@ -174,8 +176,10 @@ void ptrlist::freeAll() { int len = length(); for (int i = 0; i < len; i++) { void* p = (void*) get(i); - if (p != null) mtrace('f', p, 0); - if (p != null) ::free(p); + if (p != null) { + mtrace('f', p, 0); + ::free(p); + } } free(); } diff --git a/src/share/native/com/sun/java/util/jar/pack/bytes.h b/src/share/native/com/sun/java/util/jar/pack/bytes.h index e0c0f6f59825d608b653852913112c5fbca5fedd..f47b7eb05e95d9e2a5c6732f9cad53a3d6580797 100644 --- a/src/share/native/com/sun/java/util/jar/pack/bytes.h +++ b/src/share/native/com/sun/java/util/jar/pack/bytes.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2004 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 @@ -117,7 +117,7 @@ struct fillbytes { struct ptrlist : fillbytes { typedef const void* cvptr; - int length() { return size() / sizeof(cvptr); } + int length() { return (int)(size() / sizeof(cvptr)); } cvptr* base() { return (cvptr*) fillbytes::base(); } cvptr& get(int i) { return *(cvptr*)loc(i * sizeof(cvptr)); } cvptr* limit() { return (cvptr*) fillbytes::limit(); } @@ -133,7 +133,7 @@ struct ptrlist : fillbytes { ::qsort((ptrls).base(), (ptrls).length(), sizeof(void*), fn) struct intlist : fillbytes { - int length() { return size() / sizeof(int); } + int length() { return (int)(size() / sizeof(int)); } int* base() { return (int*) fillbytes::base(); } int& get(int i) { return *(int*)loc(i * sizeof(int)); } int* limit() { return (int*) fillbytes::limit(); } diff --git a/src/share/native/com/sun/java/util/jar/pack/coding.cpp b/src/share/native/com/sun/java/util/jar/pack/coding.cpp index d3ec4ae0e2272441b2702f478a8e8c0380efda72..dec681ccfe4af7ec4596ce1fb78c185ad554c663 100644 --- a/src/share/native/com/sun/java/util/jar/pack/coding.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/coding.cpp @@ -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 @@ -113,7 +113,7 @@ coding* coding::init() { jlong maxNegCode = range-1; while (IS_NEG_CODE(S, maxPosCode)) --maxPosCode; while (!IS_NEG_CODE(S, maxNegCode)) --maxNegCode; - int maxPos = decode_sign(S, maxPosCode); + int maxPos = decode_sign(S, (uint)maxPosCode); if (maxPos < 0) this->max = INT_MAX_VALUE; // 32-bit wraparound else @@ -121,7 +121,7 @@ coding* coding::init() { if (maxNegCode < 0) this->min = 0; // No negative codings at all. else - this->min = decode_sign(S, maxNegCode); + this->min = decode_sign(S, (uint)maxNegCode); } } @@ -149,10 +149,10 @@ coding* coding::findBySpec(int spec) { coding* ptr = NEW(coding, 1); CHECK_NULL_0(ptr); coding* c = ptr->initFrom(spec); - if (c == null) mtrace('f', ptr, 0); - if (c == null) + if (c == null) { + mtrace('f', ptr, 0); ::free(ptr); - else + } else // else caller should free it... c->isMalloc = true; return c; @@ -167,9 +167,10 @@ coding* coding::findBySpec(int B, int H, int S, int D) { } void coding::free() { - if (isMalloc) mtrace('f', this, 0); - if (isMalloc) + if (isMalloc) { + mtrace('f', this, 0); ::free(this); + } } void coding_method::reset(value_stream* state) { @@ -187,7 +188,7 @@ uint coding::parse(byte* &rp, int B, int H) { byte* ptr = rp; // hand peel the i==0 part of the loop: uint b_i = *ptr++ & 0xFF; - if (B == 1 || b_i < L) + if (B == 1 || b_i < (uint)L) { rp = ptr; return b_i; } uint sum = b_i; uint H_i = H; @@ -195,7 +196,7 @@ uint coding::parse(byte* &rp, int B, int H) { for (int i = 2; i <= B_MAX; i++) { // easy for compilers to unroll if desired b_i = *ptr++ & 0xFF; sum += b_i * H_i; - if (i == B || b_i < L) + if (i == B || b_i < (uint)L) { rp = ptr; return sum; } H_i *= H; } @@ -210,7 +211,7 @@ uint coding::parse_lgH(byte* &rp, int B, int H, int lgH) { byte* ptr = rp; // hand peel the i==0 part of the loop: uint b_i = *ptr++ & 0xFF; - if (B == 1 || b_i < L) + if (B == 1 || b_i < (uint)L) { rp = ptr; return b_i; } uint sum = b_i; uint lg_H_i = lgH; @@ -218,7 +219,7 @@ uint coding::parse_lgH(byte* &rp, int B, int H, int lgH) { for (int i = 2; i <= B_MAX; i++) { // easy for compilers to unroll if desired b_i = *ptr++ & 0xFF; sum += b_i << lg_H_i; - if (i == B || b_i < L) + if (i == B || b_i < (uint)L) { rp = ptr; return sum; } lg_H_i += lgH; } @@ -237,7 +238,7 @@ void coding::parseMultiple(byte* &rp, int N, byte* limit, int B, int H) { byte* ptr = rp; if (B == 1 || H == 256) { size_t len = (size_t)N*B; - if (len / B != N || ptr+len > limit) { + if (len / B != (size_t)N || ptr+len > limit) { abort(ERB); return; } @@ -325,7 +326,7 @@ static maybe_inline int getPopValue(value_stream* self, uint uval) { if (uval > 0) { // note that the initial parse performed a range check - assert(uval <= self->cm->fVlength); + assert(uval <= (uint)self->cm->fVlength); return self->cm->fValues[uval-1]; } else { // take an unfavored value @@ -368,7 +369,7 @@ int coding::sumInUnsignedRange(int x, int y) { static maybe_inline int getDeltaValue(value_stream* self, uint uval, bool isSubrange) { - assert((bool)(self->c.isSubrange) == isSubrange); + assert((uint)(self->c.isSubrange) == (uint)isSubrange); assert(self->c.isSubrange | self->c.isFullRange); if (isSubrange) return self->sum = self->c.sumInUnsignedRange(self->sum, (int)uval); @@ -443,7 +444,7 @@ int value_stream::getInt() { uval = coding::parse(rp, B, H); if (S != 0) uval = (uint) decode_sign(S, uval); - return getDeltaValue(this, uval, c.isSubrange); + return getDeltaValue(this, uval, (bool)c.isSubrange); case cmk_BHS1D1full: assert(S == 1 && D == 1 && c.isFullRange); @@ -499,6 +500,9 @@ int value_stream::getInt() { assert(c.spec == BYTE1_spec); assert(B == 1 && H == 256 && S == 0 && D == 0); return getPopValue(this, *rp++ & 0xFF); + + default: + break; } assert(false); return 0; @@ -695,7 +699,7 @@ void coding_method::init(byte* &band_rp, byte* band_limit, for (int i = 0; i < N; i++) { uint val = vs.getInt(); if (val == 0) UN += 1; - if (!(val <= fVlength)) { + if (!(val <= (uint)fVlength)) { abort("pop token out of range"); return; } @@ -728,6 +732,7 @@ void coding_method::init(byte* &band_rp, byte* band_limit, switch (self->vs0.cmk) { case cmk_BHS0: cmk2 = cmk_pop_BHS0; break; case cmk_BYTE1: cmk2 = cmk_pop_BYTE1; break; + default: break; } self->vs0.cmk = cmk2; if (self != this) { @@ -947,15 +952,17 @@ coding basic_codings[] = { CODING_INIT(4,240,1,1), CODING_INIT(4,248,0,1), CODING_INIT(4,248,1,1), - - 0 + CODING_INIT(0,0,0,0) }; #define BASIC_INDEX_LIMIT \ - (sizeof(basic_codings)/sizeof(basic_codings[0])-1) + (int)(sizeof(basic_codings)/sizeof(basic_codings[0])-1) coding* coding::findByIndex(int idx) { - assert(_meta_canon_min == 1); - assert(_meta_canon_max+1 == BASIC_INDEX_LIMIT); +#ifndef PRODUCT + /* Tricky assert here, constants and gcc complains about it without local. */ + int index_limit = BASIC_INDEX_LIMIT; + assert(_meta_canon_min == 1 && _meta_canon_max+1 == index_limit); +#endif if (idx >= _meta_canon_min && idx <= _meta_canon_max) return basic_codings[idx].init(); else diff --git a/src/share/native/com/sun/java/util/jar/pack/coding.h b/src/share/native/com/sun/java/util/jar/pack/coding.h index 4259915d877e3b01c5993357f18252b109458c01..65a036215104e0084467cfeeb70f6c1d46567bb3 100644 --- a/src/share/native/com/sun/java/util/jar/pack/coding.h +++ b/src/share/native/com/sun/java/util/jar/pack/coding.h @@ -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 @@ -35,9 +35,11 @@ struct unpacker; #define CODING_D(x) ((x)>>0 & 0xF) #define CODING_INIT(B, H, S, D) \ - { CODING_SPEC(B, H, S, D) } + { CODING_SPEC(B, H, S, D) , 0, 0, 0, 0, 0, 0, 0, 0} -#define long do_not_use_C_long_types_use_jlong_or_int +// For debugging purposes, some compilers do not like this and will complain. +// #define long do_not_use_C_long_types_use_jlong_or_int +// Use of the type "long" is problematic, do not use it. struct coding { int spec; // B,H,S,D diff --git a/src/share/native/com/sun/java/util/jar/pack/defines.h b/src/share/native/com/sun/java/util/jar/pack/defines.h index 19f7567e7bca7d5282df079f511533adee1c5fce..0bf25d5b0dd7fe65373279e3fa7598b8c7f09c49 100644 --- a/src/share/native/com/sun/java/util/jar/pack/defines.h +++ b/src/share/native/com/sun/java/util/jar/pack/defines.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2004 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 @@ -45,15 +45,15 @@ #ifdef PRODUCT #define IF_PRODUCT(xxx) xxx #define NOT_PRODUCT(xxx) -#define assert(p) (0) -#define printcr false && +#define assert(p) +#define PRINTCR(args) #else #define IF_PRODUCT(xxx) #define NOT_PRODUCT(xxx) xxx -#define assert(p) ((p) || (assert_failed(#p), 1)) -#define printcr u->verbose && u->printcr_if_verbose +#define assert(p) ((p) || assert_failed(#p)) +#define PRINTCR(args) u->verbose && u->printcr_if_verbose args extern "C" void breakpoint(); -extern void assert_failed(const char*); +extern int assert_failed(const char*); #define BREAK (breakpoint()) #endif @@ -79,7 +79,7 @@ extern void assert_failed(const char*); #define lengthof(array) (sizeof(array)/sizeof(array[0])) -#define NEW(T, n) (T*) must_malloc(sizeof(T)*(n)) +#define NEW(T, n) (T*) must_malloc((int)(sizeof(T)*(n))) #define U_NEW(T, n) (T*) u->alloc(sizeof(T)*(n)) #define T_NEW(T, n) (T*) u->temp_alloc(sizeof(T)*(n)) @@ -121,12 +121,12 @@ enum { false, true }; #define null (0) -#ifndef __sparc -#define intptr_t jlong -#endif - -#define ptrlowbits(x) ((int) (intptr_t)(x)) +/* Must cast to void *, then size_t, then int. */ +#define ptrlowbits(x) ((int)(size_t)(void*)(x)) +/* Back and forth from jlong to pointer */ +#define ptr2jlong(x) ((jlong)(size_t)(void*)(x)) +#define jlong2ptr(x) ((void*)(size_t)(x)) // Keys used by Java: #define UNPACK_DEFLATE_HINT "unpack.deflate.hint" diff --git a/src/share/native/com/sun/java/util/jar/pack/jni.cpp b/src/share/native/com/sun/java/util/jar/pack/jni.cpp index d217341dab617031d4763db4ca6d64952fdf4ddd..eb98982783e37246ea08455567d0b1e24de628eb 100644 --- a/src/share/native/com/sun/java/util/jar/pack/jni.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,8 @@ static jlong read_input_via_jni(unpacker* self, void* buf, jlong minlen, jlong maxlen); static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) { - unpacker* uPtr = (unpacker*) env->GetLongField(pObj, unpackerPtrFID); + unpacker* uPtr; + uPtr = (unpacker*)jlong2ptr(env->GetLongField(pObj, unpackerPtrFID)); //fprintf(stderr, "get_unpacker(%p) uPtr=%p\n", pObj, uPtr); if (uPtr == null) { if (noCreate) return null; @@ -71,7 +72,7 @@ static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) { //fprintf(stderr, "get_unpacker(%p) uPtr=%p initializing\n", pObj, uPtr); uPtr->init(read_input_via_jni); uPtr->jniobj = (void*) env->NewGlobalRef(pObj); - env->SetLongField(pObj, unpackerPtrFID, (jlong)uPtr); + env->SetLongField(pObj, unpackerPtrFID, ptr2jlong(uPtr)); } uPtr->jnienv = env; // keep refreshing this in case of MT access return uPtr; @@ -150,7 +151,7 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj, size_t buflen = 0; if (pBuf != null) { buf = env->GetDirectBufferAddress(pBuf); - buflen = env->GetDirectBufferCapacity(pBuf); + buflen = (size_t)env->GetDirectBufferCapacity(pBuf); if (buflen == 0) buf = null; if (buf == null) { THROW_IOE(ERROR_INTERNAL); return 0; } if ((size_t)offset >= buflen) diff --git a/src/share/native/com/sun/java/util/jar/pack/main.cpp b/src/share/native/com/sun/java/util/jar/pack/main.cpp index 9e216cd19c771a2ab20fc7e8a589678befe295eb..789841d2251be968695dca40bc18f69875679741 100644 --- a/src/share/native/com/sun/java/util/jar/pack/main.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,13 +86,13 @@ static jlong read_input_via_stdio(unpacker* u, readlen = (int)(maxlen - numread); int nr = 0; if (u->infileptr != null) { - nr = fread(bufptr, 1, readlen, u->infileptr); + nr = (int)fread(bufptr, 1, readlen, u->infileptr); } else { #ifndef WIN32 // we prefer unbuffered inputs - nr = read(u->infileno, bufptr, readlen); + nr = (int)read(u->infileno, bufptr, readlen); #else - nr = fread(bufptr, 1, readlen, stdin); + nr = (int)fread(bufptr, 1, readlen, stdin); #endif } if (nr <= 0) { @@ -279,7 +279,6 @@ int unpacker::run(int argc, char **argv) { char** argbuf = init_args(argc, argv, envargc); char** arg0 = argbuf+envargc; char** argp = argbuf; - int ach; int verbose = 0; char* logfile = null; @@ -370,7 +369,7 @@ int unpacker::run(int argc, char **argv) { int magic; // check for GZIP input - magic = read_magic(&u, peek, sizeof(peek)); + magic = read_magic(&u, peek, (int)sizeof(peek)); if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC) { // Oops; must slap an input filter on this data. setup_gzin(&u); @@ -397,8 +396,8 @@ int unpacker::run(int argc, char **argv) { if (u.aborting()) break; // Peek ahead for more data. - magic = read_magic(&u, peek, sizeof(peek)); - if (magic != JAVA_PACKAGE_MAGIC) { + magic = read_magic(&u, peek, (int)sizeof(peek)); + if (magic != (int)JAVA_PACKAGE_MAGIC) { if (magic != EOF_MAGIC) u.abort("garbage after end of pack archive"); break; // all done diff --git a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 6480da7002126663c3342de0ead75a6911a5d5ab..90b9f72e4eec01aed98d8eb19de543ce07af3f6b 100644 --- a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 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 @@ -27,6 +27,21 @@ // Program for unpacking specially compressed Java packages. // John R. Rose +/* + * When compiling for a 64bit LP64 system (longs and pointers being 64bits), + * the printf format %ld is correct and use of %lld will cause warning + * errors from some compilers (gcc/g++). + * _LP64 can be explicitly set (used on Linux). + * Solaris compilers will define __sparcv9 or __x86_64 on 64bit compilations. + */ +#if defined(_LP64) || defined(__sparcv9) || defined(__x86_64) + #define LONG_LONG_FORMAT "%ld" + #define LONG_LONG_HEX_FORMAT "%lx" +#else + #define LONG_LONG_FORMAT "%lld" + #define LONG_LONG_HEX_FORMAT "%016llx" +#endif + #include #include @@ -253,12 +268,12 @@ int entry::typeSize() { inline cpindex* cpool::getFieldIndex(entry* classRef) { assert(classRef->tagMatches(CONSTANT_Class)); - assert((uint)classRef->inord < tag_count[CONSTANT_Class]); + assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+0]; } inline cpindex* cpool::getMethodIndex(entry* classRef) { assert(classRef->tagMatches(CONSTANT_Class)); - assert((uint)classRef->inord < tag_count[CONSTANT_Class]); + assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+1]; } @@ -341,7 +356,7 @@ bool unpacker::ensure_input(jlong more) { rplimit += nr; fetch -= nr; bytes_read += nr; - assert(remaining == (input.limit() - rplimit)); + assert(remaining == (julong)(input.limit() - rplimit)); } return true; } @@ -441,9 +456,13 @@ int unpacker::putref_index(entry* e, int size) { e->requestOutputIndex(cp, -size); // Later on we'll fix the bits. class_fixup_type.addByte(size); - class_fixup_offset.add(wpoffset()); + class_fixup_offset.add((int)wpoffset()); class_fixup_ref.add(e); - return !assert(1) ? 0 : 0x20+size; // 0x22 is easy to eyeball +#ifdef PRODUCT + return 0; +#else + return 0x20+size; // 0x22 is easy to eyeball +#endif } } @@ -472,7 +491,7 @@ enum { CHUNK = (1 << 14), SMALL = (1 << 9) }; void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) { CHECK_0; if (!smallOK || size > SMALL) { - void* res = must_malloc(size); + void* res = must_malloc((int)size); (temp ? &tmallocs : &mallocs)->add(res); return res; } @@ -481,7 +500,7 @@ void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) { xsmallbuf.init(CHUNK); (temp ? &tmallocs : &mallocs)->add(xsmallbuf.base()); } - int growBy = size; + int growBy = (int)size; growBy += -growBy & 7; // round up mod 8 return xsmallbuf.grow(growBy); } @@ -514,7 +533,7 @@ void unpacker::read_file_header() { FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN }; bool foreign_buf = (read_input_fn == null); - byte initbuf[FIRST_READ + C_SLOP + 200]; // 200 is for JAR I/O + byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200]; // 200 is for JAR I/O if (foreign_buf) { // inbytes is all there is input.set(inbytes); @@ -553,7 +572,7 @@ void unpacker::read_file_header() { // Copy until EOF; assume the JAR file is the last segment. fprintf(errstrm, "Copy-mode.\n"); for (;;) { - jarout->write_data(rp, input_remaining()); + jarout->write_data(rp, (int)input_remaining()); if (foreign_buf) break; // one-time use of a passed in buffer if (input.size() < CHUNK) { @@ -572,7 +591,7 @@ void unpacker::read_file_header() { // Read the magic number. magic = 0; - for (int i1 = 0; i1 < sizeof(magic); i1++) { + for (int i1 = 0; i1 < (int)sizeof(magic); i1++) { magic <<= 8; magic += (*rp++ & 0xFF); } @@ -586,7 +605,7 @@ void unpacker::read_file_header() { majver = hdr.getInt(); hdrVals += 2; - if (magic != JAVA_PACKAGE_MAGIC || + if (magic != (int)JAVA_PACKAGE_MAGIC || (majver != JAVA5_PACKAGE_MAJOR_VERSION && majver != JAVA6_PACKAGE_MAJOR_VERSION) || (minver != JAVA5_PACKAGE_MINOR_VERSION && @@ -633,19 +652,19 @@ void unpacker::read_file_header() { // Now we can size the whole archive. // Read everything else into a mega-buffer. rp = hdr.rp; - int header_size_0 = (rp - input.base()); // used-up header (4byte + 3int) - int header_size_1 = (rplimit - rp); // buffered unused initial fragment + int header_size_0 = (int)(rp - input.base()); // used-up header (4byte + 3int) + int header_size_1 = (int)(rplimit - rp); // buffered unused initial fragment int header_size = header_size_0+header_size_1; unsized_bytes_read = header_size_0; CHECK; if (foreign_buf) { - if (archive_size > header_size_1) { + if (archive_size > (size_t)header_size_1) { abort("EOF reading fixed input buffer"); return; } } else if (archive_size > 0) { - input.set(U_NEW(byte, (size_t) header_size_0 + archive_size + C_SLOP), - (size_t) header_size_0 + archive_size); + input.set(U_NEW(byte, (size_t)(header_size_0 + archive_size + C_SLOP)), + (size_t) header_size_0 + (size_t)archive_size); assert(input.limit()[0] == 0); // Move all the bytes we read initially into the real buffer. input.b.copyFrom(initbuf, header_size); @@ -712,7 +731,7 @@ void unpacker::read_file_header() { } int cp_counts[N_TAGS_IN_ORDER]; - for (int k = 0; k < N_TAGS_IN_ORDER; k++) { + for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) { if (!(archive_options & AO_HAVE_CP_NUMBERS)) { switch (TAGS_IN_ORDER[k]) { case CONSTANT_Integer: @@ -753,7 +772,10 @@ void unpacker::read_file_header() { abort("EOF reading archive header"); // Now size the CP. - assert(N_TAGS_IN_ORDER == cpool::NUM_COUNTS); +#ifndef PRODUCT + bool x = (N_TAGS_IN_ORDER == cpool::NUM_COUNTS); + assert(x); +#endif //PRODUCT cp.init(this, cp_counts); CHECK; @@ -766,7 +788,7 @@ void unpacker::read_file_header() { // meta-bytes, if any, immediately follow archive header //band_headers.readData(band_headers_size); ensure_input(band_headers_size); - if (input_remaining() < band_headers_size) { + if (input_remaining() < (size_t)band_headers_size) { abort("EOF reading band headers"); return; } @@ -789,12 +811,14 @@ void unpacker::read_file_header() { void unpacker::finish() { if (verbose >= 1) { fprintf(errstrm, - "A total of %lld bytes were read in %d segment(s).\n", - bytes_read_before_reset+bytes_read, + "A total of " + LONG_LONG_FORMAT " bytes were read in %d segment(s).\n", + (bytes_read_before_reset+bytes_read), segments_read_before_reset+1); fprintf(errstrm, - "A total of %lld file content bytes were written.\n", - bytes_written_before_reset+bytes_written); + "A total of " + LONG_LONG_FORMAT " file content bytes were written.\n", + (bytes_written_before_reset+bytes_written)); fprintf(errstrm, "A total of %d files (of which %d are classes) were written to output.\n", files_written_before_reset+files_written, @@ -822,7 +846,7 @@ void cpool::init(unpacker* u_, int counts[NUM_COUNTS]) { int next_entry = 0; // Size the constant pool: - for (int k = 0; k < N_TAGS_IN_ORDER; k++) { + for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) { byte tag = TAGS_IN_ORDER[k]; int len = counts[k]; tag_count[tag] = len; @@ -902,8 +926,8 @@ static byte* skip_Utf8_chars(byte* cp, int len) { } static int compare_Utf8_chars(bytes& b1, bytes& b2) { - int l1 = b1.len; - int l2 = b2.len; + int l1 = (int)b1.len; + int l2 = (int)b2.len; int l0 = (l1 < l2) ? l1 : l2; byte* p1 = b1.ptr; byte* p2 = b2.ptr; @@ -949,10 +973,12 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { // First band: Read lengths of shared prefixes. if (len > PREFIX_SKIP_2) cp_Utf8_prefix.readData(len - PREFIX_SKIP_2); + NOT_PRODUCT(else cp_Utf8_prefix.readData(0)); // for asserts // Second band: Read lengths of unshared suffixes: if (len > SUFFIX_SKIP_1) cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1); + NOT_PRODUCT(else cp_Utf8_suffix.readData(0)); // for asserts bytes* allsuffixes = T_NEW(bytes, len); CHECK; @@ -999,7 +1025,7 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { CHECK; tmallocs.add(chars.ptr); // free it later } else { - int shrink = chars.limit() - chp; + int shrink = (int)(chars.limit() - chp); chars.len -= shrink; charbuf.b.len -= shrink; // ungrow to reclaim buffer space // Note that we did not reclaim the final '\0'. @@ -1008,7 +1034,9 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { } } //cp_Utf8_chars.done(); - if (assert(1)) charbuf.b.set(null, 0); // tidy +#ifndef PRODUCT + charbuf.b.set(null, 0); // tidy +#endif // Fourth band: Go back and size the specially packed strings. int maxlen = 0; @@ -1041,7 +1069,7 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { for (i = 0; i < len; i++) { bytes& chars = allsuffixes[i]; if (chars.ptr != null) continue; // already input - int suffix = chars.len; // pick up the hack + int suffix = (int)chars.len; // pick up the hack uint size3 = suffix * 3; if (suffix == 0) continue; // done with empty string chars.malloc(size3); @@ -1071,7 +1099,7 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { for (i = 0; i < len; i++) { bytes& chars = allsuffixes[i]; int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); - int suffix = chars.len; + int suffix = (int)chars.len; byte* fillp; // by induction, the buffer is already filled with the prefix // make sure the prefix value is not corrupted, though: @@ -1084,7 +1112,7 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { fillp = chars.writeTo(fillp); assert(bigbuf.inBounds(fillp)); *fillp = 0; // bigbuf must contain a well-formed Utf8 string - int length = fillp - bigbuf.ptr; + int length = (int)(fillp - bigbuf.ptr); bytes& value = cpMap[i].value.b; value.set(U_NEW(byte, length+1), length); value.copyFrom(bigbuf.ptr, length); @@ -1215,12 +1243,12 @@ void unpacker::read_cp() { int i; - for (int k = 0; k < N_TAGS_IN_ORDER; k++) { + for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) { byte tag = TAGS_IN_ORDER[k]; int len = cp.tag_count[tag]; int base = cp.tag_base[tag]; - printcr(1,"Reading %d %s entries...", len, NOT_PRODUCT(TAG_NAME[tag])+0); + PRINTCR((1,"Reading %d %s entries...", len, NOT_PRODUCT(TAG_NAME[tag])+0)); entry* cpMap = &cp.entries[base]; for (i = 0; i < len; i++) { cpMap[i].tag = tag; @@ -1282,7 +1310,7 @@ void unpacker::read_cp() { #ifndef PRODUCT cpindex* ix = &cp.tag_index[tag]; assert(ix->ixTag == tag); - assert(ix->len == len); + assert((int)ix->len == len); assert(ix->base1 == cpMap); #endif CHECK; @@ -1293,7 +1321,7 @@ void unpacker::read_cp() { cp.initMemberIndexes(); CHECK; - printcr(1,"parsed %d constant pool entries in %d bytes", cp.nentries, (rp - rp0)); + PRINTCR((1,"parsed %d constant pool entries in %d bytes", cp.nentries, (rp - rp0))); #define SNAME(n,s) #s "\0" const char* symNames = ( @@ -1307,7 +1335,7 @@ void unpacker::read_cp() { bytes name; name.set(symNames); if (name.len > 0 && name.ptr[0] != '0') { cp.sym[sn] = cp.ensureUtf8(name); - printcr(4, "well-known sym %d=%s", sn, cp.sym[sn]->string()); + PRINTCR((4, "well-known sym %d=%s", sn, cp.sym[sn]->string())); } symNames += name.len + 1; // skip trailing null to next name } @@ -1352,7 +1380,7 @@ unpacker::attr_definitions::defineLayout(int idx, assert(flag_limit != 0); // must be set up already if (idx >= 0) { // Fixed attr. - if (idx >= flag_limit) + if (idx >= (int)flag_limit) abort("attribute index too large"); if (isRedefined(idx)) abort("redefined attribute index"); @@ -1635,7 +1663,7 @@ unpacker::attr_definitions::parseLayout(const char* lp, band** &res, for (;;) { int caseval = 0; lp = parseNumeral(lp, caseval); - band_stack.add((void*)caseval); + band_stack.add((void*)(size_t)caseval); if (*lp == '-') { // new in version 160, allow (1-5) for (1,2,3,4,5) if (u->majver < JAVA6_PACKAGE_MAJOR_VERSION) { @@ -1654,7 +1682,7 @@ unpacker::attr_definitions::parseLayout(const char* lp, band** &res, } for (;;) { ++caseval; - band_stack.add((void*)caseval); + band_stack.add((void*)(size_t)caseval); if (caseval == caselimit) break; } } @@ -1921,7 +1949,7 @@ static int lastIndexOf(int chmin, int chmax, bytes& x, int pos) { for (byte* cp = ptr + pos; --cp >= ptr; ) { assert(x.inBounds(cp)); if (*cp >= chmin && *cp <= chmax) - return cp - ptr; + return (int)(cp - ptr); } return -1; } @@ -1976,7 +2004,7 @@ void unpacker::read_ics() { entry* inner = ic_this_class.getRef(); CHECK; uint inord = inner->inord; - assert(inord < cp.tag_count[CONSTANT_Class]); + assert(inord < (uint)cp.tag_count[CONSTANT_Class]); if (ic_index[inord] != null) { abort("identical inner class"); break; @@ -2003,10 +2031,10 @@ void unpacker::read_ics() { bytes number; bytes name; // Parse n into pkgOuter and name (and number). - printcr(5, "parse short IC name %s", n.ptr); + PRINTCR((5, "parse short IC name %s", n.ptr)); int dollar1, dollar2; // pointers to $ in the pattern // parse n = (/)*($)?($)? - int nlen = n.len; + int nlen = (int)n.len; int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, nlen) + 1; dollar2 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, nlen); if (dollar2 < 0) { @@ -2035,8 +2063,8 @@ void unpacker::read_ics() { pkgOuter = n.slice(0, dollar1); else pkgOuter.set(null,0); - printcr(5,"=> %s$ 0%s $%s", - pkgOuter.string(), number.string(), name.string()); + PRINTCR((5,"=> %s$ 0%s $%s", + pkgOuter.string(), number.string(), name.string())); if (pkgOuter.ptr != null) ics[i].outer = cp.ensureClass(pkgOuter); @@ -2049,7 +2077,7 @@ void unpacker::read_ics() { if (ics[i].outer != null) { uint outord = ics[i].outer->inord; if (outord != NO_INORD) { - assert(outord < cp.tag_count[CONSTANT_Class]); + assert(outord < (uint)cp.tag_count[CONSTANT_Class]); ics[i].next_sibling = ic_child_index[outord]; ic_child_index[outord] = &ics[i]; } @@ -2060,8 +2088,7 @@ void unpacker::read_ics() { } void unpacker::read_classes() { - int i; - printcr(1," ...scanning %d classes...", class_count); + PRINTCR((1," ...scanning %d classes...", class_count)); class_this.readData(class_count); class_super.readData(class_count); class_interface_count.readData(class_count); @@ -2070,6 +2097,7 @@ void unpacker::read_classes() { CHECK; #if 0 + int i; // Make a little mark on super-classes. for (i = 0; i < class_count; i++) { entry* e = class_super.getRefN(); @@ -2099,8 +2127,8 @@ void unpacker::read_classes() { read_code_headers(); - printcr(1,"scanned %d classes, %d fields, %d methods, %d code headers", - class_count, field_count, method_count, code_count); + PRINTCR((1,"scanned %d classes, %d fields, %d methods, %d code headers", + class_count, field_count, method_count, code_count)); } maybe_inline @@ -2137,7 +2165,7 @@ void unpacker::read_attrs(int attrc, int obj_count) { } indexBits &= indexMask; // ignore classfile flag bits for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) { - ad.flag_count[idx] += (indexBits & 1); + ad.flag_count[idx] += (int)(indexBits & 1); } } // we'll scan these again later for output: @@ -2337,7 +2365,7 @@ void unpacker::read_attrs(int attrc, int obj_count) { for (idx = 0; idx < ad.layouts.length(); idx++) { if (ad.getLayout(idx) == null) continue; // none at this fixed index <32 - if (idx < ad.flag_limit && ad.isPredefined(idx)) + if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) continue; // already handled if (ad.getCount(idx) == 0) continue; // no attributes of this type (then why transmit layouts?) @@ -2351,9 +2379,9 @@ void unpacker::attr_definitions::readBandData(int idx) { if (count == 0) return; layout_definition* lo = getLayout(idx); if (lo != null) { - printcr(1, "counted %d [redefined = %d predefined = %d] attributes of type %s.%s", + PRINTCR((1, "counted %d [redefined = %d predefined = %d] attributes of type %s.%s", count, isRedefined(idx), isPredefined(idx), - ATTR_CONTEXT_NAME[attrc], lo->name); + ATTR_CONTEXT_NAME[attrc], lo->name)); } bool hasCallables = lo->hasCallables(); band** bands = lo->bands(); @@ -2376,13 +2404,13 @@ void unpacker::attr_definitions::readBandData(int idx) { } } // Now consult whichever callables have non-zero entry counts. - readBandData(bands, -1); + readBandData(bands, (uint)-1); } } // Recursive helper to the previous function: void unpacker::attr_definitions::readBandData(band** body, uint count) { - int i, j, k; + int j, k; for (j = 0; body[j] != null; j++) { band& b = *body[j]; if (b.defc != null) { @@ -2427,7 +2455,7 @@ void unpacker::attr_definitions::readBandData(band** body, uint count) { } break; case EK_CBLE: - assert(count == -1); // incoming count is meaningless + assert((int)count == -1); // incoming count is meaningless k = b.length; assert(k >= 0); // This is intended and required for non production mode. @@ -2490,7 +2518,7 @@ void unpacker::putlayout(band** body) { assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN); x = b.getInt(); - assert(!b.le_bci || prevBCI == to_bci(prevBII)); + assert(!b.le_bci || prevBCI == (int)to_bci(prevBII)); switch (b.le_bci) { case EK_BCI: // PH: transmit R(bci), store bci x = to_bci(prevBII = x); @@ -2505,7 +2533,7 @@ void unpacker::putlayout(band** body) { prevBCI += x; break; } - assert(!b.le_bci || prevBCI == to_bci(prevBII)); + assert(!b.le_bci || prevBCI == (int)to_bci(prevBII)); switch (b.le_len) { case 0: break; @@ -2721,8 +2749,8 @@ band* unpacker::ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar) { // Cf. PackageReader.readByteCodes inline // called exactly once => inline void unpacker::read_bcs() { - printcr(3, "reading compressed bytecodes and operands for %d codes...", - code_count); + PRINTCR((3, "reading compressed bytecodes and operands for %d codes...", + code_count)); // read from bc_codes and bc_case_count fillbytes all_switch_ops; @@ -2825,18 +2853,18 @@ void unpacker::read_bcs() { // Go through the formality, so we can use it in a regular fashion later: assert(rp == rp0); - bc_codes.readData(opptr - rp); + bc_codes.readData((int)(opptr - rp)); int i = 0; // To size instruction bands correctly, we need info on switches: - bc_case_count.readData(all_switch_ops.size()); - for (i = 0; i < all_switch_ops.size(); i++) { + bc_case_count.readData((int)all_switch_ops.size()); + for (i = 0; i < (int)all_switch_ops.size(); i++) { int caseCount = bc_case_count.getInt(); int bc = all_switch_ops.getByte(i); bc_label.expectMoreLength(1+caseCount); // default label + cases bc_case_value.expectMoreLength(bc == bc_tableswitch ? 1 : caseCount); - printcr(2, "switch bc=%d caseCount=%d", bc, caseCount); + PRINTCR((2, "switch bc=%d caseCount=%d", bc, caseCount)); } bc_case_count.rewind(); // uses again for output @@ -2849,15 +2877,14 @@ void unpacker::read_bcs() { // The bc_escbyte band is counted by the immediately previous band. bc_escbyte.readData(bc_escsize.getIntTotal()); - printcr(3, "scanned %d opcode and %d operand bytes for %d codes...", + PRINTCR((3, "scanned %d opcode and %d operand bytes for %d codes...", (int)(bc_codes.size()), (int)(bc_escsize.maxRP() - bc_case_value.minRP()), - code_count); + code_count)); } void unpacker::read_bands() { byte* rp0 = rp; - int i; read_file_header(); CHECK; @@ -2886,9 +2913,9 @@ void unpacker::read_bands() { /// CP routines entry*& cpool::hashTabRef(byte tag, bytes& b) { - printcr(5, "hashTabRef tag=%d %s[%d]", tag, b.string(), b.len); - uint hash = tag + b.len; - for (int i = 0; i < b.len; i++) { + PRINTCR((5, "hashTabRef tag=%d %s[%d]", tag, b.string(), b.len)); + uint hash = tag + (int)b.len; + for (int i = 0; i < (int)b.len; i++) { hash = hash * 31 + (0xFF & b.ptr[i]); } entry** ht = hashTab; @@ -2905,15 +2932,15 @@ entry*& cpool::hashTabRef(byte tag, bytes& b) { // Note: hash2 must be relatively prime to hlen, hence the "|1". hash2 = (((hash % 499) & (hlen-1)) | 1); hash1 += hash2; - if (hash1 >= hlen) hash1 -= hlen; - assert(hash1 < hlen); + if (hash1 >= (uint)hlen) hash1 -= hlen; + assert(hash1 < (uint)hlen); assert(++probes < hlen); } #ifndef PRODUCT hash_probes[0] += 1; hash_probes[1] += probes; #endif - printcr(5, " => @%d %p", hash1, ht[hash1]); + PRINTCR((5, " => @%d %p", hash1, ht[hash1])); return ht[hash1]; } @@ -2939,7 +2966,7 @@ entry* cpool::ensureUtf8(bytes& b) { u->saveTo(e.value.b, b); assert(&e >= first_extra_entry); insert_extra(&e, tag_extras[CONSTANT_Utf8]); - printcr(4,"ensureUtf8 miss %s", e.string()); + PRINTCR((4,"ensureUtf8 miss %s", e.string())); return ix = &e; } @@ -2961,7 +2988,7 @@ entry* cpool::ensureClass(bytes& b) { e.value.b = utf->value.b; assert(&e >= first_extra_entry); insert_extra(&e, tag_extras[CONSTANT_Class]); - printcr(4,"ensureClass miss %s", e.string()); + PRINTCR((4,"ensureClass miss %s", e.string())); return &e; } @@ -2980,7 +3007,7 @@ void cpool::expandSignatures() { int refnum = 0; bytes form = e.refs[refnum++]->asUtf8(); buf.empty(); - for (int j = 0; j < form.len; j++) { + for (int j = 0; j < (int)form.len; j++) { int c = form.ptr[j]; buf.addByte(c); if (c == 'L') { @@ -2990,7 +3017,7 @@ void cpool::expandSignatures() { } assert(refnum == e.nrefs); bytes& sig = buf.b; - printcr(5,"signature %d %s -> %s", i, form.ptr, sig.ptr); + PRINTCR((5,"signature %d %s -> %s", i, form.ptr, sig.ptr)); // try to find a pre-existing Utf8: entry* &e2 = hashTabRef(CONSTANT_Utf8, sig); @@ -2999,7 +3026,7 @@ void cpool::expandSignatures() { e.value.b = e2->value.b; e.refs[0] = e2; e.nrefs = 1; - printcr(5,"signature replaced %d => %s", i, e.string()); + PRINTCR((5,"signature replaced %d => %s", i, e.string())); nreused++; } else { // there is no other replacement; reuse this CP entry as a Utf8 @@ -3007,15 +3034,15 @@ void cpool::expandSignatures() { e.tag = CONSTANT_Utf8; e.nrefs = 0; e2 = &e; - printcr(5,"signature changed %d => %s", e.inord, e.string()); + PRINTCR((5,"signature changed %d => %s", e.inord, e.string())); } nsigs++; } - printcr(1,"expanded %d signatures (reused %d utfs)", nsigs, nreused); + PRINTCR((1,"expanded %d signatures (reused %d utfs)", nsigs, nreused)); buf.free(); // go expunge all references to remaining signatures: - for (i = 0; i < nentries; i++) { + for (i = 0; i < (int)nentries; i++) { entry& e = entries[i]; for (int j = 0; j < e.nrefs; j++) { entry*& e2 = e.refs[j]; @@ -3028,7 +3055,7 @@ void cpool::expandSignatures() { void cpool::initMemberIndexes() { // This function does NOT refer to any class schema. // It is totally internal to the cpool. - int i, j, len; + int i, j; // Get the pre-existing indexes: int nclasses = tag_count[CONSTANT_Class]; @@ -3047,13 +3074,13 @@ void cpool::initMemberIndexes() { for (j = 0; j < nfields; j++) { entry& f = fields[j]; i = f.memberClass()->inord; - assert((uint)i < nclasses); + assert(i < nclasses); field_counts[i]++; } for (j = 0; j < nmethods; j++) { entry& m = methods[j]; i = m.memberClass()->inord; - assert((uint)i < nclasses); + assert(i < nclasses); method_counts[i]++; } @@ -3068,8 +3095,8 @@ void cpool::initMemberIndexes() { // reuse field_counts and member_counts as fill pointers: field_counts[i] = fbase; method_counts[i] = mbase; - printcr(3, "class %d fields @%d[%d] methods @%d[%d]", - i, fbase, fc, mbase, mc); + PRINTCR((3, "class %d fields @%d[%d] methods @%d[%d]", + i, fbase, fc, mbase, mc)); fbase += fc+1; mbase += mc+1; // (the +1 leaves a space between every subarray) @@ -3093,18 +3120,18 @@ void cpool::initMemberIndexes() { #ifndef PRODUCT // Test the result immediately on every class and field. int fvisited = 0, mvisited = 0; - int prevord; + int prevord, len; for (i = 0; i < nclasses; i++) { entry* cls = &classes[i]; cpindex* fix = getFieldIndex(cls); cpindex* mix = getMethodIndex(cls); - printcr(2, "field and method index for %s [%d] [%d]", - cls->string(), mix->len, fix->len); + PRINTCR((2, "field and method index for %s [%d] [%d]", + cls->string(), mix->len, fix->len)); prevord = -1; for (j = 0, len = fix->len; j < len; j++) { entry* f = fix->get(j); assert(f != null); - printcr(3, "- field %s", f->string()); + PRINTCR((3, "- field %s", f->string())); assert(f->memberClass() == cls); assert(prevord < (int)f->inord); prevord = f->inord; @@ -3115,7 +3142,7 @@ void cpool::initMemberIndexes() { for (j = 0, len = mix->len; j < len; j++) { entry* m = mix->get(j); assert(m != null); - printcr(3, "- method %s", m->string()); + PRINTCR((3, "- method %s", m->string())); assert(m->memberClass() == cls); assert(prevord < (int)m->inord); prevord = m->inord; @@ -3164,7 +3191,7 @@ void cpool::resetOutputIndexes() { outputEntries.empty(); #ifndef PRODUCT // they must all be clear now - for (i = 0; i < nentries; i++) + for (i = 0; i < (int)nentries; i++) assert(entries[i].outputIndex == NOT_REQUESTED); #endif } @@ -3215,7 +3242,7 @@ void cpool::computeOutputIndexes() { static uint checkStart = 0; int checkStep = 1; if (nentries > 100) checkStep = nentries / 100; - for (i = (checkStart++ % checkStep); i < nentries; i += checkStep) { + for (i = (int)(checkStart++ % checkStep); i < (int)nentries; i += checkStep) { entry& e = entries[i]; if (e.outputIndex != NOT_REQUESTED) { assert(outputEntries.contains(&e)); @@ -3225,7 +3252,7 @@ void cpool::computeOutputIndexes() { } // check hand-initialization of TAG_ORDER - for (i = 0; i < N_TAGS_IN_ORDER; i++) { + for (i = 0; i < (int)N_TAGS_IN_ORDER; i++) { byte tag = TAGS_IN_ORDER[i]; assert(TAG_ORDER[tag] == i+1); } @@ -3247,7 +3274,7 @@ void cpool::computeOutputIndexes() { if (e.isDoubleWord()) nextIndex++; // do not use the next index } outputIndexLimit = nextIndex; - printcr(3,"renumbering CP to %d entries", outputIndexLimit); + PRINTCR((3,"renumbering CP to %d entries", outputIndexLimit)); } #ifndef PRODUCT @@ -3257,9 +3284,9 @@ unpacker* debug_u; static bytes& getbuf(int len) { // for debugging only! static int bn = 0; - static bytes bufs[8] = { 0 }; + static bytes bufs[8]; bytes& buf = bufs[bn++ & 7]; - while (buf.len < len+10) + while ((int)buf.len < len+10) buf.realloc(buf.len ? buf.len * 2 : 1000); buf.ptr[0] = 0; // for the sake of strcat return buf; @@ -3285,7 +3312,7 @@ char* entry::string() { case CONSTANT_Long: case CONSTANT_Double: buf = getbuf(24); - sprintf((char*)buf.ptr, "0x%016llx", value.l); + sprintf((char*)buf.ptr, "0x" LONG_LONG_HEX_FORMAT, value.l); break; default: if (nrefs == 0) { @@ -3296,7 +3323,7 @@ char* entry::string() { } else { char* s1 = refs[0]->string(); char* s2 = refs[1]->string(); - buf = getbuf(strlen(s1) + 1 + strlen(s2) + 4 + 1); + buf = getbuf((int)strlen(s1) + 1 + (int)strlen(s2) + 4 + 1); buf.strcat(s1).strcat(" ").strcat(s2); if (nrefs > 2) buf.strcat(" ..."); } @@ -3409,7 +3436,9 @@ void unpacker::reset() { segments_read_before_reset += 1; if (verbose >= 2) { fprintf(errstrm, - "After segment %d, %lld bytes read and %lld bytes written.\n", + "After segment %d, " + LONG_LONG_FORMAT " bytes read and " + LONG_LONG_FORMAT " bytes written.\n", segments_read_before_reset-1, bytes_read_before_reset, bytes_written_before_reset); fprintf(errstrm, @@ -3475,7 +3504,9 @@ void unpacker::init(read_input_fn_t input_fn) { int i; NOT_PRODUCT(debug_u = this); BYTES_OF(*this).clear(); - if (assert(1)) free(); // just to make sure freeing is idempotent +#ifndef PRODUCT + free(); // just to make sure freeing is idempotent +#endif this->u = this; // self-reference for U_NEW macro errstrm = stdout; // default error-output log_file = LOGFILE_STDOUT; @@ -3621,7 +3652,7 @@ void unpacker::put_stackmap_type() { maybe_inline void unpacker::put_label(int curIP, int size) { code_fixup_type.addByte(size); - code_fixup_offset.add(put_empty(size)); + code_fixup_offset.add((int)put_empty(size)); code_fixup_source.add(curIP); } @@ -3658,7 +3689,7 @@ void unpacker::write_bc_ops() { } for (int curIP = 0; ; curIP++) { - int curPC = wpoffset() - codeBase; + int curPC = (int)(wpoffset() - codeBase); bcimap.add(curPC); ensure_put_space(10); // covers most instrs w/o further bounds check int bc = *opptr++ & 0xFF; @@ -3702,7 +3733,7 @@ void unpacker::write_bc_ops() { put_label(curIP, 4); //int lVal = bc_label.getInt(); } } - assert(to_bci(curIP) == curPC); + assert((int)to_bci(curIP) == curPC); continue; } case bc_iinc: @@ -3805,7 +3836,7 @@ void unpacker::write_bc_ops() { assert(bc <= bc_jsr_w); put_label(curIP, 4); //putu4(lVal); } - assert(to_bci(curIP) == curPC); + assert((int)to_bci(curIP) == curPC); continue; } bc_which = ref_band_for_op(bc); @@ -3880,7 +3911,7 @@ void unpacker::write_bc_ops() { //bcimap.add(curPC); // PC limit is already also in map, from bc_end_marker // Armed with a bcimap, we can now fix up all the labels. - for (int i = 0; i < code_fixup_type.size(); i++) { + for (int i = 0; i < (int)code_fixup_type.size(); i++) { int type = code_fixup_type.getByte(i); byte* bp = wp_at(code_fixup_offset.get(i)); int curIP = code_fixup_source.get(i); @@ -3896,7 +3927,7 @@ void unpacker::write_bc_ops() { inline // called exactly once => inline void unpacker::write_code() { - int i, j; + int j; int max_stack, max_locals, handler_count, cflags; get_code_header(max_stack, max_locals, handler_count, cflags); @@ -3919,7 +3950,7 @@ void unpacker::write_code() { CHECK; byte* bcbasewp = wp_at(bcbase); - putu4_at(bcbasewp, wp - (bcbasewp+4)); // size of code attr + putu4_at(bcbasewp, (int)(wp - (bcbasewp+4))); // size of code attr putu2(handler_count); for (j = 0; j < handler_count; j++) { @@ -3968,10 +3999,10 @@ int unpacker::write_attrs(int attrc, julong indexBits) { if ((indexBits & 1) != 0) bitIndexes[biCount++] = idx; } - assert(biCount <= lengthof(bitIndexes)); + assert(biCount <= (int)lengthof(bitIndexes)); // Write a provisional attribute count, perhaps to be corrected later. - int naOffset = wpoffset(); + int naOffset = (int)wpoffset(); int na0 = biCount + oiCount; putu2(na0); @@ -3986,7 +4017,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { entry* ref; // scratch size_t abase = put_empty(2+4); CHECK_0; - if (idx < ad.flag_limit && ad.isPredefined(idx)) { + if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) { // Switch on the attrc and idx simultaneously. switch (ADH_BYTE(attrc, idx)) { @@ -4020,16 +4051,16 @@ int unpacker::write_attrs(int attrc, julong indexBits) { if (ref == null) { bytes& n = cur_class->ref(0)->value.b; // parse n = (/)*?($)* - int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, n.len)+1; + int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, (int)n.len)+1; bytes prefix = n.slice(pkglen, n.len); for (;;) { // Work backwards, finding all '$', '#', etc. - int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, prefix.len); + int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, (int)prefix.len); if (dollar < 0) break; prefix = prefix.slice(0, dollar); } const char* suffix = ".java"; - int len = prefix.len + strlen(suffix); + int len = (int)(prefix.len + strlen(suffix)); bytes name; name.set(T_NEW(byte, len + 1), len); name.strcat(prefix).strcat(suffix); ref = cp.ensureUtf8(name); @@ -4081,7 +4112,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { // (253) [(1)(2)(2)] // (254) [(1)(2)(2)(2)] putu2(code_StackMapTable_offset.getInt()); - for (int j2 = (tag - 251); j2 > 0; j2--) { + for (int k = (tag - 251); k > 0; k--) { put_stackmap_type(); } } else { @@ -4165,7 +4196,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { abort("bad layout index"); break; } - assert(lo->idx == idx); + assert((int)lo->idx == idx); aname = lo->nameEntry; if (aname == null) { bytes nameb; nameb.set(lo->name); @@ -4198,7 +4229,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { // patch the name and length putref(aname); - putu4(wp1 - (wp+4)); // put the attr size + putu4((int)(wp1 - (wp+4))); // put the attr size wp = wp1; na++; // count the attrs actually written } @@ -4279,7 +4310,7 @@ void unpacker::write_classfile_tail() { cur_class_has_local_ics = false; // may be set true by write_attrs - int naOffset = wpoffset(); + int naOffset = (int)wpoffset(); int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask)); @@ -4448,7 +4479,7 @@ void unpacker::write_classfile_head() { putu1(tag); switch (tag) { case CONSTANT_Utf8: - putu2(e.value.b.len); + putu2((int)e.value.b.len); put_bytes(e.value.b); break; case CONSTANT_Integer: @@ -4479,7 +4510,7 @@ void unpacker::write_classfile_head() { #ifndef PRODUCT total_cp_size[0] += cp.outputIndexLimit; - total_cp_size[1] += cur_classfile_head.size(); + total_cp_size[1] += (int)cur_classfile_head.size(); #endif close_output(); } @@ -4544,7 +4575,7 @@ unpacker::file* unpacker::get_next_file() { if (cur_file.name[0] == '\0') { bytes& prefix = cur_class->ref(0)->value.b; const char* suffix = ".class"; - int len = prefix.len + strlen(suffix); + int len = (int)(prefix.len + strlen(suffix)); bytes name; name.set(T_NEW(byte, len + 1), len); cur_file.name = name.strcat(prefix).strcat(suffix).strval(); } @@ -4564,7 +4595,7 @@ unpacker::file* unpacker::get_next_file() { } if (rpleft < cur_file.size) { // Caller must read the rest. - size_t fleft = cur_file.size - rpleft; + size_t fleft = (size_t)cur_file.size - rpleft; bytes_read += fleft; // Credit it to the overall archive size. } } @@ -4580,7 +4611,7 @@ void unpacker::write_file_to_jar(unpacker::file* f) { julong fsize = f->size; #ifndef PRODUCT if (nowrite NOT_PRODUCT(|| skipfiles-- > 0)) { - printcr(2,"would write %d bytes to %s", (int) fsize, f->name); + PRINTCR((2,"would write %d bytes to %s", (int) fsize, f->name)); return; } #endif @@ -4623,7 +4654,8 @@ void unpacker::write_file_to_jar(unpacker::file* f) { part1, part2); } if (verbose >= 3) { - fprintf(errstrm, "Wrote %lld bytes to: %s\n", fsize, f->name); + fprintf(errstrm, "Wrote " + LONG_LONG_FORMAT " bytes to: %s\n", fsize, f->name); } } diff --git a/src/share/native/com/sun/java/util/jar/pack/unpack.h b/src/share/native/com/sun/java/util/jar/pack/unpack.h index 7ab8e07b2acf6e271a9a72c742d394775438e9ff..8bad674e0850870a1abe52e7db12d15958c2de1b 100644 --- a/src/share/native/com/sun/java/util/jar/pack/unpack.h +++ b/src/share/native/com/sun/java/util/jar/pack/unpack.h @@ -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 @@ -314,7 +314,7 @@ struct unpacker { void readBandData(band** body, uint count); // recursive helper layout_definition* getLayout(uint idx) { - if (idx >= layouts.length()) return null; + if (idx >= (uint)layouts.length()) return null; return (layout_definition*) layouts.get(idx); } @@ -332,12 +332,12 @@ struct unpacker { int predefCount(uint idx); bool isRedefined(uint idx) { - assert(idx < flag_limit); - return ((redef >> idx) & 1); + if (idx >= flag_limit) return false; + return (bool)((redef >> idx) & 1); } bool isPredefined(uint idx) { - assert(idx < flag_limit); - return (((predef & ~redef) >> idx) & 1); + if (idx >= flag_limit) return false; + return (bool)(((predef & ~redef) >> idx) & 1); } julong flagIndexMask() { return (predef | redef); @@ -345,9 +345,9 @@ struct unpacker { bool isIndex(uint idx) { assert(flag_limit != 0); // must be set up already if (idx < flag_limit) - return (((predef | redef) >> idx) & 1); + return (bool)(((predef | redef) >> idx) & 1); else - return (idx - flag_limit < overflow_count.length()); + return (idx - flag_limit < (uint)overflow_count.length()); } int& getCount(uint idx) { assert(isIndex(idx)); diff --git a/src/share/native/com/sun/java/util/jar/pack/utils.cpp b/src/share/native/com/sun/java/util/jar/pack/utils.cpp index 4f45c84b524baf1b895c4570db92690d38bfb6cd..9566e541233d40365720f5e0564619d2ac7b3782 100644 --- a/src/share/native/com/sun/java/util/jar/pack/utils.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2004 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 @@ -65,7 +65,7 @@ void* must_malloc(int size) { void mkdirs(int oklen, char* path) { - if (strlen(path) <= oklen) return; + if (strlen(path) <= (size_t)oklen) return; char dir[PATH_MAX]; strcpy(dir, path); @@ -79,12 +79,13 @@ void mkdirs(int oklen, char* path) { #ifndef PRODUCT void breakpoint() { } // hook for debugger -void assert_failed(const char* p) { +int assert_failed(const char* p) { char message[1<<12]; sprintf(message, "@assert failed: %s\n", p); fprintf(stdout, 1+message); breakpoint(); unpack_abort(message); + return 0; } #endif diff --git a/src/share/native/com/sun/java/util/jar/pack/utils.h b/src/share/native/com/sun/java/util/jar/pack/utils.h index 6176634bcaf1674be02614f1aa6692b5576abb6e..2fc1728d8e7359e5d20d38c0e71eddcaac04b144 100644 --- a/src/share/native/com/sun/java/util/jar/pack/utils.h +++ b/src/share/native/com/sun/java/util/jar/pack/utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2003 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 @@ -27,7 +27,7 @@ void* must_malloc(int size); #ifndef USE_MTRACE -#define mtrace(c, ptr, size) (0) +#define mtrace(c, ptr, size) #else void mtrace(char c, void* ptr, size_t size); #endif diff --git a/src/share/native/com/sun/java/util/jar/pack/zip.cpp b/src/share/native/com/sun/java/util/jar/pack/zip.cpp index 1042738f23024e250d91d12c7646b9d8a2b6acf9..6bfb64463a17cbee83a7cb7e03b0d88eb0452eac 100644 --- a/src/share/native/com/sun/java/util/jar/pack/zip.cpp +++ b/src/share/native/com/sun/java/util/jar/pack/zip.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 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 @@ -85,7 +85,7 @@ void jar::init(unpacker* u_) { // Write data to the ZIP output stream. void jar::write_data(void* buff, int len) { while (len > 0) { - int rc = fwrite(buff, 1, len, jarfp); + int rc = (int)fwrite(buff, 1, len, jarfp); if (rc <= 0) { fprintf(u->errstrm, "Error: write on output file failed err=%d\n",errno); exit(1); // Called only from the native standalone unpacker @@ -98,17 +98,17 @@ void jar::write_data(void* buff, int len) { void jar::add_to_jar_directory(const char* fname, bool store, int modtime, int len, int clen, uLong crc) { - uint fname_length = strlen(fname); + uint fname_length = (uint)strlen(fname); ushort header[23]; if (modtime == 0) modtime = default_modtime; uLong dostime = get_dostime(modtime); - header[0] = SWAP_BYTES(0x4B50); - header[1] = SWAP_BYTES(0x0201); - header[2] = SWAP_BYTES(0xA); + header[0] = (ushort)SWAP_BYTES(0x4B50); + header[1] = (ushort)SWAP_BYTES(0x0201); + header[2] = (ushort)SWAP_BYTES(0xA); // required version - header[3] = SWAP_BYTES(0xA); + header[3] = (ushort)SWAP_BYTES(0xA); // flags 02 = maximum sub-compression flag header[4] = ( store ) ? 0x0 : SWAP_BYTES(0x2); @@ -117,23 +117,23 @@ void jar::add_to_jar_directory(const char* fname, bool store, int modtime, header[5] = ( store ) ? 0x0 : SWAP_BYTES(0x08); // Last modified date and time. - header[6] = GET_INT_LO(dostime); - header[7] = GET_INT_HI(dostime); + header[6] = (ushort)GET_INT_LO(dostime); + header[7] = (ushort)GET_INT_HI(dostime); // CRC - header[8] = GET_INT_LO(crc); - header[9] = GET_INT_HI(crc); + header[8] = (ushort)GET_INT_LO(crc); + header[9] = (ushort)GET_INT_HI(crc); // Compressed length: - header[10] = GET_INT_LO(clen); - header[11] = GET_INT_HI(clen); + header[10] = (ushort)GET_INT_LO(clen); + header[11] = (ushort)GET_INT_HI(clen); // Uncompressed length. - header[12] = GET_INT_LO(len); - header[13] = GET_INT_HI(len); + header[12] = (ushort)GET_INT_LO(len); + header[13] = (ushort)GET_INT_HI(len); // Filename length - header[14] = SWAP_BYTES(fname_length); + header[14] = (ushort)SWAP_BYTES(fname_length); // So called "extra field" length. header[15] = 0; // So called "comment" length. @@ -146,8 +146,8 @@ void jar::add_to_jar_directory(const char* fname, bool store, int modtime, header[19] = 0; header[20] = 0; // Offset within ZIP file. - header[21] = GET_INT_LO(output_file_offset); - header[22] = GET_INT_HI(output_file_offset); + header[21] = (ushort)GET_INT_LO(output_file_offset); + header[22] = (ushort)GET_INT_HI(output_file_offset); // Copy the whole thing into the central directory. central_directory.append(header, sizeof(header)); @@ -160,17 +160,17 @@ void jar::add_to_jar_directory(const char* fname, bool store, int modtime, void jar::write_jar_header(const char* fname, bool store, int modtime, int len, int clen, uint crc) { - uint fname_length = strlen(fname); + uint fname_length = (uint)strlen(fname); ushort header[15]; if (modtime == 0) modtime = default_modtime; uLong dostime = get_dostime(modtime); // ZIP LOC magic. - header[0] = SWAP_BYTES(0x4B50); - header[1] = SWAP_BYTES(0x0403); + header[0] = (ushort)SWAP_BYTES(0x4B50); + header[1] = (ushort)SWAP_BYTES(0x0403); // Version - header[2] = SWAP_BYTES(0xA); + header[2] = (ushort)SWAP_BYTES(0xA); // flags 02 = maximum sub-compression flag header[3] = ( store ) ? 0x0 : SWAP_BYTES(0x2); @@ -179,31 +179,31 @@ void jar::write_jar_header(const char* fname, bool store, int modtime, header[4] = ( store ) ? 0x0 : SWAP_BYTES(0x08); // Last modified date and time. - header[5] = GET_INT_LO(dostime); - header[6] = GET_INT_HI(dostime); + header[5] = (ushort)GET_INT_LO(dostime); + header[6] = (ushort)GET_INT_HI(dostime); // CRC - header[7] = GET_INT_LO(crc); - header[8] = GET_INT_HI(crc); + header[7] = (ushort)GET_INT_LO(crc); + header[8] = (ushort)GET_INT_HI(crc); // Compressed length: - header[9] = GET_INT_LO(clen); - header[10] = GET_INT_HI(clen); + header[9] = (ushort)GET_INT_LO(clen); + header[10] = (ushort)GET_INT_HI(clen); // Uncompressed length. - header[11] = GET_INT_LO(len); - header[12] = GET_INT_HI(len); + header[11] = (ushort)GET_INT_LO(len); + header[12] = (ushort)GET_INT_HI(len); // Filename length - header[13] = SWAP_BYTES(fname_length); + header[13] = (ushort)SWAP_BYTES(fname_length); // So called "extra field" length. header[14] = 0; // Write the LOC header to the output file. - write_data(header, sizeof(header)); + write_data(header, (int)sizeof(header)); // Copy the fname to the header. - write_data((char*)fname, fname_length); + write_data((char*)fname, (int)fname_length); } static const char marker_comment[] = ZIP_ARCHIVE_MARKER_COMMENT; @@ -214,32 +214,32 @@ void jar::write_central_directory() { ushort header[11]; // Create the End of Central Directory structure. - header[0] = SWAP_BYTES(0x4B50); - header[1] = SWAP_BYTES(0x0605); + header[0] = (ushort)SWAP_BYTES(0x4B50); + header[1] = (ushort)SWAP_BYTES(0x0605); // disk numbers header[2] = 0; header[3] = 0; // Number of entries in central directory. - header[4] = SWAP_BYTES(central_directory_count); - header[5] = SWAP_BYTES(central_directory_count); + header[4] = (ushort)SWAP_BYTES(central_directory_count); + header[5] = (ushort)SWAP_BYTES(central_directory_count); // Size of the central directory} - header[6] = GET_INT_LO(central_directory.size()); - header[7] = GET_INT_HI(central_directory.size()); + header[6] = (ushort)GET_INT_LO((int)central_directory.size()); + header[7] = (ushort)GET_INT_HI((int)central_directory.size()); // Offset of central directory within disk. - header[8] = GET_INT_LO(output_file_offset); - header[9] = GET_INT_HI(output_file_offset); + header[8] = (ushort)GET_INT_LO(output_file_offset); + header[9] = (ushort)GET_INT_HI(output_file_offset); // zipfile comment length; - header [10] = SWAP_BYTES(mc.len); + header [10] = (ushort)SWAP_BYTES((int)mc.len); // Write the central directory. - printcr(2, "Central directory at %d\n", output_file_offset); + PRINTCR((2, "Central directory at %d\n", output_file_offset)); write_data(central_directory.b); // Write the End of Central Directory structure. - printcr(2, "end-of-directory at %d\n", output_file_offset); - write_data(header, sizeof(header)); + PRINTCR((2, "end-of-directory at %d\n", output_file_offset)); + write_data(header, (int)sizeof(header)); - printcr(2, "writing zip comment\n"); + PRINTCR((2, "writing zip comment\n")); // Write the comment. write_data(mc); } @@ -249,7 +249,7 @@ void jar::write_central_directory() { // Open a Jar file and initialize. void jar::openJarFile(const char* fname) { if (!jarfp) { - printcr(1, "jar::openJarFile: opening %s\n",fname); + PRINTCR((1, "jar::openJarFile: opening %s\n",fname)); jarfp = fopen(fname, "wb"); if (!jarfp) { fprintf(u->errstrm, "Error: Could not open jar file: %s\n",fname); @@ -262,25 +262,25 @@ void jar::openJarFile(const char* fname) { void jar::addJarEntry(const char* fname, bool deflate_hint, int modtime, bytes& head, bytes& tail) { - int len = head.len + tail.len; + int len = (int)(head.len + tail.len); int clen = 0; - uint crc = get_crc32(0L,Z_NULL,0); + uint crc = get_crc32(0,Z_NULL,0); if (head.len != 0) - crc = get_crc32(crc, (uchar *)head.ptr, head.len); + crc = get_crc32(crc, (uchar *)head.ptr, (uint)head.len); if (tail.len != 0) - crc = get_crc32(crc, (uchar *)tail.ptr, tail.len); + crc = get_crc32(crc, (uchar *)tail.ptr, (uint)tail.len); bool deflate = (deflate_hint && len > 0); if (deflate) { if (deflate_bytes(head, tail) == false) { - printcr(2, "Reverting to store fn=%s\t%d -> %d\n", - fname, len, deflated.size()); + PRINTCR((2, "Reverting to store fn=%s\t%d -> %d\n", + fname, len, deflated.size())); deflate = false; } } - clen = (deflate) ? deflated.size() : len; + clen = (int)((deflate) ? deflated.size() : len); add_to_jar_directory(fname, !deflate, modtime, len, clen, crc); write_jar_header( fname, !deflate, modtime, len, clen, crc); @@ -306,7 +306,7 @@ void jar::closeJarFile(bool central) { if (central) write_central_directory(); fflush(jarfp); fclose(jarfp); - printcr(2, "jar::closeJarFile:closed jar-file\n"); + PRINTCR((2, "jar::closeJarFile:closed jar-file\n")); } reset(); } @@ -338,6 +338,7 @@ uLong jar::get_dostime(int modtime) { default_modtime = modtime; // catch a reasonable default time_t t = modtime; struct tm sbuf; + (void)memset((void*)&sbuf,0, sizeof(sbuf)); struct tm* s = gmtime_r(&t, &sbuf); modtime_cache = modtime; dostime_cache = dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday, @@ -355,7 +356,7 @@ uLong jar::get_dostime(int modtime) { input data */ bool jar::deflate_bytes(bytes& head, bytes& tail) { - int len = head.len + tail.len; + int len = (int)(head.len + tail.len); z_stream zs; BYTES_OF(zs).clear(); @@ -368,26 +369,26 @@ bool jar::deflate_bytes(bytes& head, bytes& tail) { if (error != Z_OK) { switch (error) { case Z_MEM_ERROR: - printcr(2, "Error: deflate error : Out of memory \n"); + PRINTCR((2, "Error: deflate error : Out of memory \n")); break; case Z_STREAM_ERROR: - printcr(2,"Error: deflate error : Invalid compression level \n"); + PRINTCR((2,"Error: deflate error : Invalid compression level \n")); break; case Z_VERSION_ERROR: - printcr(2,"Error: deflate error : Invalid version\n"); + PRINTCR((2,"Error: deflate error : Invalid version\n")); break; default: - printcr(2,"Error: Internal deflate error error = %d\n", error); + PRINTCR((2,"Error: Internal deflate error error = %d\n", error)); } return false; } deflated.empty(); zs.next_out = (uchar*) deflated.grow(len + (len/2)); - zs.avail_out = deflated.size(); + zs.avail_out = (int)deflated.size(); zs.next_in = (uchar*)head.ptr; - zs.avail_in = head.len; + zs.avail_in = (int)head.len; bytes* first = &head; bytes* last = &tail; @@ -400,28 +401,28 @@ bool jar::deflate_bytes(bytes& head, bytes& tail) { if (first != null && error == Z_OK) { zs.next_in = (uchar*) first->ptr; - zs.avail_in = first->len; + zs.avail_in = (int)first->len; error = deflate(&zs, Z_NO_FLUSH); } if (error == Z_OK) { zs.next_in = (uchar*) last->ptr; - zs.avail_in = last->len; + zs.avail_in = (int)last->len; error = deflate(&zs, Z_FINISH); } if (error == Z_STREAM_END) { - if (len > zs.total_out ) { - printcr(2, "deflate compressed data %d -> %d\n", len, zs.total_out); + if (len > (int)zs.total_out ) { + PRINTCR((2, "deflate compressed data %d -> %d\n", len, zs.total_out)); deflated.b.len = zs.total_out; deflateEnd(&zs); return true; } - printcr(2, "deflate expanded data %d -> %d\n", len, zs.total_out); + PRINTCR((2, "deflate expanded data %d -> %d\n", len, zs.total_out)); deflateEnd(&zs); return false; } deflateEnd(&zs); - printcr(2, "Error: deflate error deflate did not finish error=%d\n",error); + PRINTCR((2, "Error: deflate error deflate did not finish error=%d\n",error)); return false; } @@ -486,7 +487,7 @@ void gunzip::init(unpacker* u_) { BYTES_OF(*this).clear(); u = u_; assert(u->gzin == null); // once only, please - read_input_fn = (void*)(intptr_t)u->read_input_fn; + read_input_fn = (void*)u->read_input_fn; zstream = NEW(z_stream, 1); u->gzin = this; u->read_input_fn = read_input_via_gzip; @@ -555,7 +556,7 @@ void gunzip::read_fixed_field(char* buf, size_t buflen) { if (aborting()) return; jlong nr = ((unpacker::read_input_fn_t)read_input_fn) (u, buf, buflen, buflen); - if (nr != buflen) + if ((size_t)nr != buflen) u->abort("short stream header"); } diff --git a/src/share/native/com/sun/java/util/jar/pack/zip.h b/src/share/native/com/sun/java/util/jar/pack/zip.h index 358dbe51fae76e0186524a5584b8cb299f5df6bb..007dfc3f76e3a1f74b28af22e79db7e95c64c601 100644 --- a/src/share/native/com/sun/java/util/jar/pack/zip.h +++ b/src/share/native/com/sun/java/util/jar/pack/zip.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2004 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 @@ -69,7 +69,7 @@ struct jar { // Private Methods void write_data(void* ptr, int len); - void write_data(bytes& b) { write_data(b.ptr, b.len); } + void write_data(bytes& b) { write_data(b.ptr, (int)b.len); } void add_to_jar_directory(const char* fname, bool store, int modtime, int len, int clen, uLong crc); void write_jar_header(const char* fname, bool store, int modtime, diff --git a/src/share/native/common/check_code.c b/src/share/native/common/check_code.c index d06b2eddd6257fc58ceec55b7117a1942f4fcbd4..7e1613255dcf48924fd92b93447469ebcf049644 100644 --- a/src/share/native/common/check_code.c +++ b/src/share/native/common/check_code.c @@ -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 @@ -87,10 +87,7 @@ #include "jni.h" #include "jvm.h" -#include "typedefs.h" - -#include "opcodes.h" -#include "opcodes.length" +#include "classfile_constants.h" #include "opcodes.in_out" #define MAX_ARRAY_DIMENSIONS 255 @@ -161,8 +158,8 @@ typedef unsigned int *bitvector; #define NULL_FULLINFO MAKE_FULLINFO(ITEM_Object, 0, 0) -/* opc_invokespecial calls to need to be treated special */ -#define opc_invokeinit 0x100 +/* JVM_OPC_invokespecial calls to need to be treated special */ +#define JVM_OPC_invokeinit 0x100 /* A hash mechanism used by the verifier. * Maps class names to unique 16 bit integers. @@ -301,7 +298,7 @@ struct mask_type { typedef unsigned short flag_type; struct instruction_data_type { - opcode_type opcode; /* may turn into "canonical" opcode */ + int opcode; /* may turn into "canonical" opcode */ unsigned changed:1; /* has it changed */ unsigned protected:1; /* must accessor be a subclass of "this" */ union { @@ -345,7 +342,7 @@ static void free_all_code(int num_methods, int* lengths, unsigned char** code); static void verify_field(context_type *context, jclass cb, int index); static void verify_opcode_operands (context_type *, unsigned int inumber, int offset); -static void set_protected(context_type *, unsigned int inumber, int key, opcode_type); +static void set_protected(context_type *, unsigned int inumber, int key, int); static jboolean is_superclass(context_type *, fullinfo_type); static void initialize_exception_table(context_type *); @@ -1084,7 +1081,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) int *code_data = context->code_data; int mi = context->method_index; unsigned char *code = context->code; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int var; /* @@ -1096,17 +1093,17 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) switch (opcode) { - case opc_jsr: + case JVM_OPC_jsr: /* instruction of ret statement */ this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; /* FALLTHROUGH */ - case opc_ifeq: case opc_ifne: case opc_iflt: - case opc_ifge: case opc_ifgt: case opc_ifle: - case opc_ifnull: case opc_ifnonnull: - case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: - case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: - case opc_if_acmpeq: case opc_if_acmpne: - case opc_goto: { + case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_iflt: + case JVM_OPC_ifge: case JVM_OPC_ifgt: case JVM_OPC_ifle: + case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: + case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmplt: + case JVM_OPC_if_icmpge: case JVM_OPC_if_icmpgt: case JVM_OPC_if_icmple: + case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: + case JVM_OPC_goto: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; int target = offset + jump; @@ -1116,11 +1113,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_jsr_w: + case JVM_OPC_jsr_w: /* instruction of ret statement */ this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; /* FALLTHROUGH */ - case opc_goto_w: { + case JVM_OPC_goto_w: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 24) + (code[offset+2] << 16) + (code[offset+3] << 8) + @@ -1132,8 +1129,8 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_tableswitch: - case opc_lookupswitch: { + case JVM_OPC_tableswitch: + case JVM_OPC_lookupswitch: { /* Set the ->operand to be a table of possible instruction targets. */ int *lpc = (int *) UCALIGN(code + offset + 1); int *lptr; @@ -1147,7 +1144,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) CCerror(context, "Non zero padding bytes in switch"); } } - if (opcode == opc_tableswitch) { + if (opcode == JVM_OPC_tableswitch) { keys = ntohl(lpc[2]) - ntohl(lpc[1]) + 1; delta = 1; } else { @@ -1169,7 +1166,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) { int target = offset + ntohl(lptr[0]); if (!isLegalTarget(context, target)) - CCerror(context, "Illegal branch in opc_tableswitch"); + CCerror(context, "Illegal branch in tableswitch"); saved_operand[k + 1] = code_data[target]; } saved_operand[0] = keys + 1; /* number of successors */ @@ -1177,7 +1174,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc: { + case JVM_OPC_ldc: { /* Make sure the constant pool item is the right type. */ int key = code[offset + 1]; int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | @@ -1190,7 +1187,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc_w: { + case JVM_OPC_ldc_w: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | @@ -1203,7 +1200,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc2_w: { + case JVM_OPC_ldc2_w: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; int types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long); @@ -1212,28 +1209,28 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_getfield: case opc_putfield: - case opc_getstatic: case opc_putstatic: { + case JVM_OPC_getfield: case JVM_OPC_putfield: + case JVM_OPC_getstatic: case JVM_OPC_putstatic: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; this_idata->operand.i = key; verify_constant_pool_type(context, key, 1 << JVM_CONSTANT_Fieldref); - if (opcode == opc_getfield || opcode == opc_putfield) + if (opcode == JVM_OPC_getfield || opcode == JVM_OPC_putfield) set_protected(context, inumber, key, opcode); break; } - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: { + case JVM_OPC_invokevirtual: + case JVM_OPC_invokespecial: + case JVM_OPC_invokestatic: + case JVM_OPC_invokeinterface: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; const char *methodname; jclass cb = context->class; fullinfo_type clazz_info; int is_constructor, is_internal; - int kind = (opcode == opc_invokeinterface + int kind = (opcode == JVM_OPC_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref : 1 << JVM_CONSTANT_Methodref); /* Make sure the constant pool item is the right type. */ @@ -1249,16 +1246,16 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) this_idata->operand.i = key; this_idata->operand2.fi = clazz_info; if (is_constructor) { - if (opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokespecial) { CCerror(context, "Must call initializers using invokespecial"); } - this_idata->opcode = opc_invokeinit; + this_idata->opcode = JVM_OPC_invokeinit; } else { if (is_internal) { CCerror(context, "Illegal call to internal method"); } - if (opcode == opc_invokespecial + if (opcode == JVM_OPC_invokespecial && clazz_info != context->currentclass_info && clazz_info != context->superclass_info) { int not_found = 1; @@ -1290,7 +1287,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } } - if (opcode == opc_invokeinterface) { + if (opcode == JVM_OPC_invokeinterface) { unsigned int args1; unsigned int args2; const char *signature = @@ -1300,25 +1297,25 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) args2 = code[offset + 3]; if (args1 != args2) { CCerror(context, - "Inconsistent args_size for opc_invokeinterface"); + "Inconsistent args_size for invokeinterface"); } if (code[offset + 4] != 0) { CCerror(context, "Fourth operand byte of invokeinterface must be zero"); } pop_and_free(context); - } else if (opcode == opc_invokevirtual - || opcode == opc_invokespecial) + } else if (opcode == JVM_OPC_invokevirtual + || opcode == JVM_OPC_invokespecial) set_protected(context, inumber, key, opcode); break; } - case opc_instanceof: - case opc_checkcast: - case opc_new: - case opc_anewarray: - case opc_multianewarray: { + case JVM_OPC_instanceof: + case JVM_OPC_checkcast: + case JVM_OPC_new: + case JVM_OPC_anewarray: + case JVM_OPC_multianewarray: { /* Make sure the constant pool item is a class */ int key = (code[offset + 1] << 8) + code[offset + 2]; fullinfo_type target; @@ -1327,14 +1324,14 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) if (GET_ITEM_TYPE(target) == ITEM_Bogus) CCerror(context, "Illegal type"); switch(opcode) { - case opc_anewarray: + case JVM_OPC_anewarray: if ((GET_INDIRECTION(target)) >= MAX_ARRAY_DIMENSIONS) CCerror(context, "Array with too many dimensions"); this_idata->operand.fi = MAKE_FULLINFO(GET_ITEM_TYPE(target), GET_INDIRECTION(target) + 1, GET_EXTRA_INFO(target)); break; - case opc_new: + case JVM_OPC_new: if (WITH_ZERO_EXTRA_INFO(target) != MAKE_FULLINFO(ITEM_Object, 0, 0)) CCerror(context, "Illegal creation of multi-dimensional array"); @@ -1343,10 +1340,10 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) this_idata->operand.fi = MAKE_FULLINFO(ITEM_NewObject, 0, inumber); this_idata->operand2.fi = target; break; - case opc_multianewarray: + case JVM_OPC_multianewarray: this_idata->operand.fi = target; this_idata->operand2.i = code[offset + 3]; - if ( (this_idata->operand2.i > GET_INDIRECTION(target)) + if ( (this_idata->operand2.i > (int)GET_INDIRECTION(target)) || (this_idata->operand2.i == 0)) CCerror(context, "Illegal dimension argument"); break; @@ -1356,8 +1353,8 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_newarray: { - /* Cache the result of the opc_newarray into the operand slot */ + case JVM_OPC_newarray: { + /* Cache the result of the JVM_OPC_newarray into the operand slot */ fullinfo_type full_info; switch (code[offset + 1]) { case JVM_T_INT: @@ -1376,78 +1373,78 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) full_info = MAKE_FULLINFO(ITEM_Short, 1, 0); break; default: full_info = 0; /* Keep lint happy */ - CCerror(context, "Bad type passed to opc_newarray"); + CCerror(context, "Bad type passed to newarray"); } this_idata->operand.fi = full_info; break; } /* Fudge iload_x, aload_x, etc to look like their generic cousin. */ - case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: - this_idata->opcode = opc_iload; - var = opcode - opc_iload_0; + case JVM_OPC_iload_0: case JVM_OPC_iload_1: case JVM_OPC_iload_2: case JVM_OPC_iload_3: + this_idata->opcode = JVM_OPC_iload; + var = opcode - JVM_OPC_iload_0; goto check_local_variable; - case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: - this_idata->opcode = opc_fload; - var = opcode - opc_fload_0; + case JVM_OPC_fload_0: case JVM_OPC_fload_1: case JVM_OPC_fload_2: case JVM_OPC_fload_3: + this_idata->opcode = JVM_OPC_fload; + var = opcode - JVM_OPC_fload_0; goto check_local_variable; - case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: - this_idata->opcode = opc_aload; - var = opcode - opc_aload_0; + case JVM_OPC_aload_0: case JVM_OPC_aload_1: case JVM_OPC_aload_2: case JVM_OPC_aload_3: + this_idata->opcode = JVM_OPC_aload; + var = opcode - JVM_OPC_aload_0; goto check_local_variable; - case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: - this_idata->opcode = opc_lload; - var = opcode - opc_lload_0; + case JVM_OPC_lload_0: case JVM_OPC_lload_1: case JVM_OPC_lload_2: case JVM_OPC_lload_3: + this_idata->opcode = JVM_OPC_lload; + var = opcode - JVM_OPC_lload_0; goto check_local_variable2; - case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: - this_idata->opcode = opc_dload; - var = opcode - opc_dload_0; + case JVM_OPC_dload_0: case JVM_OPC_dload_1: case JVM_OPC_dload_2: case JVM_OPC_dload_3: + this_idata->opcode = JVM_OPC_dload; + var = opcode - JVM_OPC_dload_0; goto check_local_variable2; - case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: - this_idata->opcode = opc_istore; - var = opcode - opc_istore_0; + case JVM_OPC_istore_0: case JVM_OPC_istore_1: case JVM_OPC_istore_2: case JVM_OPC_istore_3: + this_idata->opcode = JVM_OPC_istore; + var = opcode - JVM_OPC_istore_0; goto check_local_variable; - case opc_fstore_0: case opc_fstore_1: case opc_fstore_2: case opc_fstore_3: - this_idata->opcode = opc_fstore; - var = opcode - opc_fstore_0; + case JVM_OPC_fstore_0: case JVM_OPC_fstore_1: case JVM_OPC_fstore_2: case JVM_OPC_fstore_3: + this_idata->opcode = JVM_OPC_fstore; + var = opcode - JVM_OPC_fstore_0; goto check_local_variable; - case opc_astore_0: case opc_astore_1: case opc_astore_2: case opc_astore_3: - this_idata->opcode = opc_astore; - var = opcode - opc_astore_0; + case JVM_OPC_astore_0: case JVM_OPC_astore_1: case JVM_OPC_astore_2: case JVM_OPC_astore_3: + this_idata->opcode = JVM_OPC_astore; + var = opcode - JVM_OPC_astore_0; goto check_local_variable; - case opc_lstore_0: case opc_lstore_1: case opc_lstore_2: case opc_lstore_3: - this_idata->opcode = opc_lstore; - var = opcode - opc_lstore_0; + case JVM_OPC_lstore_0: case JVM_OPC_lstore_1: case JVM_OPC_lstore_2: case JVM_OPC_lstore_3: + this_idata->opcode = JVM_OPC_lstore; + var = opcode - JVM_OPC_lstore_0; goto check_local_variable2; - case opc_dstore_0: case opc_dstore_1: case opc_dstore_2: case opc_dstore_3: - this_idata->opcode = opc_dstore; - var = opcode - opc_dstore_0; + case JVM_OPC_dstore_0: case JVM_OPC_dstore_1: case JVM_OPC_dstore_2: case JVM_OPC_dstore_3: + this_idata->opcode = JVM_OPC_dstore; + var = opcode - JVM_OPC_dstore_0; goto check_local_variable2; - case opc_wide: + case JVM_OPC_wide: this_idata->opcode = code[offset + 1]; var = (code[offset + 2] << 8) + code[offset + 3]; switch(this_idata->opcode) { - case opc_lload: case opc_dload: - case opc_lstore: case opc_dstore: + case JVM_OPC_lload: case JVM_OPC_dload: + case JVM_OPC_lstore: case JVM_OPC_dstore: goto check_local_variable2; default: goto check_local_variable; } - case opc_iinc: /* the increment amount doesn't matter */ - case opc_ret: - case opc_aload: case opc_iload: case opc_fload: - case opc_astore: case opc_istore: case opc_fstore: + case JVM_OPC_iinc: /* the increment amount doesn't matter */ + case JVM_OPC_ret: + case JVM_OPC_aload: case JVM_OPC_iload: case JVM_OPC_fload: + case JVM_OPC_astore: case JVM_OPC_istore: case JVM_OPC_fstore: var = code[offset + 1]; check_local_variable: /* Make sure that the variable number isn't illegal. */ @@ -1456,7 +1453,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) CCerror(context, "Illegal local variable number"); break; - case opc_lload: case opc_dload: case opc_lstore: case opc_dstore: + case JVM_OPC_lload: case JVM_OPC_dload: case JVM_OPC_lstore: case JVM_OPC_dstore: var = code[offset + 1]; check_local_variable2: /* Make sure that the variable number isn't illegal. */ @@ -1466,7 +1463,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; default: - if (opcode >= opc_breakpoint) + if (opcode > JVM_OPC_MAX) CCerror(context, "Quick instructions shouldn't appear yet."); break; } /* of switch */ @@ -1474,11 +1471,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) static void -set_protected(context_type *context, unsigned int inumber, int key, opcode_type opcode) +set_protected(context_type *context, unsigned int inumber, int key, int opcode) { JNIEnv *env = context->env; fullinfo_type clazz_info; - if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) { clazz_info = cp_index_to_class_fullinfo(context, key, JVM_CONSTANT_Fieldref); } else { @@ -1497,7 +1494,7 @@ set_protected(context_type *context, unsigned int inumber, int key, opcode_type calledClass = (*env)->NewLocalRef(env, calledClass); do { jclass tmp_cb; - if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) { access = JVM_GetCPFieldModifiers (env, context->class, key, calledClass); } else { @@ -1607,9 +1604,10 @@ initialize_exception_table(context_type *context) */ static int instruction_length(unsigned char *iptr, unsigned char *end) { + static unsigned char opcode_length[] = JVM_OPCODE_LENGTH_INITIALIZER; int instruction = *iptr; switch (instruction) { - case opc_tableswitch: { + case JVM_OPC_tableswitch: { int *lpc = (int *)UCALIGN(iptr + 1); int index; if (lpc + 2 >= (int *)end) { @@ -1623,7 +1621,7 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) } } - case opc_lookupswitch: { + case JVM_OPC_lookupswitch: { int *lpc = (int *) UCALIGN(iptr + 1); int npairs; if (lpc + 1 >= (int *)end) @@ -1638,18 +1636,18 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) return (unsigned char *)(&lpc[2 * (npairs + 1)]) - iptr; } - case opc_wide: + case JVM_OPC_wide: if (iptr + 1 >= end) return -1; /* do not read pass the end */ switch(iptr[1]) { - case opc_ret: - case opc_iload: case opc_istore: - case opc_fload: case opc_fstore: - case opc_aload: case opc_astore: - case opc_lload: case opc_lstore: - case opc_dload: case opc_dstore: + case JVM_OPC_ret: + case JVM_OPC_iload: case JVM_OPC_istore: + case JVM_OPC_fload: case JVM_OPC_fstore: + case JVM_OPC_aload: case JVM_OPC_astore: + case JVM_OPC_lload: case JVM_OPC_lstore: + case JVM_OPC_dload: case JVM_OPC_dstore: return 4; - case opc_iinc: + case JVM_OPC_iinc: return 6; default: return -1; @@ -1767,7 +1765,7 @@ run_dataflow(context_type *context) { jclass cb = context->class; int max_stack_size = JVM_GetMethodIxMaxStack(env, cb, mi); instruction_data_type *idata = context->instruction_data; - int icount = context->instruction_count; + unsigned int icount = context->instruction_count; jboolean work_to_do = JNI_TRUE; unsigned int inumber; @@ -1839,7 +1837,7 @@ check_register_values(context_type *context, unsigned int inumber) { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int register_count = this_idata->register_info.register_count; fullinfo_type *registers = this_idata->register_info.registers; @@ -1849,17 +1847,17 @@ check_register_values(context_type *context, unsigned int inumber) switch (opcode) { default: return; - case opc_iload: case opc_iinc: + case JVM_OPC_iload: case JVM_OPC_iinc: type = ITEM_Integer; break; - case opc_fload: + case JVM_OPC_fload: type = ITEM_Float; break; - case opc_aload: + case JVM_OPC_aload: type = ITEM_Object; break; - case opc_ret: + case JVM_OPC_ret: type = ITEM_ReturnAddress; break; - case opc_lload: + case JVM_OPC_lload: type = ITEM_Long; double_word = JNI_TRUE; break; - case opc_dload: + case JVM_OPC_dload: type = ITEM_Double; double_word = JNI_TRUE; break; } if (!double_word) { @@ -1871,7 +1869,7 @@ check_register_values(context_type *context, unsigned int inumber) } reg = registers[operand]; - if (WITH_ZERO_EXTRA_INFO(reg) == MAKE_FULLINFO(type, 0, 0)) { + if (WITH_ZERO_EXTRA_INFO(reg) == (unsigned)MAKE_FULLINFO(type, 0, 0)) { /* the register is obviously of the given type */ return; } else if (GET_INDIRECTION(reg) > 0 && type == ITEM_Object) { @@ -1882,7 +1880,7 @@ check_register_values(context_type *context, unsigned int inumber) operand); /* alternatively (GET_ITEM_TYPE(reg) == ITEM_ReturnAddress) - && (opcode == opc_iload) + && (opcode == JVM_OPC_iload) && (type == ITEM_Object || type == ITEM_Integer) but this never occurs */ @@ -1902,8 +1900,8 @@ check_register_values(context_type *context, unsigned int inumber) "Accessing value from uninitialized register pair %d/%d", operand, operand+1); } else { - if ((registers[operand] == MAKE_FULLINFO(type, 0, 0)) && - (registers[operand + 1] == MAKE_FULLINFO(type + 1, 0, 0))) { + if ((registers[operand] == (unsigned)MAKE_FULLINFO(type, 0, 0)) && + (registers[operand + 1] == (unsigned)MAKE_FULLINFO(type + 1, 0, 0))) { return; } else { CCerror(context, "Register pair %d/%d contains wrong type", @@ -1922,16 +1920,16 @@ check_flags(context_type *context, unsigned int inumber) { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; switch (opcode) { - case opc_return: + case JVM_OPC_return: /* We need a constructor, but we aren't guaranteed it's called */ if ((this_idata->or_flags & FLAG_NEED_CONSTRUCTOR) && !(this_idata->and_flags & FLAG_CONSTRUCTED)) CCerror(context, "Constructor must call super() or this()"); /* fall through */ - case opc_ireturn: case opc_lreturn: - case opc_freturn: case opc_dreturn: case opc_areturn: + case JVM_OPC_ireturn: case JVM_OPC_lreturn: + case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn: if (this_idata->or_flags & FLAG_NO_RETURN) /* This method cannot exit normally */ CCerror(context, "Cannot return normally"); @@ -1950,7 +1948,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; stack_item_type *stack = this_idata->stack_info.stack; int stack_size = this_idata->stack_info.stack_size; char *stack_operands, *p; @@ -1958,7 +1956,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac fullinfo_type stack_extra_info_buffer[256]; /* save info popped off stack */ fullinfo_type *stack_extra_info = &stack_extra_info_buffer[256]; fullinfo_type full_info; /* only used in case of invoke instructions */ - fullinfo_type put_full_info; /* only used in case opc_putstatic and opc_putfield */ + fullinfo_type put_full_info; /* only used in case JVM_OPC_putstatic and JVM_OPC_putfield */ switch(opcode) { default: @@ -1966,7 +1964,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac stack_operands = opcode_in_out[opcode][0]; break; - case opc_putstatic: case opc_putfield: { + case JVM_OPC_putstatic: case JVM_OPC_putfield: { /* The top thing on the stack depends on the signature of * the object. */ int operand = this_idata->operand.i; @@ -1981,7 +1979,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac print_formatted_fieldname(context, operand); } #endif - if (opcode == opc_putfield) + if (opcode == JVM_OPC_putfield) *ip++ = 'A'; /* object for putfield */ *ip++ = signature_to_fieldtype(context, &signature, &put_full_info); *ip = '\0'; @@ -1990,9 +1988,9 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: /* invokespecial call to */ - case opc_invokestatic: case opc_invokeinterface: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: /* invokespecial call to */ + case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* The top stuff on the stack depends on the method signature */ int operand = this_idata->operand.i; const char *signature = @@ -2007,9 +2005,9 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac print_formatted_methodname(context, operand); } #endif - if (opcode != opc_invokestatic) + if (opcode != JVM_OPC_invokestatic) /* First, push the object */ - *ip++ = (opcode == opc_invokeinit ? '@' : 'A'); + *ip++ = (opcode == JVM_OPC_invokeinit ? '@' : 'A'); for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) { *ip++ = signature_to_fieldtype(context, &p, &full_info); if (ip >= buffer + sizeof(buffer) - 1) @@ -2022,7 +2020,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_multianewarray: { + case JVM_OPC_multianewarray: { /* Count can't be larger than 255. So can't overflow buffer */ int count = this_idata->operand2.i; /* number of ints on stack */ memset(buffer, 'I', count); @@ -2062,19 +2060,19 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac * one of the special cases */ if ( (WITH_ZERO_EXTRA_INFO(top_type) == MAKE_FULLINFO(ITEM_ReturnAddress, 0, 0)) - && (opcode == opc_astore)) + && (opcode == JVM_OPC_astore)) break; if ( (GET_ITEM_TYPE(top_type) == ITEM_NewObject || (GET_ITEM_TYPE(top_type) == ITEM_InitObject)) - && ((opcode == opc_astore) || (opcode == opc_aload) - || (opcode == opc_ifnull) || (opcode == opc_ifnonnull))) + && ((opcode == JVM_OPC_astore) || (opcode == JVM_OPC_aload) + || (opcode == JVM_OPC_ifnull) || (opcode == JVM_OPC_ifnonnull))) break; /* The 2nd edition VM of the specification allows field * initializations before the superclass initializer, * if the field is defined within the current class. */ if ( (GET_ITEM_TYPE(top_type) == ITEM_InitObject) - && (opcode == opc_putfield)) { + && (opcode == JVM_OPC_putfield)) { int operand = this_idata->operand.i; int access_bits = JVM_GetCPFieldModifiers(context->env, context->class, @@ -2231,7 +2229,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac */ switch (opcode) { default: break; - case opc_aastore: { /* array index object */ + case JVM_OPC_aastore: { /* array index object */ fullinfo_type array_type = stack_extra_info[0]; fullinfo_type object_type = stack_extra_info[2]; fullinfo_type target_type = decrement_indirection(array_type); @@ -2246,12 +2244,12 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_putfield: - case opc_getfield: - case opc_putstatic: { + case JVM_OPC_putfield: + case JVM_OPC_getfield: + case JVM_OPC_putstatic: { int operand = this_idata->operand.i; fullinfo_type stack_object = stack_extra_info[0]; - if (opcode == opc_putfield || opcode == opc_getfield) { + if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_getfield) { if (!isAssignableTo (context, stack_object, @@ -2266,8 +2264,8 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac CCerror(context, "Bad access to protected data"); } } - if (opcode == opc_putfield || opcode == opc_putstatic) { - int item = (opcode == opc_putfield ? 1 : 0); + if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_putstatic) { + int item = (opcode == JVM_OPC_putfield ? 1 : 0); if (!isAssignableTo(context, stack_extra_info[item], put_full_info)) { CCerror(context, "Bad type in putfield/putstatic"); @@ -2276,23 +2274,23 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_athrow: + case JVM_OPC_athrow: if (!isAssignableTo(context, stack_extra_info[0], context->throwable_info)) { CCerror(context, "Can only throw Throwable objects"); } break; - case opc_aaload: { /* array index */ + case JVM_OPC_aaload: { /* array index */ /* We need to pass the information to the stack updater */ fullinfo_type array_type = stack_extra_info[0]; context->swap_table[0] = decrement_indirection(array_type); break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: - case opc_invokeinterface: case opc_invokestatic: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: + case JVM_OPC_invokeinterface: case JVM_OPC_invokestatic: { int operand = this_idata->operand.i; const char *signature = JVM_GetCPMethodSignatureUTF(context->env, @@ -2301,15 +2299,15 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac int item; const char *p; check_and_push(context, signature, VM_STRING_UTF); - if (opcode == opc_invokestatic) { + if (opcode == JVM_OPC_invokestatic) { item = 0; - } else if (opcode == opc_invokeinit) { + } else if (opcode == JVM_OPC_invokeinit) { fullinfo_type init_type = this_idata->operand2.fi; fullinfo_type object_type = stack_extra_info[0]; context->swap_table[0] = object_type; /* save value */ if (GET_ITEM_TYPE(stack_extra_info[0]) == ITEM_NewObject) { /* We better be calling the appropriate init. Find the - * inumber of the "opc_new" instruction", and figure + * inumber of the "JVM_OPC_new" instruction", and figure * out what the type really is. */ unsigned int new_inumber = GET_EXTRA_INFO(stack_extra_info[0]); @@ -2341,7 +2339,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac CCerror(context, "Incompatible object argument for function call"); } - if (opcode == opc_invokespecial + if (opcode == JVM_OPC_invokespecial && !isAssignableTo(context, object_type, context->currentclass_info)) { /* Make sure object argument is assignment compatible to current class */ @@ -2381,13 +2379,13 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_return: + case JVM_OPC_return: if (context->return_type != MAKE_FULLINFO(ITEM_Void, 0, 0)) CCerror(context, "Wrong return type in function"); break; - case opc_ireturn: case opc_lreturn: case opc_freturn: - case opc_dreturn: case opc_areturn: { + case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_freturn: + case JVM_OPC_dreturn: case JVM_OPC_areturn: { fullinfo_type target_type = context->return_type; fullinfo_type object_type = stack_extra_info[0]; if (!isAssignableTo(context, object_type, target_type)) { @@ -2396,7 +2394,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_new: { + case JVM_OPC_new: { /* Make sure that nothing on the stack already looks like what * we want to create. I can't image how this could possibly happen * but we should test for it anyway, since if it could happen, the @@ -2433,7 +2431,7 @@ update_registers(context_type *context, unsigned int inumber, { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int register_count = this_idata->register_info.register_count; fullinfo_type *registers = this_idata->register_info.registers; @@ -2453,11 +2451,11 @@ update_registers(context_type *context, unsigned int inumber, /* Remember, we've already verified the type at the top of the stack. */ switch (opcode) { default: break; - case opc_istore: case opc_fstore: case opc_astore: + case JVM_OPC_istore: case JVM_OPC_fstore: case JVM_OPC_astore: access = ACCESS_SINGLE; goto continue_store; - case opc_lstore: case opc_dstore: + case JVM_OPC_lstore: case JVM_OPC_dstore: access = ACCESS_DOUBLE; goto continue_store; @@ -2484,16 +2482,16 @@ update_registers(context_type *context, unsigned int inumber, break; } - case opc_iload: case opc_fload: case opc_aload: - case opc_iinc: case opc_ret: + case JVM_OPC_iload: case JVM_OPC_fload: case JVM_OPC_aload: + case JVM_OPC_iinc: case JVM_OPC_ret: access = ACCESS_SINGLE; break; - case opc_lload: case opc_dload: + case JVM_OPC_lload: case JVM_OPC_dload: access = ACCESS_DOUBLE; break; - case opc_jsr: case opc_jsr_w: + case JVM_OPC_jsr: case JVM_OPC_jsr_w: for (i = 0; i < new_mask_count; i++) if (new_masks[i].entry == operand) CCerror(context, "Recursive call to jsr entry"); @@ -2501,8 +2499,8 @@ update_registers(context_type *context, unsigned int inumber, new_mask_count++; break; - case opc_invokeinit: - case opc_new: { + case JVM_OPC_invokeinit: + case JVM_OPC_new: { /* For invokeinit, an uninitialized object has been initialized. * For new, all previous occurrences of an uninitialized object * from the same instruction must be made bogus. @@ -2588,7 +2586,7 @@ update_flags(context_type *context, unsigned int inumber, flag_type or_flags = this_idata->or_flags; /* Set the "we've done a constructor" flag */ - if (this_idata->opcode == opc_invokeinit) { + if (this_idata->opcode == JVM_OPC_invokeinit) { fullinfo_type from = context->swap_table[0]; if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0)) and_flags |= FLAG_CONSTRUCTED; @@ -2611,7 +2609,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int stack_size = new_stack_info->stack_size; @@ -2631,7 +2629,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta stack_results = opcode_in_out[opcode][1]; break; - case opc_ldc: case opc_ldc_w: case opc_ldc2_w: { + case JVM_OPC_ldc: case JVM_OPC_ldc_w: case JVM_OPC_ldc2_w: { /* Look to constant pool to determine correct result. */ unsigned char *type_table = context->constant_types; switch (type_table[operand]) { @@ -2661,7 +2659,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_getstatic: case opc_getfield: { + case JVM_OPC_getstatic: case JVM_OPC_getfield: { /* Look to signature to determine correct result. */ int operand = this_idata->operand.i; const char *signature = JVM_GetCPFieldSignatureUTF(context->env, @@ -2680,9 +2678,9 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: - case opc_invokestatic: case opc_invokeinterface: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: + case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* Look to signature to determine correct result. */ int operand = this_idata->operand.i; const char *signature = JVM_GetCPMethodSignatureUTF(context->env, @@ -2703,28 +2701,28 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_aconst_null: + case JVM_OPC_aconst_null: stack_results = opcode_in_out[opcode][1]; full_info = NULL_FULLINFO; /* special NULL */ break; - case opc_new: - case opc_checkcast: - case opc_newarray: - case opc_anewarray: - case opc_multianewarray: + case JVM_OPC_new: + case JVM_OPC_checkcast: + case JVM_OPC_newarray: + case JVM_OPC_anewarray: + case JVM_OPC_multianewarray: stack_results = opcode_in_out[opcode][1]; /* Conveniently, this result type is stored here */ full_info = this_idata->operand.fi; break; - case opc_aaload: + case JVM_OPC_aaload: stack_results = opcode_in_out[opcode][1]; /* pop_stack() saved value for us. */ full_info = context->swap_table[0]; break; - case opc_aload: + case JVM_OPC_aload: stack_results = opcode_in_out[opcode][1]; /* The register hasn't been modified, so we can use its value. */ full_info = this_idata->register_info.registers[operand]; @@ -2772,7 +2770,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta stack_size++; } /* outer for loop */ - if (opcode == opc_invokeinit) { + if (opcode == JVM_OPC_invokeinit) { /* If there are any instances of "from" on the stack, we need to * replace it with "to", since calling initializes all versions * of the object, obviously. */ @@ -2807,7 +2805,7 @@ merge_into_successors(context_type *context, unsigned int inumber, { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; struct handler_info_type *handler_info = context->handler_info; int handler_info_length = @@ -2827,35 +2825,35 @@ merge_into_successors(context_type *context, unsigned int inumber, buffer[0] = inumber + 1; break; - case opc_ifeq: case opc_ifne: case opc_ifgt: - case opc_ifge: case opc_iflt: case opc_ifle: - case opc_ifnull: case opc_ifnonnull: - case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: - case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: - case opc_if_acmpeq: case opc_if_acmpne: + case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_ifgt: + case JVM_OPC_ifge: case JVM_OPC_iflt: case JVM_OPC_ifle: + case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: + case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmpgt: + case JVM_OPC_if_icmpge: case JVM_OPC_if_icmplt: case JVM_OPC_if_icmple: + case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: successors_count = 2; buffer[0] = inumber + 1; buffer[1] = operand; break; - case opc_jsr: case opc_jsr_w: + case JVM_OPC_jsr: case JVM_OPC_jsr_w: if (this_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) idata[this_idata->operand2.i].changed = JNI_TRUE; /* FALLTHROUGH */ - case opc_goto: case opc_goto_w: + case JVM_OPC_goto: case JVM_OPC_goto_w: successors_count = 1; buffer[0] = operand; break; - case opc_ireturn: case opc_lreturn: case opc_return: - case opc_freturn: case opc_dreturn: case opc_areturn: - case opc_athrow: + case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_return: + case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn: + case JVM_OPC_athrow: /* The testing for the returns is handled in pop_stack() */ successors_count = 0; break; - case opc_ret: { + case JVM_OPC_ret: { /* This is slightly slow, but good enough for a seldom used instruction. * The EXTRA_ITEM_INFO of the ITEM_ReturnAddress indicates the * address of the first instruction of the subroutine. We can return @@ -2866,16 +2864,16 @@ merge_into_successors(context_type *context, unsigned int inumber, int called_instruction = GET_EXTRA_INFO(registers[operand]); int i, count, *ptr;; for (i = context->instruction_count, count = 0; --i >= 0; ) { - if (((idata[i].opcode == opc_jsr) || - (idata[i].opcode == opc_jsr_w)) && + if (((idata[i].opcode == JVM_OPC_jsr) || + (idata[i].opcode == JVM_OPC_jsr_w)) && (idata[i].operand.i == called_instruction)) count++; } this_idata->operand2.ip = ptr = NEW(int, count + 1); *ptr++ = count; for (i = context->instruction_count, count = 0; --i >= 0; ) { - if (((idata[i].opcode == opc_jsr) || - (idata[i].opcode == opc_jsr_w)) && + if (((idata[i].opcode == JVM_OPC_jsr) || + (idata[i].opcode == JVM_OPC_jsr_w)) && (idata[i].operand.i == called_instruction)) *ptr++ = i + 1; } @@ -2886,8 +2884,8 @@ merge_into_successors(context_type *context, unsigned int inumber, } - case opc_tableswitch: - case opc_lookupswitch: + case JVM_OPC_tableswitch: + case JVM_OPC_lookupswitch: successors = this_idata->operand.ip; /* use this instead */ successors_count = *successors++; break; @@ -2907,9 +2905,9 @@ merge_into_successors(context_type *context, unsigned int inumber, handler_info = context->handler_info; for (i = handler_info_length; --i >= 0; handler_info++) { - if (handler_info->start <= inumber && handler_info->end > inumber) { + if (handler_info->start <= (int)inumber && handler_info->end > (int)inumber) { int handler = handler_info->handler; - if (opcode != opc_invokeinit) { + if (opcode != JVM_OPC_invokeinit) { merge_into_one_successor(context, inumber, handler, &this_idata->register_info, /* old */ &handler_info->stack_info, @@ -2984,9 +2982,9 @@ merge_into_one_successor(context_type *context, * ret are executed. Thus uninitialized objects can't propagate * into or out of a subroutine. */ - if (idata[from_inumber].opcode == opc_ret || - idata[from_inumber].opcode == opc_jsr || - idata[from_inumber].opcode == opc_jsr_w) { + if (idata[from_inumber].opcode == JVM_OPC_ret || + idata[from_inumber].opcode == JVM_OPC_jsr || + idata[from_inumber].opcode == JVM_OPC_jsr_w) { int new_register_count = new_register_info->register_count; fullinfo_type *new_registers = new_register_info->registers; int i; @@ -3036,7 +3034,7 @@ merge_into_one_successor(context_type *context, * that needs to get merged into the new instruction is a joining * of info from the ret instruction with stuff in the jsr instruction */ - if (idata[from_inumber].opcode == opc_ret && !isException) { + if (idata[from_inumber].opcode == JVM_OPC_ret && !isException) { int new_register_count = new_register_info->register_count; fullinfo_type *new_registers = new_register_info->registers; int new_mask_count = new_register_info->mask_count; @@ -3045,7 +3043,7 @@ merge_into_one_successor(context_type *context, int called_instruction = GET_EXTRA_INFO(new_registers[operand]); instruction_data_type *jsr_idata = &idata[to_inumber - 1]; register_info_type *jsr_reginfo = &jsr_idata->register_info; - if (jsr_idata->operand2.i != from_inumber) { + if (jsr_idata->operand2.i != (int)from_inumber) { if (jsr_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) CCerror(context, "Multiple returns to single jsr"); jsr_idata->operand2.i = from_inumber; @@ -3675,7 +3673,7 @@ signature_to_fieldtype(context_type *context, char *buffer = buffer_space; char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS); int length = finish - p; - if (length + 1 > sizeof(buffer_space)) { + if (length + 1 > (int)sizeof(buffer_space)) { buffer = malloc(length + 1); check_and_push(context, buffer, VM_MALLOC_BLK); } diff --git a/src/share/native/common/check_format.c b/src/share/native/common/check_format.c index 26539d133feb6dd3c04581dc214c87e5819b1da5..0b5f42077db3255d79809ed679ec414212604476 100644 --- a/src/share/native/common/check_format.c +++ b/src/share/native/common/check_format.c @@ -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 @@ -246,7 +246,7 @@ VerifyClassname(char *name, jboolean allowArrayClass) /* skip over the fieldname. Slashes are okay */ p = skip_over_fieldname(name, JNI_TRUE, length); } - return (p != 0 && p - name == length); + return (p != 0 && p - name == (ptrdiff_t)length); } /* diff --git a/src/share/native/java/net/net_util.c b/src/share/native/java/net/net_util.c index 2559a0edb8c291c8d06b90f48b52d0ac6b9d418b..5634e736a341f26790d72c021a444b180ec5b028 100644 --- a/src/share/native/java/net/net_util.c +++ b/src/share/native/java/net/net_util.c @@ -82,7 +82,7 @@ void init(JNIEnv *env) { } } -jobject +JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; init(env); @@ -159,7 +159,7 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 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 --git a/src/share/native/java/net/net_util.h b/src/share/native/java/net/net_util.h index d00a1c0be8130ee62304e5aee93f81cd98c6d5b8..9033d66fac458c33ef6a13b73e56031eb11ae335 100644 --- a/src/share/native/java/net/net_util.h +++ b/src/share/native/java/net/net_util.h @@ -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 @@ -116,7 +116,7 @@ NET_AllocSockaddr(struct sockaddr **him, int *len); 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 initLocalAddrTable (); 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 --git a/src/share/native/java/nio/Bits.c b/src/share/native/java/nio/Bits.c index 0227d6de86b91a5599d7237f8c22b9f2b78ec32e..448a0581c89d090384205efe53ae3bcc0318a1ed 100644 --- a/src/share/native/java/nio/Bits.c +++ b/src/share/native/java/nio/Bits.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2003 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 @@ -67,46 +67,6 @@ #define SWAPLONG(x) ((jlong)(((jlong)SWAPINT((jint)(x)) << 32) | \ ((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 --git a/src/share/native/java/util/zip/zip_util.c b/src/share/native/java/util/zip/zip_util.c index 1f6e04a1f7ed36e1c7b961c67291eeba9a9bc888..5d518cf4ced4f75620e790df2da6f72216ae86fb 100644 --- a/src/share/native/java/util/zip/zip_util.c +++ b/src/share/native/java/util/zip/zip_util.c @@ -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 @@ -722,16 +722,22 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) } len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END); - if (len == -1) { - if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) - *pmsg = errbuf; + if (len <= 0) { + if (len == 0) { /* zip file is empty */ + if (pmsg) { + *pmsg = "zip file is empty"; + } + } else { /* error */ + if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) + *pmsg = errbuf; + } ZFILE_Close(zfd); freeZip(zip); return NULL; } zip->zfd = zfd; - if (readCEN(zip, -1) <= 0) { + if (readCEN(zip, -1) < 0) { /* An error occurred while trying to read the zip file */ if (pmsg != 0) { /* Set the zip error message */ @@ -947,10 +953,15 @@ jzentry * ZIP_GetEntry(jzfile *zip, char *name, jint ulen) { unsigned int hsh = hash(name); - jint idx = zip->table[hsh % zip->tablelen]; - jzentry *ze; + jint idx; + jzentry *ze = 0; ZIP_Lock(zip); + if (zip->total == 0) { + goto Finally; + } + + idx = zip->table[hsh % zip->tablelen]; /* * This while loop is an optimization where a double lookup @@ -1025,6 +1036,7 @@ ZIP_GetEntry(jzfile *zip, char *name, jint ulen) ulen = 0; } +Finally: ZIP_Unlock(zip); return ze; } diff --git a/src/share/native/sun/nio/ch/genSocketOptionRegistry.c b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c new file mode 100644 index 0000000000000000000000000000000000000000..70f95c6c59b231673eb895f6478555470fd30fda --- /dev/null +++ b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c @@ -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. + */ + +#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 --git a/src/share/sample/nio/multicast/MulticastAddress.java b/src/share/sample/nio/multicast/MulticastAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..e1a3bf3eb90eec98e654ec5a5223b834f27e0908 --- /dev/null +++ b/src/share/sample/nio/multicast/MulticastAddress.java @@ -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 --git a/src/share/sample/nio/multicast/Reader.java b/src/share/sample/nio/multicast/Reader.java new file mode 100644 index 0000000000000000000000000000000000000000..0d1bd8672efd79027847df018e9e5309d23038d8 --- /dev/null +++ b/src/share/sample/nio/multicast/Reader.java @@ -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 --git a/src/share/sample/nio/multicast/Sender.java b/src/share/sample/nio/multicast/Sender.java new file mode 100644 index 0000000000000000000000000000000000000000..d72a24d5aa568e4e6474cfbb73895e7d3dfeb3aa --- /dev/null +++ b/src/share/sample/nio/multicast/Sender.java @@ -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 --git a/src/share/transport/shmem/shmemBack.c b/src/share/transport/shmem/shmemBack.c index 629325be0ebe4fd503321703890beb3c794055a1..e63c2bd6a6f44be1dba064049bebd630ab85fc33 100644 --- a/src/share/transport/shmem/shmemBack.c +++ b/src/share/transport/shmem/shmemBack.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2003 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 diff --git a/src/share/transport/shmem/shmemBase.c b/src/share/transport/shmem/shmemBase.c index 461baf647bfc0b81a9f7a2fdb58a19753dbb87a0..f0ee7f0530dae6c7136da257d18e2142fb12ca39 100644 --- a/src/share/transport/shmem/shmemBase.c +++ b/src/share/transport/shmem/shmemBase.c @@ -1,5 +1,5 @@ /* - * Copyright 1999-2003 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 diff --git a/src/share/transport/socket/socketTransport.c b/src/share/transport/socket/socketTransport.c index 705b7ef918c4b90af0891ff3e23eccb29bc0d0e5..f960fae2d39a726aaf2494410380e47511a98e81 100644 --- a/src/share/transport/socket/socketTransport.c +++ b/src/share/transport/socket/socketTransport.c @@ -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 diff --git a/src/share/transport/socket/sysSocket.h b/src/share/transport/socket/sysSocket.h index fc7ecb6b86e006126ce567ea97ee0480d815d98a..8931e8a4bd0a0f3e74aa0e63868551a8d6a77b43 100644 --- a/src/share/transport/socket/sysSocket.h +++ b/src/share/transport/socket/sysSocket.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/solaris/back/util_md.h b/src/solaris/back/util_md.h index 52f7d18aaa57a08840f69d97f24530579c403749..10853f4e65a2bf7cc3a23f8db08c776ef4a83d32 100644 --- a/src/solaris/back/util_md.h +++ b/src/solaris/back/util_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 @@ -26,6 +26,9 @@ #ifndef JDWP_UTIL_MD_H #define JDWP_UTIL_MD_H +#include +#include /* To get uintptr_t */ + #include #include diff --git a/src/solaris/bin/java_md.c b/src/solaris/bin/java_md.c index c7c0da6d793b97e8cab93dee44c51c005f9c2750..6ecd9681c8f04c041e052792d8c07f902f695bda 100644 --- a/src/solaris/bin/java_md.c +++ b/src/solaris/bin/java_md.c @@ -289,13 +289,13 @@ CreateExecutionEnvironment(int *_argcp, 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 @@ CreateExecutionEnvironment(int *_argcp, 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 @@ CreateExecutionEnvironment(int *_argcp, 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 @@ CreateExecutionEnvironment(int *_argcp, break; default: - ReportErrorMessage(JRE_ERROR3, __LINE__); + JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); exit(1); /* unknown value in wanted */ break; } @@ -553,17 +553,17 @@ CreateExecutionEnvironment(int *_argcp, (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 @@ GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative) } if (!speculative) - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -680,13 +680,13 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) 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 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) return JNI_TRUE; error: - ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } @@ -848,7 +848,7 @@ SetExecname(char **argv) 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 @@ SetExecname(char **argv) 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 @@ void ReportErrorMessage(const char* fmt, ...) { va_end(vl); } -void ReportErrorMessageSys(const char* fmt, ...) { +void JLI_ReportErrorMessageSys(const char* fmt, ...) { va_list vl; char *emsg; @@ -912,7 +912,7 @@ void ReportErrorMessageSys(const char* fmt, ...) { va_end(vl); } -void ReportExceptionDescription(JNIEnv * env) { +void JLI_ReportExceptionDescription(JNIEnv * env) { (*env)->ExceptionDescribe(env); } @@ -1078,7 +1078,7 @@ ExecJRE(char *jre, char **argv) * 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 @@ ExecJRE(char *jre, char **argv) */ SetExecname(argv); if (execname == NULL) { - ReportErrorMessage(JRE_ERROR10); + JLI_ReportErrorMessage(JRE_ERROR10); exit(1); } @@ -1106,7 +1106,7 @@ ExecJRE(char *jre, char **argv) * 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 @@ ExecJRE(char *jre, char **argv) (void)fflush(stdout); (void)fflush(stderr); execv(wanted, argv); - ReportErrorMessageSys(JRE_ERROR12, wanted); + JLI_ReportErrorMessageSys(JRE_ERROR12, wanted); exit(1); } diff --git a/src/solaris/classes/sun/awt/X11/XKeysym.java b/src/solaris/classes/sun/awt/X11/XKeysym.java index 77e7ba98e22360f6d3134ff5b3d55730496f349b..4dae66c0183095d1e96d2ee7d8f62b19565cbde4 100644 --- a/src/solaris/classes/sun/awt/X11/XKeysym.java +++ b/src/solaris/classes/sun/awt/X11/XKeysym.java @@ -101,10 +101,15 @@ public class XKeysym { // 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 --git a/src/solaris/classes/sun/awt/X11/XNETProtocol.java b/src/solaris/classes/sun/awt/X11/XNETProtocol.java index ccc1b1242049bd1d1785750ddec877d4e26ff6ba..68145a74f79a8f5d2118b19e0ad69cc192e0d796 100644 --- a/src/solaris/classes/sun/awt/X11/XNETProtocol.java +++ b/src/solaris/classes/sun/awt/X11/XNETProtocol.java @@ -189,6 +189,8 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt 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 --git a/src/solaris/classes/sun/awt/X11/XToolkit.java b/src/solaris/classes/sun/awt/X11/XToolkit.java index 871f99368b603ba6700bf93673c901f9b222b902..9349ee8d1c93440134927c6974edec6d199c28f9 100644 --- a/src/solaris/classes/sun/awt/X11/XToolkit.java +++ b/src/solaris/classes/sun/awt/X11/XToolkit.java @@ -97,6 +97,11 @@ public final class XToolkit extends UNIXToolkit implements Runnable { 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 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } } + @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 --git a/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/src/solaris/classes/sun/awt/X11/XWindowPeer.java index 17d76b0de24b8e2c5e3aaf06843fcc6392753611..77b39c13d9013980bb782e57d1ee3b28fc463594 100644 --- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -129,6 +129,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, 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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, boolean isOverrideRedirect() { return (XWM.getWMID() == XWM.OPENLOOK_WM ? true : false) || + ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target) || XTrayIconPeer.isTrayIconStuffWindow((Window)target); } diff --git a/src/solaris/classes/sun/awt/X11/keysym2ucs.h b/src/solaris/classes/sun/awt/X11/keysym2ucs.h index c7a4b0d72c7765721aff86bcd6b2dd57e49c5c84..c5750d8d101b996d2da0f6ded7a177d2d3ce0aa0 100644 --- a/src/solaris/classes/sun/awt/X11/keysym2ucs.h +++ b/src/solaris/classes/sun/awt/X11/keysym2ucs.h @@ -139,10 +139,15 @@ tojava // Xsun without XKB uses keysymarray[2] keysym to determine if it 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 --git a/src/solaris/classes/sun/awt/motif/MButtonPeer.java b/src/solaris/classes/sun/awt/motif/MButtonPeer.java deleted file mode 100644 index 0fbb4420ebf6199464858bcbda4ea2ce13772cef..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MButtonPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MCanvasPeer.java b/src/solaris/classes/sun/awt/motif/MCanvasPeer.java deleted file mode 100644 index c7063ac6a185e92d46eead5aa6a8053c88eff771..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MCanvasPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MCheckboxMenuItemPeer.java b/src/solaris/classes/sun/awt/motif/MCheckboxMenuItemPeer.java deleted file mode 100644 index 6acc0bfd6a4ff124d411759b18460e5ddb785848..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MCheckboxMenuItemPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MCheckboxPeer.java b/src/solaris/classes/sun/awt/motif/MCheckboxPeer.java deleted file mode 100644 index c2e4ac21e8f12b30bebc5d9cb93e2c0bca136bb4..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MCheckboxPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MChoicePeer.java b/src/solaris/classes/sun/awt/motif/MChoicePeer.java deleted file mode 100644 index 1a6b32d8b6300a30b34a34725337ee1ba0650ccd..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MChoicePeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MComponentPeer.java b/src/solaris/classes/sun/awt/motif/MComponentPeer.java deleted file mode 100644 index 87f556c93d14ab17e210ad659393782e2d5d2c38..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MComponentPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MCustomCursor.java b/src/solaris/classes/sun/awt/motif/MCustomCursor.java deleted file mode 100644 index 075ea36289b6010802524c7d42e7b2536f7f98cc..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MCustomCursor.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MDataTransferer.java b/src/solaris/classes/sun/awt/motif/MDataTransferer.java deleted file mode 100644 index 805410aa527f35f06e489cb5eefbec1a13723384..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MDataTransferer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MDialogPeer.java b/src/solaris/classes/sun/awt/motif/MDialogPeer.java deleted file mode 100644 index b5ec721211fa5ea0290fc8037efed59d187e128e..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MDialogPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MDragSourceContextPeer.java b/src/solaris/classes/sun/awt/motif/MDragSourceContextPeer.java deleted file mode 100644 index 040c93e3b3d4573f5efe3c16111e1ee237959507..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MDragSourceContextPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MDropTargetContextPeer.java b/src/solaris/classes/sun/awt/motif/MDropTargetContextPeer.java deleted file mode 100644 index 5994cd1b83990bf535e0b53f02d84a8212792c15..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MDropTargetContextPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java b/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java deleted file mode 100644 index 0e189bfeb3178766aadc8b847a2d10cc6bb8559b..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MEmbedCanvasPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MEmbeddedFrame.java b/src/solaris/classes/sun/awt/motif/MEmbeddedFrame.java deleted file mode 100644 index 762508187bc8e57954df71a3ed6a3113768ea650..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MEmbeddedFrame.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java b/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java deleted file mode 100644 index d3e7a78c656cf0936c7819de2b7c9c1a5ac5a569..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MFileDialogPeer.java b/src/solaris/classes/sun/awt/motif/MFileDialogPeer.java deleted file mode 100644 index e51aaa71b50d57690d6613ab6258e20ec2cdb1fc..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MFileDialogPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MFramePeer.java b/src/solaris/classes/sun/awt/motif/MFramePeer.java deleted file mode 100644 index afdb49a15dfbe19d5e69707502ae7b0e68bd8216..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MFramePeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MGlobalCursorManager.java b/src/solaris/classes/sun/awt/motif/MGlobalCursorManager.java deleted file mode 100644 index dfa8452995df801dd9230132ab1b64d0ce15df47..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MGlobalCursorManager.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MInputMethod.java b/src/solaris/classes/sun/awt/motif/MInputMethod.java deleted file mode 100644 index 3c2a5f1536825f247cca129fbf8ccd4e12b8d0d1..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MInputMethod.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MInputMethodControl.java b/src/solaris/classes/sun/awt/motif/MInputMethodControl.java deleted file mode 100644 index 6dc89897ea566f2de60d4ac3b091cd7866a651c8..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MInputMethodControl.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MLabelPeer.java b/src/solaris/classes/sun/awt/motif/MLabelPeer.java deleted file mode 100644 index 16cfc4ef972b5c1d5bdeadde98202feddde7ec18..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MLabelPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MListPeer.java b/src/solaris/classes/sun/awt/motif/MListPeer.java deleted file mode 100644 index 664425337240182c3394e41b4978693eeeb7cc7a..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MListPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MMenuBarPeer.java b/src/solaris/classes/sun/awt/motif/MMenuBarPeer.java deleted file mode 100644 index de88ea0e8f40b91e97e79e9793393d6cd62685fc..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MMenuBarPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MMenuItemPeer.java b/src/solaris/classes/sun/awt/motif/MMenuItemPeer.java deleted file mode 100644 index cb08c6b448517c7aee95f6006c7c219f9341aae4..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MMenuItemPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MMenuPeer.java b/src/solaris/classes/sun/awt/motif/MMenuPeer.java deleted file mode 100644 index 4a378e7468595190277c52fe318cc85b4a94e1fa..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MMenuPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MMouseDragGestureRecognizer.java b/src/solaris/classes/sun/awt/motif/MMouseDragGestureRecognizer.java deleted file mode 100644 index 460e189e5d46a39b322b2a422e01acfb8538e4e1..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MMouseDragGestureRecognizer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MPanelPeer.java b/src/solaris/classes/sun/awt/motif/MPanelPeer.java deleted file mode 100644 index 9a1833ecd9aa0f07ece006c9d1cf4e0d4dc05cae..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MPanelPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MPopupMenuPeer.java b/src/solaris/classes/sun/awt/motif/MPopupMenuPeer.java deleted file mode 100644 index cdf8f2093500a7b17c415d242740d4e50ad5a9fd..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MPopupMenuPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MRobotPeer.java b/src/solaris/classes/sun/awt/motif/MRobotPeer.java deleted file mode 100644 index 08c38a942b80380c564b21d152f290a81334f764..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MRobotPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java b/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java deleted file mode 100644 index 2b310efdebc5349e623e8f7a59336a66b59231db..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MScrollbarPeer.java b/src/solaris/classes/sun/awt/motif/MScrollbarPeer.java deleted file mode 100644 index 6aaddfcca620aa6f153b6cd726cdb8973b4b3227..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MScrollbarPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MTextAreaPeer.java b/src/solaris/classes/sun/awt/motif/MTextAreaPeer.java deleted file mode 100644 index dde7e7527539a1b812a2c892bcfbb49b23ccc23a..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MTextAreaPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MTextFieldPeer.java b/src/solaris/classes/sun/awt/motif/MTextFieldPeer.java deleted file mode 100644 index f11f5597c7cd88c3bd0829173b4bfb0cead6ca46..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MTextFieldPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/MToolkit.java b/src/solaris/classes/sun/awt/motif/MToolkit.java index 3a71353c1f7ed0e45d343429b7c95bef5a7308b8..717990da2f7e8067e0ad3bb0fb450e848d1a3880 100644 --- a/src/solaris/classes/sun/awt/motif/MToolkit.java +++ b/src/solaris/classes/sun/awt/motif/MToolkit.java @@ -60,12 +60,12 @@ import java.awt.dnd.MouseDragGestureRecognizer; 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 @@ public class MToolkit extends UNIXToolkit implements Runnable { 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 @@ public class MToolkit extends UNIXToolkit implements Runnable { 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 @@ public class MToolkit extends UNIXToolkit implements Runnable { } 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 class MToolkit extends UNIXToolkit implements Runnable { */ 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 class MToolkit extends UNIXToolkit implements Runnable { 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 class MToolkit extends UNIXToolkit implements Runnable { } 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 @@ public class MToolkit extends UNIXToolkit implements Runnable { 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 @@ public class MToolkit extends UNIXToolkit implements Runnable { * 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 class MToolkit extends UNIXToolkit implements Runnable { */ 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 class MToolkit extends UNIXToolkit implements Runnable { 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 --git a/src/solaris/classes/sun/awt/motif/MWindowPeer.java b/src/solaris/classes/sun/awt/motif/MWindowPeer.java deleted file mode 100644 index a719accdb63db7e68878ca0770fb1eff67d62470..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/MWindowPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/X11Clipboard.java b/src/solaris/classes/sun/awt/motif/X11Clipboard.java deleted file mode 100644 index db9794de8a431931fb5aec1d523b1429d72f5236..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/X11Clipboard.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/X11DragSourceContextPeer.java b/src/solaris/classes/sun/awt/motif/X11DragSourceContextPeer.java deleted file mode 100644 index db4078b8da87c5e929d85e54f51b4766349df1e3..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/X11DragSourceContextPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/X11DropTargetContextPeer.java b/src/solaris/classes/sun/awt/motif/X11DropTargetContextPeer.java deleted file mode 100644 index 48eb9bbed8370100eb0ab99c8542f0211b6178b7..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/X11DropTargetContextPeer.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/awt/motif/X11Selection.java b/src/solaris/classes/sun/awt/motif/X11Selection.java deleted file mode 100644 index 1612009354589e756325d98d16a779160e76347e..0000000000000000000000000000000000000000 --- a/src/solaris/classes/sun/awt/motif/X11Selection.java +++ /dev/null @@ -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 --git a/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java b/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java index 7261443a6cb64eb001f9e0ddf23dcccf0b1e54b5..532b02c23c9461c1dcc0c3c0b3f65b1b925e64db 100644 --- a/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java +++ b/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java @@ -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 diff --git a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java index 4ee5e0617990e0e14d7908d36e8d1a15e6016951..d8542e1b03d69082d9a6580a5533d3bcb8e2f81d 100644 --- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java +++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java @@ -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 @@ -69,11 +69,11 @@ class EPollArrayWrapper { 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 @@ class EPollArrayWrapper { 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 --git a/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java index 341fd4704b36400835caf35a35b93fd5e0908087..b9193435c79495159eb37fc68985bb44a6f3d6be 100644 --- a/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java +++ b/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java @@ -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 diff --git a/src/solaris/instrument/FileSystemSupport_md.h b/src/solaris/instrument/FileSystemSupport_md.h index c092193f192c43fe6b0eb406498485934c1952df..a83e3d16f0a1795299513c95584a5f65a1a218cb 100644 --- a/src/solaris/instrument/FileSystemSupport_md.h +++ b/src/solaris/instrument/FileSystemSupport_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -23,5 +23,8 @@ * have any questions. */ +#include +#include /* For uintprt_t */ #include #include /* For MAXPATHLEN */ + diff --git a/src/solaris/javavm/export/jvm_md.h b/src/solaris/javavm/export/jvm_md.h index 2789492eeb596676249f611598e041e673baf4a5..4c6b8e14ec36d38c8fbdcb723bedf7b82e94f189 100644 --- a/src/solaris/javavm/export/jvm_md.h +++ b/src/solaris/javavm/export/jvm_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-1999 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 @@ -34,6 +34,8 @@ #include /* For DIR */ #include /* For MAXPATHLEN */ #include /* For F_OK, R_OK, W_OK */ +#include /* For ptrdiff_t */ +#include /* For uintptr_t */ #define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"} #define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"} diff --git a/src/solaris/javavm/include/typedefs_md.h b/src/solaris/javavm/include/typedefs_md.h deleted file mode 100644 index 552a7951a7583cb1773f596a4b003f78db111ed4..0000000000000000000000000000000000000000 --- a/src/solaris/javavm/include/typedefs_md.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 1994-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. - */ - -/* - * Solaris-dependent types for Green threads - */ - -#ifndef _JAVASOFT_SOLARIS_TYPES_MD_H_ -#define _JAVASOFT_SOLARIS_TYPES_MD_H_ - -#include -#include - -#ifdef __linux__ -#include -#define HAVE_INTPTR_T -#define _UINT64_T -#endif - -#define int8_t char - -/* Fix for varargs differences on PowerPC */ -#if defined(__powerpc__) -#define VARGS(x) (x) -#else -#define VARGS(x) (&x) -#endif /* __powerpc__ */ - - -#if defined(__alpha__) -#define PTR_IS_64 1 -#define LONG_IS_64 1 -#else -#define PTR_IS_32 1 -#endif - -/* don't redefine typedef's on Solaris 2.6 or Later */ - -#if !defined(_ILP32) && !defined(_LP64) - -#ifndef HAVE_INTPTR_T -#ifdef LONG_IS_64 -typedef long intptr_t; -typedef unsigned long uintptr_t; -#else -typedef int intptr_t; -typedef unsigned int uintptr_t; -#endif /* LONG_IS_64 */ -#endif /* don't HAVE_INTPTR_T */ - -#ifndef _UINT64_T -#define _UINT64_T -#ifdef LONG_IS_64 -typedef unsigned long uint64_t; -#else -typedef unsigned long long uint64_t; -#endif -#define _UINT32_T -#ifndef uint32_t /* [sbb] scaffolding */ -typedef unsigned int uint32_t; -#endif /* [sbb] scaffolding */ -#if defined(__linux__) -typedef unsigned int uint_t; -#endif -#endif - -#ifndef __BIT_TYPES_DEFINED__ -/* that should get Linux, at least */ -#ifndef _INT64_T -#define _INT64_T -#ifdef LONG_IS_64 -typedef long int64_t; -#else -typedef long long int64_t; -#endif -#define _INT32_T -#ifndef int32_t /* [sbb] scaffolding */ -typedef int int32_t; -#endif /* [sbb] scaffolding */ -#if defined(__linux__) -typedef int int_t; -#endif -#endif -#endif /* __BIT_TYPES_DEFINED__ */ - -#endif /* !defined(_ILP32) && !defined(_LP64) */ - -/* use these macros when the compiler supports the long long type */ - -#define ll_high(a) ((uint32_t)(((uint64_t)(a))>>32)) -#define ll_low(a) ((uint32_t)(a)) -#define int2ll(a) ((int64_t)(a)) -#define ll2int(a) ((int)(a)) -#define ll_add(a, b) ((int64_t)(a) + (int64_t)(b)) -#define ll_and(a, b) ((int64_t)(a) & (int64_t)(b)) -#define ll_div(a, b) ((int64_t)(a) / (int64_t)(b)) -#define ll_mul(a, b) ((int64_t)(a) * (int64_t)(b)) -#define ll_neg(a) (-(a)) -#define ll_not(a) (~(uint64_t)(a)) -#define ll_or(a, b) ((uint64_t)(a) | (b)) -#define ll_shl(a, n) ((uint64_t)(a) << (n)) -#define ll_shr(a, n) ((int64_t)(a) >> (n)) -#define ll_sub(a, b) ((uint64_t)(a) - (b)) -#define ll_ushr(a, n) ((uint64_t)(a) >>(n)) -#define ll_xor(a, b) ((int64_t)(a) ^ (int64_t)(b)) -#define uint2ll(a) ((uint64_t)(a)) -#define ll_rem(a,b) ((int64_t)(a) % (int64_t)(b)) - -extern int32_t float2l(float f); -extern int32_t double2l(double d); -extern int64_t float2ll(float f); -extern int64_t double2ll(double d); - -#define ll2float(a) ((float) (a)) -#define ll2double(a) ((double) (a)) - -/* Useful on machines where jlong and jdouble have different endianness. */ -#define ll2double_bits(a) ((void) 0) - -/* comparison operators */ -#define ll_ltz(ll) ((ll)<0) -#define ll_gez(ll) ((ll)>=0) -#define ll_eqz(a) ((a) == 0) -#define ll_nez(a) ((a) != 0) -#define ll_eq(a, b) ((a) == (b)) -#define ll_ne(a,b) ((a) != (b)) -#define ll_ge(a,b) ((a) >= (b)) -#define ll_le(a,b) ((a) <= (b)) -#define ll_lt(a,b) ((a) < (b)) -#define ll_gt(a,b) ((a) > (b)) - -#define ll_zero_const ((int64_t) 0) -#define ll_one_const ((int64_t) 1) - -extern void ll2str(int64_t a, char *s, char *limit); - -#define ll2ptr(a) ((void*)(uintptr_t)(a)) -#define ptr2ll(a) ((int64_t)(uintptr_t)(a)) - -#ifdef ppc -#define HAVE_ALIGNED_DOUBLES -#define HAVE_ALIGNED_LONGLONGS -#endif - -/* printf format modifier for printing pointers */ -#ifdef _LP64 -#define FORMAT64_MODIFIER "l" -#else -#define FORMAT64_MODIFIER "ll" -#endif - -#endif /* !_JAVASOFT_SOLARIS_TYPES_MD_H_ */ diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h b/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h index b0d15f85e3d7808a731694d47fd03b7dcd390764..2836b994485bd1b61fc896f2fe903d9f36247be7 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 @@ -31,7 +31,9 @@ #include #include #include +#ifndef __linux__ #include +#endif #include #include #include diff --git a/src/solaris/native/common/gdefs_md.h b/src/solaris/native/common/gdefs_md.h index 006e753f60ebe13624545a5fc5796ca4b70a29c1..dd74cfc2ce645b025aa2ec4bd915dc5d37d16ac2 100644 --- a/src/solaris/native/common/gdefs_md.h +++ b/src/solaris/native/common/gdefs_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 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 @@ -24,15 +24,12 @@ */ /* - * Solaris dependent type definitions includes intptr_t, etc + * Solaris/Linux dependent type definitions includes intptr_t, etc */ +#include +#include /* For uintptr_t */ +#include #include -/* - * Linux version of does not define intptr_t - */ -#ifdef __linux__ -#include -#include -#endif /* __linux__ */ + diff --git a/src/solaris/native/common/jlong_md.h b/src/solaris/native/common/jlong_md.h index 4460701065e2a575836d05dbf604b13e4bed6c56..a12044e475188d3aa83cece3b017d0e497ce55f6 100644 --- a/src/solaris/native/common/jlong_md.h +++ b/src/solaris/native/common/jlong_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-2002 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,7 +28,7 @@ /* Make sure ptrdiff_t is defined */ #include -#include "typedefs.h" +#include /* For uintptr_t */ #define jlong_high(a) ((jint)((a)>>32)) #define jlong_low(a) ((jint)(a)) diff --git a/src/solaris/native/java/net/NetworkInterface.c b/src/solaris/native/java/net/NetworkInterface.c index a541744831a5a17291f2d42c50e1a258ed8c4359..14273f5c132d26893778a0d8e3fb6931fbf2e578 100644 --- a/src/solaris/native/java/net/NetworkInterface.c +++ b/src/solaris/native/java/net/NetworkInterface.c @@ -206,10 +206,10 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 /* * Class: java_net_NetworkInterface - * Method: getByIndex + * Method: getByIndex0 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0 (JNIEnv *env, jclass cls, jint index) { netif *ifs, *curr; diff --git a/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/src/solaris/native/java/net/PlainDatagramSocketImpl.c index 7c68f720582f2950e43b4416758ccc88c24ec897..dc804be4575125560929855c08a0a64199d62bb9 100644 --- a/src/solaris/native/java/net/PlainDatagramSocketImpl.c +++ b/src/solaris/native/java/net/PlainDatagramSocketImpl.c @@ -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 @@ -1741,7 +1741,7 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { * (for IF). */ if (index > 0) { - ni = Java_java_net_NetworkInterface_getByIndex(env, ni_class, + ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, index); if (ni == NULL) { char errmsg[255]; diff --git a/src/solaris/native/java/net/SocketInputStream.c b/src/solaris/native/java/net/SocketInputStream.c index a491461b9c7a687dacd281ce1972f644e2f4edee..5e5f193e3f2e8446c6e62cd9f7c12ff47630122d 100644 --- a/src/solaris/native/java/net/SocketInputStream.c +++ b/src/solaris/native/java/net/SocketInputStream.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2002 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 diff --git a/src/solaris/native/java/net/SocketOutputStream.c b/src/solaris/native/java/net/SocketOutputStream.c index 2ab6645f3ef2a3d0db94d91b13bc25161bca87f8..575a719eadd18e9f8c01b8bfa383abc4e1110ade 100644 --- a/src/solaris/native/java/net/SocketOutputStream.c +++ b/src/solaris/native/java/net/SocketOutputStream.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2002 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 diff --git a/src/solaris/native/java/net/linux_close.c b/src/solaris/native/java/net/linux_close.c index 4547451e42e1dc0ca2f4ac7af4ca0818614072dc..59f0bd3decb1704fc41b19ff9e0e7fb91b3c78a9 100644 --- a/src/solaris/native/java/net/linux_close.c +++ b/src/solaris/native/java/net/linux_close.c @@ -1,5 +1,5 @@ /* - * Copyright 2001 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 diff --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c index 1ff6c48dba2bab452a4415192d74b78f0a1ae728..cfc86a8842f502a683187ba7104380dc2828ec7a 100644 --- a/src/solaris/native/java/net/net_util_md.c +++ b/src/solaris/native/java/net/net_util_md.c @@ -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 @@ -791,7 +791,7 @@ NET_SetTrafficClass(struct sockaddr *him, int trafficClass) { #endif /* AF_INET6 */ } -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { #ifdef AF_INET6 if (him->sa_family == AF_INET6) { diff --git a/src/solaris/native/java/nio/MappedByteBuffer.c b/src/solaris/native/java/nio/MappedByteBuffer.c index 70d5c3e658ee852627a7432a147aed9eecfe4199..60572bc6c05fd0ef940854fb1dc2137bf118139b 100644 --- a/src/solaris/native/java/nio/MappedByteBuffer.c +++ b/src/solaris/native/java/nio/MappedByteBuffer.c @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 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 diff --git a/src/solaris/native/sun/awt/awt_Button.c b/src/solaris/native/sun/awt/awt_Button.c deleted file mode 100644 index a522487c0d0993d1328c0d27a87b9fed5fdde97c..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Button.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Canvas.c b/src/solaris/native/sun/awt/awt_Canvas.c deleted file mode 100644 index 98cf45e1cb0df523d632bdae99d41aab3e2139ab..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Canvas.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Checkbox.c b/src/solaris/native/sun/awt/awt_Checkbox.c deleted file mode 100644 index e620d678e422cc7d9de9fdba11f67a317fb2988c..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Checkbox.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Choice12.c b/src/solaris/native/sun/awt/awt_Choice12.c deleted file mode 100644 index 57f9e6d029e856cc510f91d2273d9672efca70be..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Choice12.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Choice21.c b/src/solaris/native/sun/awt/awt_Choice21.c deleted file mode 100644 index 838f991f84ec116fc93bd16c13b393deab62d9d3..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Choice21.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Component.c b/src/solaris/native/sun/awt/awt_Component.c deleted file mode 100644 index b61e89dfc7d9c7b0930b097c0aba282acaab0787..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Component.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Cursor.c b/src/solaris/native/sun/awt/awt_Cursor.c deleted file mode 100644 index 0555c854f58e40303d9bc28db07a86db7b882e2f..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Cursor.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_DataTransferer.c b/src/solaris/native/sun/awt/awt_DataTransferer.c deleted file mode 100644 index 4944f5ef1c141fb7b78a794c3e9419ac7fe6b51a..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_DataTransferer.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_DataTransferer.h b/src/solaris/native/sun/awt/awt_DataTransferer.h deleted file mode 100644 index e4be5800759026b6651a8213d3184b9611c32eaf..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_DataTransferer.h +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_DrawingSurface.c b/src/solaris/native/sun/awt/awt_DrawingSurface.c index a761966022577d927b00d1d864b7834b58d7958c..8af0c57e95a6ec9cd2450507c2baf0aaaa1945b8 100644 --- a/src/solaris/native/sun/awt/awt_DrawingSurface.c +++ b/src/solaris/native/sun/awt/awt_DrawingSurface.c @@ -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 --git a/src/solaris/native/sun/awt/awt_FileDialog.c b/src/solaris/native/sun/awt/awt_FileDialog.c deleted file mode 100644 index a170deda9c40cece220ac48e63b9a72daefb011c..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_FileDialog.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_GlobalCursorManager.c b/src/solaris/native/sun/awt/awt_GlobalCursorManager.c deleted file mode 100644 index a64aeed210adfee8c90f901c589bca90f62b4658..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_GlobalCursorManager.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_KeyboardFocusManager.c b/src/solaris/native/sun/awt/awt_KeyboardFocusManager.c deleted file mode 100644 index 14774d771cf545589d79a354338685de1834c679..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_KeyboardFocusManager.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Label.c b/src/solaris/native/sun/awt/awt_Label.c deleted file mode 100644 index f690ad939e98ef4e33b00f804bc0d6ce11b11aad..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Label.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_List.c b/src/solaris/native/sun/awt/awt_List.c deleted file mode 100644 index 0064344497033a029dacf4103ccf5fa4ea55cccc..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_List.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_MToolkit.c b/src/solaris/native/sun/awt/awt_MToolkit.c index aeeae21723984952ce3b4166483122c7469d1902..cef75987915d89f4439a20682391efa40a4eb87a 100644 --- a/src/solaris/native/sun/awt/awt_MToolkit.c +++ b/src/solaris/native/sun/awt/awt_MToolkit.c @@ -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 --git a/src/solaris/native/sun/awt/awt_Menu.c b/src/solaris/native/sun/awt/awt_Menu.c deleted file mode 100644 index 3b2b3918dec6a4095c254eb0b44d12cf1f3ccd6c..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Menu.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_MenuBar.c b/src/solaris/native/sun/awt/awt_MenuBar.c deleted file mode 100644 index 903293e828ec588f8f1c28ebd6486c4f086bec8c..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_MenuBar.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_MenuItem.c b/src/solaris/native/sun/awt/awt_MenuItem.c deleted file mode 100644 index 28eebc49685b283b04f968380e90984d45f2d90f..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_MenuItem.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_PopupMenu.c b/src/solaris/native/sun/awt/awt_PopupMenu.c deleted file mode 100644 index afd186b7e5af729a1f68464496f22dc35432ac01..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_PopupMenu.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Robot.c b/src/solaris/native/sun/awt/awt_Robot.c index 10cf652d77e9f24b4e1cafd72ccd0f989ecda719..07c053bce281476cc0804e152f200e0e290c3972 100644 --- a/src/solaris/native/sun/awt/awt_Robot.c +++ b/src/solaris/native/sun/awt/awt_Robot.c @@ -204,14 +204,8 @@ static XImage *getWindowImage(Display * display, Window window, /*********************************************************************************************/ -#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 @@ FUNC_NAME(setup) (JNIEnv * env, jclass cls) { } 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 @@ FUNC_NAME(getRGBPixelsImpl)( JNIEnv *env, } JNIEXPORT void JNICALL -FUNC_NAME(keyPressImpl) (JNIEnv *env, +Java_sun_awt_X11_XRobotPeer_keyPressImpl (JNIEnv *env, jclass cls, jint keycode) { @@ -315,7 +309,7 @@ FUNC_NAME(keyPressImpl) (JNIEnv *env, } 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 @@ FUNC_NAME(keyReleaseImpl) (JNIEnv *env, } 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 @@ FUNC_NAME(mouseMoveImpl) (JNIEnv *env, } 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 @@ FUNC_NAME(mousePressImpl) (JNIEnv *env, } 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 @@ FUNC_NAME(mouseReleaseImpl) (JNIEnv *env, } 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 --git a/src/solaris/native/sun/awt/awt_ScrollPane.c b/src/solaris/native/sun/awt/awt_ScrollPane.c deleted file mode 100644 index 1c6777cb92b0a8d722406e03da6519df17834f1a..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_ScrollPane.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Scrollbar.c b/src/solaris/native/sun/awt/awt_Scrollbar.c deleted file mode 100644 index 4b7586edf79ee7baf65009e98921c3598333f71e..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Scrollbar.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_Selection.c b/src/solaris/native/sun/awt/awt_Selection.c deleted file mode 100644 index 5d5b934459f9ae06bccba6ab7dbd0ff3c5197953..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_Selection.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_TextArea.c b/src/solaris/native/sun/awt/awt_TextArea.c deleted file mode 100644 index 548b0d243101398ceec9f6e66bfae30911989f78..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_TextArea.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_TextField.c b/src/solaris/native/sun/awt/awt_TextField.c deleted file mode 100644 index 889d82b718b13fa6c42914ab7b76f986bc35e32e..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_TextField.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_TopLevel.c b/src/solaris/native/sun/awt/awt_TopLevel.c deleted file mode 100644 index 165c1cfa56210376e79a64be0674fee0d7608844..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_TopLevel.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_XmDnD.c b/src/solaris/native/sun/awt/awt_XmDnD.c deleted file mode 100644 index 602af7a2df5064a4e1ffbae0067a22e6de7dc63a..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_XmDnD.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_dnd.c b/src/solaris/native/sun/awt/awt_dnd.c deleted file mode 100644 index 1b5c9d49ce42841e8da7b76d08578c2043f13209..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_dnd.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_dnd.h b/src/solaris/native/sun/awt/awt_dnd.h deleted file mode 100644 index 5e2f3e437da1ea11a1db153b8e8b08687c5d91e2..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_dnd.h +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_dnd_ds.c b/src/solaris/native/sun/awt/awt_dnd_ds.c deleted file mode 100644 index 4edc454df82419b59b54e7bd74af984306c83e8a..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_dnd_ds.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_dnd_dt.c b/src/solaris/native/sun/awt/awt_dnd_dt.c deleted file mode 100644 index 7b76f81195e53c43bef03dc3f419396d1a0909c9..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_dnd_dt.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_motif12.c b/src/solaris/native/sun/awt/awt_motif12.c deleted file mode 100644 index fc3d90ed99537b0dc9f874f0d85545fe65f9aa40..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_motif12.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_motif21.c b/src/solaris/native/sun/awt/awt_motif21.c deleted file mode 100644 index 3bd95f97aeff65462896c21bf6221484c6ef0c5a..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_motif21.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/awt_p.h b/src/solaris/native/sun/awt/awt_p.h index eb7bc55a27dbe2a2a278aad85ae4b837014e6f08..fb4f513f79f80f37f51b9b2c31bdd16a3ec2b36e 100644 --- a/src/solaris/native/sun/awt/awt_p.h +++ b/src/solaris/native/sun/awt/awt_p.h @@ -79,7 +79,7 @@ #ifndef XAWT #include "GLXGraphicsConfig.h" -#include +//#include #endif #ifndef HEADLESS diff --git a/src/solaris/native/sun/awt/awt_xembed.c b/src/solaris/native/sun/awt/awt_xembed.c deleted file mode 100644 index 86bfae68f661e6d31584bccb05ce292bedf72951..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/awt_xembed.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/canvas.c b/src/solaris/native/sun/awt/canvas.c deleted file mode 100644 index 1a2f7dd4164efcd717c155f6c891aa22ec68ccdf..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/canvas.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/cursor.c b/src/solaris/native/sun/awt/cursor.c deleted file mode 100644 index f93c15e295a2ae21bcbbc1d3ca209a7773f7dc61..0000000000000000000000000000000000000000 --- a/src/solaris/native/sun/awt/cursor.c +++ /dev/null @@ -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 --git a/src/solaris/native/sun/awt/initIDs.c b/src/solaris/native/sun/awt/initIDs.c index f026d9ae727f6468b185dcff085cbf918ca20fa7..1eb03b1c52f79a6807d5bd80beb5f9a939ae3eea 100644 --- a/src/solaris/native/sun/awt/initIDs.c +++ b/src/solaris/native/sun/awt/initIDs.c @@ -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 --git a/src/solaris/native/sun/awt/multi_font.c b/src/solaris/native/sun/awt/multi_font.c index aad6bfec9925c61bac668f30b463e914db9fc46d..3d321bbb5fb53625b1f3cb7e7d67789b81ca9525 100644 --- a/src/solaris/native/sun/awt/multi_font.c +++ b/src/solaris/native/sun/awt/multi_font.c @@ -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 @@ awtJNI_DeleteGlobalMenuRef(JNIEnv * env, jobject this) 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 --git a/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c b/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c index 657950f48d6fd6c663cce8476b69637be455a60f..c50f6c67879ad886087fbe8bb1ae647a44863c21 100644 --- a/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c +++ b/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c @@ -40,6 +40,7 @@ #include #include #include +#include static Bool shapeSupported; static int shapeEventBase, shapeErrorBase; @@ -534,40 +535,34 @@ void 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 --git a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c index b1f9f680b18a3a75600ed18a40250616b6b3290b..a1e66d938e9c030db4599bd736254c8385a37b60 100644 --- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c @@ -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 @@ -198,7 +198,7 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, 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 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, if (NET_InetAddressToSockaddr(env, destAddress, destPort, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } diff --git a/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c b/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c index ad9237b2e177443633999707afbd85e99e0658d0..635588dd8739745038aed07729f6b3f8131427d0 100644 --- a/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c +++ b/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c @@ -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 @@ -48,10 +48,18 @@ typedef union epoll_data { __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 @@ Java_sun_nio_ch_EPollArrayWrapper_fdLimit(JNIEnv *env, jclass this) 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 --git a/src/solaris/native/sun/nio/ch/FileKey.c b/src/solaris/native/sun/nio/ch/FileKey.c index 511b27f877d06022bd00d8445902ed170306a882..b0eebeadfdd82efaadada7786d5a9321e2cfa286 100644 --- a/src/solaris/native/sun/nio/ch/FileKey.c +++ b/src/solaris/native/sun/nio/ch/FileKey.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -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 --git a/src/solaris/native/sun/nio/ch/InheritedChannel.c b/src/solaris/native/sun/nio/ch/InheritedChannel.c index c6ba463a5a0e720749f1c65c861a384049f2bd2b..408730777ce3a567a841104eb0234cf67dd045b9 100644 --- a/src/solaris/native/sun/nio/ch/InheritedChannel.c +++ b/src/solaris/native/sun/nio/ch/InheritedChannel.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c index 9eb31c8926efe31048f94e3d27357a03284890ac..14ef8d143052fbafa84e0d4cc8d04265fa837b3d 100644 --- a/src/solaris/native/sun/nio/ch/Net.c +++ b/src/solaris/native/sun/nio/ch/Net.c @@ -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 @@ -37,61 +37,171 @@ #include "net_util.h" #include "net_util_md.h" #include "nio_util.h" -#include "java_net_SocketOptions.h" #include "nio.h" -#ifdef __linux__ -#include +/** + * 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 -#define IPV6_MULTICAST_IF 17 -#ifndef SO_BSDCOMPAT -#define SO_BSDCOMPAT 14 +#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__ + +#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 */ +}; + +#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) { /* 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 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk } } +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 @@ Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 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) -{ - - switch (opt) { - - case java_net_SocketOptions_IP_TOS: - *klevel = IPPROTO_IP; - *kopt = IP_TOS; - break; - - 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; - - case java_net_SocketOptions_TCP_NODELAY: - *klevel = IPPROTO_IP; - *kopt = TCP_NODELAY; - return 0; - - default: - JNU_ThrowByName(env, "java/lang/IllegalArgumentException", NULL); - return -1; - } - - 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; - } - - return 0; -} -#endif - - JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt) +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) { - int klevel, kopt; int result; struct linger linger; + u_char carg; void *arg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return -1; + /* Option value is an int except for a few specific cases */ + + arg = (void *)&result; + arglen = sizeof(result); + + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { + arg = (void*)&carg; + arglen = sizeof(carg); } - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == 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 (mayNeedConversion) { + n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); + } else { + n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); + } + 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; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return; + /* Option value is an int except for a few specific cases */ + + 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 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, 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 --git a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c index da92ed73d951387d33884c16514cf471e211584b..e946dbdc82d807d5938c32808631548632ffa527 100644 --- a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 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 @@ -65,14 +65,6 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass c) "(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 --git a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c index 94c8467cf21db978f83609dfba54eb46563dabbc..785d4a612d8051257aab0f64bb2844903f018bc4 100644 --- a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 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 @@ -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 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this, } 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 --git a/src/solaris/native/sun/nio/ch/nio_util.h b/src/solaris/native/sun/nio/ch/nio_util.h index 608b0cc8999bf83b369ed3264b1608d0f5816f37..79c20bf24fe49362bf885e7115c854e2a56b564e 100644 --- a/src/solaris/native/sun/nio/ch/nio_util.h +++ b/src/solaris/native/sun/nio/ch/nio_util.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2002 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 @@ -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 --git a/src/solaris/transport/socket/socket_md.c b/src/solaris/transport/socket/socket_md.c index 84bfbe9374ceaebb78fdb12e132d7f4b744c0922..63ac591ed3a539bcac63b0f62608f40008c476d4 100644 --- a/src/solaris/transport/socket/socket_md.c +++ b/src/solaris/transport/socket/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/windows/back/util_md.h b/src/windows/back/util_md.h index 2b9200b77a6156f47280247c6795fabf225f8357..604b3cccb9b59d77576c499e67fae25a52332068 100644 --- a/src/windows/back/util_md.h +++ b/src/windows/back/util_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 @@ -26,6 +26,7 @@ #ifndef JDWP_UTIL_MD_H #define JDWP_UTIL_MD_H +#include /* for uintptr_t */ #include /* for _MAx_PATH */ typedef unsigned __int64 UNSIGNED_JLONG; diff --git a/src/windows/bin/java_md.c b/src/windows/bin/java_md.c index 53e1e9a0a9399a2099f7936e7bd2a6b020618d21..2db1f25e2c4e4faed00e666d23032b0ee3de6717 100644 --- a/src/windows/bin/java_md.c +++ b/src/windows/bin/java_md.c @@ -105,26 +105,26 @@ CreateExecutionEnvironment(int *_argc, } } 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 @@ GetJREPath(char *path, jint pathsize) goto found; } - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -212,7 +212,7 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) 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 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) /* 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 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) 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 @@ GetPublicJREHome(char *buf, jint bufsize) /* 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 @@ GetPublicJREHome(char *buf, jint bufsize) /* 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 @@ jlong Counter2Micros(jlong counts) } void -ReportErrorMessage(const char* fmt, ...) { +JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl,fmt); @@ -394,12 +394,12 @@ ReportErrorMessage(const char* fmt, ...) { } /* - * 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 @@ ReportErrorMessageSys(const char *fmt, ...) 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 @@ ExecJRE(char *jre, char **argv) { */ 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 @@ ExecJRE(char *jre, char **argv) { * 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 @@ ExecJRE(char *jre, char **argv) { (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 @@ ExecJRE(char *jre, char **argv) { if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) exitCode = 1; } else { - ReportErrorMessage(SYS_ERROR2); + JLI_ReportErrorMessage(SYS_ERROR2); exitCode = 1; } diff --git a/src/windows/classes/sun/nio/ch/PipeImpl.java b/src/windows/classes/sun/nio/ch/PipeImpl.java index f021265f491f0cefa315c0fec34eebc3bc82ce87..4bee9845fd41c51a20173b4f9c41a7270197ad4e 100644 --- a/src/windows/classes/sun/nio/ch/PipeImpl.java +++ b/src/windows/classes/sun/nio/ch/PipeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2004 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 diff --git a/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index 0617c0f7ddc2c88cc28a5273f70ab18b00657af4..ac25ac0803ae4b9a72f529da238edf47050c2b84 100644 --- a/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 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 diff --git a/src/windows/hpi/src/socket_md.c b/src/windows/hpi/src/socket_md.c index 852022a4938f9165b0f6cc18c2e6c1aff4136434..8dd5f95680f53feb7a1ec11e9b9808f83632765d 100644 --- a/src/windows/hpi/src/socket_md.c +++ b/src/windows/hpi/src/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 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 @@ -29,7 +29,6 @@ #include "hpi_impl.h" #include "mutex_md.h" -#include "typedefs.h" struct sockaddr; diff --git a/src/windows/hpi/src/threads_md.c b/src/windows/hpi/src/threads_md.c index 410f61c98075d3f9f5ab3b52e1fe621203f336a5..1c6b63f33b73c2d21200608666e0167f380faf6f 100644 --- a/src/windows/hpi/src/threads_md.c +++ b/src/windows/hpi/src/threads_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1994-2003 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 @@ -35,7 +35,6 @@ #include "threads_md.h" #include "monitor_md.h" -#include "typedefs.h" /* diff --git a/src/windows/instrument/FileSystemSupport_md.h b/src/windows/instrument/FileSystemSupport_md.h index bd9c029bcbd8a86c7bf39f16077159a1cc378536..9d29ea6fef05fe336b97b105a73597ebcd60f648 100644 --- a/src/windows/instrument/FileSystemSupport_md.h +++ b/src/windows/instrument/FileSystemSupport_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -23,6 +23,7 @@ * have any questions. */ +#include /* For uintprt_t */ #include #define MAXPATHLEN _MAX_PATH diff --git a/src/windows/javavm/export/jvm_md.h b/src/windows/javavm/export/jvm_md.h index 76560f6ec7d341806c671082439aba6eb3df34eb..771ab10334a1d069e1fbacb4f6b8fdda3607bfd2 100644 --- a/src/windows/javavm/export/jvm_md.h +++ b/src/windows/javavm/export/jvm_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-1999 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 @@ -53,6 +53,7 @@ typedef struct { WIN32_FIND_DATA find_data; } DIR; +#include /* For uintptr_t */ #include #define JVM_MAXPATHLEN _MAX_PATH @@ -65,6 +66,19 @@ typedef struct { JNIEXPORT void * JNICALL JVM_GetThreadInterruptEvent(); +/* + * These routines are only reentrant on Windows + */ + +JNIEXPORT struct protoent * JNICALL +JVM_GetProtoByName(char* name); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByAddr(const char* name, int len, int type); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByName(char* name); + /* * File I/O */ diff --git a/src/windows/javavm/include/typedefs_md.h b/src/windows/javavm/include/typedefs_md.h deleted file mode 100644 index 7c41e9aa706a489603c163df2e005a1b10621a0f..0000000000000000000000000000000000000000 --- a/src/windows/javavm/include/typedefs_md.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 1994-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. - */ - -/* - * Win32 dependent type definitions - */ - -#ifndef _JAVASOFT_WIN32_TYPEDEF_MD_H_ -#define _JAVASOFT_WIN32_TYPEDEF_MD_H_ - -#include - -#define VARGS(x) (&x) - -typedef char int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; - -typedef unsigned char uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned int uint_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -/* Make sure that we have the intptr_t and uintptr_t definitions */ -#ifndef _INTPTR_T_DEFINED -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -typedef int intptr_t; -#endif -#define _INTPTR_T_DEFINED -#endif - -#ifndef _UINTPTR_T_DEFINED -#ifdef _WIN64 -typedef unsigned __int64 uintptr_t; -#else -typedef unsigned int uintptr_t; -#endif -#define _UINTPTR_T_DEFINED -#endif - -typedef intptr_t ssize_t; - -/* use these macros when the compiler supports the long long type */ - -#define ll_high(a) ((long)((a)>>32)) -#define ll_low(a) ((long)(a)) -#define int2ll(a) ((int64_t)(a)) -#define ll2int(a) ((int)(a)) -#define ll_add(a, b) ((a) + (b)) -#define ll_and(a, b) ((a) & (b)) -#define ll_div(a, b) ((a) / (b)) -#define ll_mul(a, b) ((a) * (b)) -#define ll_neg(a) (-(a)) -#define ll_not(a) (~(a)) -#define ll_or(a, b) ((a) | (b)) -/* THE FOLLOWING DEFINITION IS NOW A FUNCTION CALL IN ORDER TO WORKAROUND - OPTIMIZER BUG IN MSVC++ 2.1 (see system_md.c) - #define ll_shl(a, n) ((a) << (n)) */ -#define ll_shr(a, n) ((a) >> (n)) -#define ll_sub(a, b) ((a) - (b)) -#define ll_ushr(a, n) ((uint64_t)(a) >> (n)) -#define ll_xor(a, b) ((a) ^ (b)) -#define uint2ll(a) ((uint64_t)(unsigned long)(a)) -#define ll_rem(a,b) ((a) % (b)) - -int32_t float2l(float f); -int32_t double2l(double f); -int64_t float2ll(float f); -int64_t double2ll(double f); -#define ll2float(a) ((float) (a)) -#define ll2double(a) ((double) (a)) - -/* Useful on machines where jlong and jdouble have different endianness. */ -#define ll2double_bits(a) ((void) 0) - -/* comparison operators */ -#define ll_ltz(ll) ((ll) < 0) -#define ll_gez(ll) ((ll) >= 0) -#define ll_eqz(a) ((a) == 0) -#define ll_nez(a) ((a) != 0) -#define ll_eq(a, b) ((a) == (b)) -#define ll_ne(a,b) ((a) != (b)) -#define ll_ge(a,b) ((a) >= (b)) -#define ll_le(a,b) ((a) <= (b)) -#define ll_lt(a,b) ((a) < (b)) -#define ll_gt(a,b) ((a) > (b)) - -#define ll_zero_const ((int64_t) 0) -#define ll_one_const ((int64_t) 1) - -int64_t ll_shl(int64_t a, int bits); - -#define ll2ptr(a) ((void*)(a)) -#define ptr2ll(a) ((jlong)(a)) - -/* printf format modifier for printing pointers */ -#define FORMAT64_MODIFIER "I64" - -#endif /* !_JAVASOFT_WIN32_TYPEDEF_MD_H_ */ diff --git a/src/windows/native/java/net/NetworkInterface.c b/src/windows/native/java/net/NetworkInterface.c index a9adb183377932e1b2c2b8065c00f5a78137547c..47133fd150168d38fa02aeb46e6e3c18cd069721 100644 --- a/src/windows/native/java/net/NetworkInterface.c +++ b/src/windows/native/java/net/NetworkInterface.c @@ -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 @@ -554,11 +554,11 @@ Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;"); ni_ctor = (*env)->GetMethodID(env, ni_class, "", "()V"); - ni_iacls = (*env)->FindClass(env, "Ljava/net/InetAddress;"); + ni_iacls = (*env)->FindClass(env, "java/net/InetAddress"); ni_iacls = (*env)->NewGlobalRef(env, ni_iacls); ni_iaAddr = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_ia4cls = (*env)->FindClass(env, "Ljava/net/Inet4Address;"); + ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4Ctor = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); @@ -762,17 +762,17 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 /* * Class: NetworkInterface - * Method: getByIndex + * Method: getByIndex0 * Signature: (I)LNetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0 (JNIEnv *env, jclass cls, jint index) { netif *ifList, *curr; jobject netifObj = NULL; if (os_supports_ipv6 && ipv6_available()) { - return Java_java_net_NetworkInterface_getByIndex_XP (env, cls, index); + return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index); } /* get the list of interfaces */ diff --git a/src/windows/native/java/net/NetworkInterface.h b/src/windows/native/java/net/NetworkInterface.h index 55600830e46d541eeaf9b472ed41ac802546fee3..c3d8511c663d17fbfa23a0aa1deaf85bc14f823a 100644 --- a/src/windows/native/java/net/NetworkInterface.h +++ b/src/windows/native/java/net/NetworkInterface.h @@ -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 diff --git a/src/windows/native/java/net/NetworkInterface_win9x.c b/src/windows/native/java/net/NetworkInterface_win9x.c index c2114165421d8568d084867f3a01d23d3cc7cdfb..1e77adc81a2acb37018ad0371b748f969d9456b8 100644 --- a/src/windows/native/java/net/NetworkInterface_win9x.c +++ b/src/windows/native/java/net/NetworkInterface_win9x.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2003 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 diff --git a/src/windows/native/java/net/NetworkInterface_winXP.c b/src/windows/native/java/net/NetworkInterface_winXP.c index 87eb2eb9ab5633294b0c6539d26380c358db23c2..0fcfa9fddeff6db6c8d49b2a5b2283d54dc24ea1 100644 --- a/src/windows/native/java/net/NetworkInterface_winXP.c +++ b/src/windows/native/java/net/NetworkInterface_winXP.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -576,10 +576,10 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP /* * Class: NetworkInterface - * Method: getByIndex + * Method: getByIndex0_XP * Signature: (I)LNetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex_XP +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP (JNIEnv *env, jclass cls, jint index) { netif *ifList, *curr; diff --git a/src/windows/native/java/net/SocketOutputStream.c b/src/windows/native/java/net/SocketOutputStream.c index 6b33a7d39dc7ccaff0a210cc5d44e86776862174..7664e5f7f55ccac2b521e450a248b88213ea10de 100644 --- a/src/windows/native/java/net/SocketOutputStream.c +++ b/src/windows/native/java/net/SocketOutputStream.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2003 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 diff --git a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c index 4ada9f964d22581cf5761c9bd38d57767c3ed2a9..77633f4e40ac819ab2bc7d14d14df1f48ff00f36 100644 --- a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c +++ b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c @@ -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 @@ -2090,7 +2090,7 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o * (for IF). */ if (index > 0) { - ni = Java_java_net_NetworkInterface_getByIndex(env, ni_class, + ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, index); if (ni == NULL) { char errmsg[255]; diff --git a/src/windows/native/java/net/TwoStacksPlainSocketImpl.c b/src/windows/native/java/net/TwoStacksPlainSocketImpl.c index f3cfd20dfceee3eecddaa90ef24bad24368d758e..58dbf36a7726b10de2a15814dee90b7331ab63c0 100644 --- a/src/windows/native/java/net/TwoStacksPlainSocketImpl.c +++ b/src/windows/native/java/net/TwoStacksPlainSocketImpl.c @@ -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 diff --git a/src/windows/native/java/net/net_util_md.c b/src/windows/native/java/net/net_util_md.c index 87dbdcf79e0166e5c8a6b4ca06a0cb4e8cd2aedd..ddf149684789ef1bffb4407ab9091e288ce83ab7 100644 --- a/src/windows/native/java/net/net_util_md.c +++ b/src/windows/native/java/net/net_util_md.c @@ -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 @@ -28,7 +28,6 @@ #include "net_util.h" #include "jni.h" -#include "typedefs.h" #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e @@ -890,7 +889,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr 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 --git a/src/windows/native/java/net/net_util_md.h b/src/windows/native/java/net/net_util_md.h index 9b237c4dcf69c625fd7f54fddb83600b8cbfd2c3..23574f1725f8f6d7bf7dd5e84b67c1d3170b3dcc 100644 --- a/src/windows/native/java/net/net_util_md.h +++ b/src/windows/native/java/net/net_util_md.h @@ -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 @@ -329,7 +329,7 @@ extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP (JNIEnv *env, jclass cls, jstring name); -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex_XP +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP (JNIEnv *env, jclass cls, jint index); JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0_XP diff --git a/src/windows/native/sun/net/dns/ResolverConfigurationImpl.c b/src/windows/native/sun/net/dns/ResolverConfigurationImpl.c index d698787568a5d7baefc6eebd8455c052c9977325..9d564056ee5fdea0ad652fed027d990a8bbd79ac 100644 --- a/src/windows/native/sun/net/dns/ResolverConfigurationImpl.c +++ b/src/windows/native/sun/net/dns/ResolverConfigurationImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2002 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 diff --git a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c index 6d400c213c0e9909c0157fb51b1136665a315aaa..5e6a386aa34c7affac20b2919c77a558e314bf16 100644 --- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c @@ -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 @@ -39,46 +39,9 @@ static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ 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; +static jmethodID isa_ctorID; /* java.net.InetSocketAddress(InetAddress, int) */ -/* - * 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; - } - - /* - * 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 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) "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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) 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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) 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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) 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 @@ Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this, { 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, { 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, (char *)buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, &sa_len); if (n == SOCKET_ERROR) { @@ -233,21 +164,30 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, } } while (retry); - if (!isSenderCached(env, this, &psa)) { - int port = ntohs(psa.sin_port); - jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID); - jobject isa = NULL; - - if (psa.sin_family != AF_INET) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", - "Protocol family unavailable"); + /* + * 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; + 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, // 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, 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 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); diff --git a/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c index b9fac794e45d19835e972b642e84b866e5832022..b6353b9b3b57294948ca0b195261a04365c719a5 100644 --- a/src/windows/native/sun/nio/ch/Net.c +++ b/src/windows/native/sun/nio/ch/Net.c @@ -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 @@ -36,51 +36,95 @@ #include "sun_nio_ch_Net.h" +/** + * Definitions to allow for building with older SDK include files. + */ + +#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 jfieldID ia_addrID; -static jclass ia_class; -static jmethodID ia_ctorID; -static jfieldID ia_famID; +typedef struct my_ip_mreq_source { + IN_ADDR imr_multiaddr; + IN_ADDR imr_sourceaddr; + IN_ADDR imr_interface; +}; -/************************************************************** - * static method to store field IDs in initializers +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 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, 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 @@ Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao, 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 @@ Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 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; } + return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); +} - 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)); - } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) +{ + SOCKETADDRESS sa; + int sa_len = sizeof(sa); - return iao; + 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, jint opt) +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) { - int klevel, kopt; - int result; + int result = 0; struct linger linger; char *arg; - int arglen; - - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return IOS_THROWN; - } + int arglen, n; - 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 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, 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 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, 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 --git a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c index 36b6006e0aa48aa4d1be16fefabdce338e706154..4b4669205e266cfd19ef94d2fe14fa9b69d702c4 100644 --- a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c +++ b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 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 @@ -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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass cls) 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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, { 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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); return IOS_THROWN; } - (*env)->SetIntField(env, newfdo, fd_fdID, newfd); - 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); + (*env)->SetIntField(env, newfdo, fd_fdID, newfd); + remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); - isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, - ntohs(sa.sin_port)); + isa = (*env)->NewObject(env, isa_class, isa_ctorID, + remote_ia, remote_port); (*env)->SetObjectArrayElement(env, isaa, 0, isa); + return 1; } diff --git a/src/windows/native/sun/nio/ch/SocketChannelImpl.c b/src/windows/native/sun/nio/ch/SocketChannelImpl.c index d49d9bf29ed779c2cffab831a83039b6a08f668e..a8125d9b44e5b5feb316cb66dc9aaf298ce7e7a7 100644 --- a/src/windows/native/sun/nio/ch/SocketChannelImpl.c +++ b/src/windows/native/sun/nio/ch/SocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 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 @@ -139,12 +139,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this, 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 --git a/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c b/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c index cb424adebc488d9b51b20c94f1f8f8ebf1cc241b..a9d35938faa8731b7b9b48bb98bb32a4b2c096ee 100644 --- a/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c +++ b/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c @@ -1,5 +1,5 @@ /* - * Copyright 2002 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 diff --git a/src/windows/native/sun/windows/ComCtl32Util.cpp b/src/windows/native/sun/windows/ComCtl32Util.cpp index d9309a6856bac3b345381f14e115164f1c271772..a36ac6df9fcf02159887bf059af5a41b8e61b328 100644 --- a/src/windows/native/sun/windows/ComCtl32Util.cpp +++ b/src/windows/native/sun/windows/ComCtl32Util.cpp @@ -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 @@ -49,6 +49,9 @@ void ComCtl32Util::InitLibraries() { m_bNewSubclassing = (m_lpfnSetWindowSubclass != NULL) && (m_lpfnRemoveWindowSubclass != NULL) && (m_lpfnDefSubclassProc != NULL); + + fn_InitCommonControlsEx = (ComCtl32Util::InitCommonControlsExType)::GetProcAddress(hModComCtl32, "InitCommonControlsEx"); + InitCommonControls(); } } } @@ -108,3 +111,15 @@ LRESULT ComCtl32Util::SharedWindowProc(HWND hwnd, UINT msg, 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 --git a/src/windows/native/sun/windows/ComCtl32Util.h b/src/windows/native/sun/windows/ComCtl32Util.h index b90869ba39e53b2ac783495d97da341a03661713..888a14db1ba51ea1dd26cb00c28f2a3b3544b7f5 100644 --- a/src/windows/native/sun/windows/ComCtl32Util.h +++ b/src/windows/native/sun/windows/ComCtl32Util.h @@ -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 @@ -25,6 +25,8 @@ #include "awt_Component.h" +#include + #ifndef _COMCTL32UTIL_H #define _COMCTL32UTIL_H @@ -81,6 +83,11 @@ class ComCtl32Util 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 --git a/src/windows/native/sun/windows/awt_Container.cpp b/src/windows/native/sun/windows/awt_Container.cpp index c136e4bd85e7128c33d323af63be683e2ecefe3f..65ded5910963de3f43a41cc195e6f28e20d9a4f3 100644 --- a/src/windows/native/sun/windows/awt_Container.cpp +++ b/src/windows/native/sun/windows/awt_Container.cpp @@ -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 @@ JNIEXPORT void JNICALL 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 --git a/src/windows/native/sun/windows/awt_Container.h b/src/windows/native/sun/windows/awt_Container.h index a1f244b219ab427aba1f277bd809dfd2a189d51a..88dc92d4351d6119e8265fb4a155175d7adf2c40 100644 --- a/src/windows/native/sun/windows/awt_Container.h +++ b/src/windows/native/sun/windows/awt_Container.h @@ -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 @@ class AwtContainer { public: /* java.awt.Container field ids */ - static jfieldID ncomponentsID; - static jfieldID componentID; static jfieldID layoutMgrID; static jmethodID findComponentAtMID; diff --git a/src/windows/native/sun/windows/awt_TextArea.cpp b/src/windows/native/sun/windows/awt_TextArea.cpp index 10a90ca08896d5e7099e985a41c36103ad5805b1..92a36b7a1a96ee8386cd88e2b6973ff382d44e97 100644 --- a/src/windows/native/sun/windows/awt_TextArea.cpp +++ b/src/windows/native/sun/windows/awt_TextArea.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 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 @@ -209,15 +209,13 @@ done: 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 @@ void AwtTextArea::_ReplaceText(void *param) 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 --git a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp index dc4d05efed8675848796395bcd6937dd54cd5b95..047f7148c1982b3ce03507fea3e68634805c5cec 100644 --- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp +++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp @@ -1021,6 +1021,10 @@ Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive( // 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 @@ Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive( ::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 --git a/src/windows/transport/socket/socket_md.c b/src/windows/transport/socket/socket_md.c index 622b9e2da38265e163101dedbba35ff885dbb862..b8bca54d6a0481f771d9b380e3035da60f02c2d3 100644 --- a/src/windows/transport/socket/socket_md.c +++ b/src/windows/transport/socket/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 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 diff --git a/src/windows/transport/socket/socket_md.h b/src/windows/transport/socket/socket_md.h index bbf9b3439b2db2c4ad22cd6b170126b66d7a30db..c2d01438f0d9baf530bc1303190d7ceac0545fb0 100644 --- a/src/windows/transport/socket/socket_md.h +++ b/src/windows/transport/socket/socket_md.h @@ -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 diff --git a/test/com/sun/jdi/ClassesByName2Test.java b/test/com/sun/jdi/ClassesByName2Test.java index 96df25d792d44ff0e24c41c38a4ea3ad60f25d13..438661a0e0b9c8f494cb1f5b9cc6ed9bdb8b8827 100644 --- a/test/com/sun/jdi/ClassesByName2Test.java +++ b/test/com/sun/jdi/ClassesByName2Test.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2003 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 @@ -41,8 +41,7 @@ import java.util.*; /********** target program **********/ class ClassesByName2Targ { - public static void ready() { - System.out.println("Ready!"); + static void bkpt() { } public static void main(String[] args){ @@ -74,22 +73,24 @@ class ClassesByName2Targ { } }; - ready(); - two.start(); one.start(); zero.start(); try { zero.join(); + System.out.println("zero joined"); one.join(); + System.out.println("one joined"); two.join(); + System.out.println("two joined"); } catch (InterruptedException iex) { iex.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } + bkpt(); System.out.println("Goodbye from ClassesByName2Targ!"); } } @@ -97,29 +98,64 @@ class ClassesByName2Targ { /********** test program **********/ public class ClassesByName2Test extends TestScaffold { + volatile boolean stop = false; ClassesByName2Test (String args[]) { super(args); } + public void breakpointReached(BreakpointEvent event) { + System.out.println("Got BreakpointEvent: " + event); + stop = true; + } + + public void eventSetComplete(EventSet set) { + // Don't resume. + } + public static void main(String[] args) throws Exception { new ClassesByName2Test(args).startTests(); } + void breakpointAtMethod(ReferenceType ref, String methodName) + throws Exception { + List meths = ref.methodsByName(methodName); + if (meths.size() != 1) { + throw new Exception("test error: should be one " + + methodName); + } + Method meth = (Method)meths.get(0); + BreakpointRequest bkptReq = vm().eventRequestManager(). + createBreakpointRequest(meth.location()); + bkptReq.enable(); + try { + addListener (this); + } catch (Exception ex){ + ex.printStackTrace(); + failure("failure: Could not add listener"); + throw new Exception("ClassesByname2Test: failed"); + } + } + protected void runTests() throws Exception { - /* - * Get to the top of ready() - */ - startTo("ClassesByName2Targ", "ready", "()V"); + BreakpointEvent bpe = startToMain("ClassesByName2Targ"); + /* + Bug 6263966 - Don't just resume because the debuggee can + complete and disconnect while the following loop is + accessing it. + */ + breakpointAtMethod(bpe.location().declaringType(), "bkpt"); vm().resume(); - int i = 0; - while (i < 8 && !vmDisconnected) { - i++; + /* The test of 'stop' is so that we stop when the debuggee hits + the bkpt. The 150 is so we stop if the debuggee + is slow (eg, -Xcomp -server) - we don't want to + spend all day waiting for it to get to the bkpt. + */ + for (int i = 0; i < 150 && !stop; i++) { List all = vm().allClasses(); - System.out.println(""); - System.out.println("++++ Lookup number: " + i + ". allClasses() returned " + + System.out.println("\n++++ Lookup number: " + i + ". allClasses() returned " + all.size() + " classes."); for (Iterator it = all.iterator(); it.hasNext(); ) { ReferenceType cls = (ReferenceType)it.next(); @@ -134,10 +170,10 @@ public class ClassesByName2Test extends TestScaffold { } } } - /* - * resume the target listening for events - */ - listenUntilVMDisconnect(); + + // In case of a slow debuggee, we don't want to resume the debuggee and wait + // for it to complete. + vm().exit(0); /* * deal with results of test diff --git a/test/com/sun/jdi/ConnectedVMs.java b/test/com/sun/jdi/ConnectedVMs.java index 549efcc9c9048f143a73e4016aa76a4bf3a57a5b..3b25392492e041742af9da5b4da77f8ab1a356ed 100644 --- a/test/com/sun/jdi/ConnectedVMs.java +++ b/test/com/sun/jdi/ConnectedVMs.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001 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 @@ -28,7 +28,10 @@ * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g InstTarg.java - * @run main ConnectedVMs InstTarg + * @run main ConnectedVMs "Kill" + * @run main ConnectedVMs "Resume to exit" + * @run main ConnectedVMs "dispose()" + * @run main ConnectedVMs "exit()" * * @summary ConnectedVMs checks the method * VirtualMachineManager.connectedVirtualMachines() @@ -40,14 +43,10 @@ import java.util.List; public class ConnectedVMs extends TestScaffold { static int failCount = 0;; - static int pass; - static String[] passNames = {"Kill", "Resume to exit", - "dispose()", "exit()"}; + static String passName; public static void main(String args[]) throws Exception { - for (pass=0; pass < passNames.length; pass++) { - new ConnectedVMs(args).startTests(); - } + new ConnectedVMs(args[0]).startTests(); if (failCount > 0) { throw new RuntimeException( "VirtualMachineManager.connectedVirtualMachines() " + @@ -58,16 +57,17 @@ public class ConnectedVMs extends TestScaffold { } } - ConnectedVMs(String args[]) throws Exception { - super(args); - System.out.println("create"); + ConnectedVMs(String name) throws Exception { + super(new String[0]); + passName = name; + System.out.println("create " + passName); } void vms(int expected) { List vms = Bootstrap.virtualMachineManager(). connectedVirtualMachines(); if (vms.size() != expected) { - System.out.println("FAILURE! " + passNames[pass] + + System.out.println("FAILURE! " + passName + " - expected: " + expected + ", got: " + vms.size()); ++failCount; @@ -75,27 +75,22 @@ public class ConnectedVMs extends TestScaffold { } protected void runTests() throws Exception { - System.out.println("Testing " + passNames[pass]); + System.out.println("Testing " + passName); vms(0); startToMain("InstTarg"); ThreadReference thread = waitForVMStart(); StepEvent stepEvent = stepIntoLine(thread); vms(1); - // pick a way to die - switch (pass) { - case 0: - vm().process().destroy(); - break; - case 1: - vm().resume(); - break; - case 2: - vm().dispose(); - break; - case 3: - vm().exit(1); - break; + // pick a way to die based on the input arg. + if (passName.equals("Kill")) { + vm().process().destroy(); + } else if (passName.equals("Resume to exit")) { + vm().resume(); + } else if (passName.equals("dispose()")) { + vm().dispose(); + } else if (passName.equals("exit()")) { + vm().exit(1); } resumeToVMDisconnect(); diff --git a/test/com/sun/jdi/MonitorFrameInfo.java b/test/com/sun/jdi/MonitorFrameInfo.java index 056428da20d3578252308ea857b573f17039828f..a58ddb7cdab945bdea7c0bdb7c57bdcdd79812e3 100644 --- a/test/com/sun/jdi/MonitorFrameInfo.java +++ b/test/com/sun/jdi/MonitorFrameInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/test/com/sun/jdi/Solaris32AndSolaris64Test.sh b/test/com/sun/jdi/Solaris32AndSolaris64Test.sh index 5ddb871b20b25e38a4053222fadbbbc03abe193d..c1b4491a706f33f824641a824161cd08da91f818 100644 --- a/test/com/sun/jdi/Solaris32AndSolaris64Test.sh +++ b/test/com/sun/jdi/Solaris32AndSolaris64Test.sh @@ -1,7 +1,7 @@ #!/bin/ksh -p # -# Copyright 2001-2006 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 @@ -25,7 +25,7 @@ # # @test Solaris32AndSolaris64Test.sh -# @bug 4478312 4780570 4913748 +# @bug 4478312 4780570 4913748 6730273 # @summary Test debugging with mixed 32/64bit VMs. # @author Tim Bell # Based on test/java/awt/TEMPLATE/AutomaticShellTest.sh @@ -177,8 +177,14 @@ filename=$TESTCLASSES/@debuggeeVMOptions if [ ! -r ${filename} ] ; then filename=$TESTCLASSES/../@debuggeeVMOptions fi +# Remove -d32, -d64 if present, and remove -XX:[+-]UseCompressedOops +# if present since it is illegal in 32 bit mode. if [ -r ${filename} ] ; then - DEBUGGEEFLAGS=`cat ${filename} | sed -e 's/-d32//g' -e 's/-d64//g'` + DEBUGGEEFLAGS=`cat ${filename} | sed \ + -e 's/-d32//g' \ + -e 's/-d64//g' \ + -e 's/-XX:.UseCompressedOops//g' \ + ` fi # diff --git a/test/com/sun/jdi/SourceNameFilterTest.java b/test/com/sun/jdi/SourceNameFilterTest.java index cb8260646f092aef59135edcc1bbfaf80085d4e7..42b1e9495111028d29968826d3e380eafd78b676 100644 --- a/test/com/sun/jdi/SourceNameFilterTest.java +++ b/test/com/sun/jdi/SourceNameFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 diff --git a/test/com/sun/jdi/VMConnection.java b/test/com/sun/jdi/VMConnection.java index c9cb83f72577646e6a9a9f38597e695ffa87e34a..5d5f9e13bb679b7f94e47c2fa816c5d30af091f0 100644 --- a/test/com/sun/jdi/VMConnection.java +++ b/test/com/sun/jdi/VMConnection.java @@ -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 diff --git a/test/com/sun/jdi/sde/MangleStepTest.java b/test/com/sun/jdi/sde/MangleStepTest.java index 7a1a12c2f02cc2138e31e496d1527966960d9159..ca10e27b7dc4014418013c0c0a19ce9663b78e49 100644 --- a/test/com/sun/jdi/sde/MangleStepTest.java +++ b/test/com/sun/jdi/sde/MangleStepTest.java @@ -10,7 +10,11 @@ * @run build TestScaffold VMConnection TargetListener TargetAdapter InstallSDE * @run compile MangleStepTest.java * @run compile -g onion/pickle/Mangle.java - * @run main MangleStepTest unset Java XYZ Rats bogus + * @run main MangleStepTest unset + * @run main MangleStepTest Java + * @run main MangleStepTest XYZ + * @run main MangleStepTest Rats + * @run main MangleStepTest bogus */ import com.sun.jdi.*; import com.sun.jdi.event.*; @@ -32,9 +36,7 @@ public class MangleStepTest extends TestScaffold { public static void main(String[] args) throws Exception { testSetUp(); - for (int i = 0; i < args.length; ++i) { - new MangleStepTest(args[i]).startTests(); - } + new MangleStepTest(args[0]).startTests(); if (aTestFailed) { throw new Exception("MangleStepTest: failed"); } diff --git a/test/com/sun/net/httpserver/bugs/B6744329.java b/test/com/sun/net/httpserver/bugs/B6744329.java new file mode 100644 index 0000000000000000000000000000000000000000..9a783845e2c4cfaed363b5182dd25c85fc4d2356 --- /dev/null +++ b/test/com/sun/net/httpserver/bugs/B6744329.java @@ -0,0 +1,106 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along 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 B6744329 + * @summary Exception in light weight Http server + */ + +import com.sun.net.httpserver.*; + +import java.util.*; +import java.util.concurrent.*; +import java.io.*; +import java.net.*; +import java.security.*; +import java.security.cert.*; +import javax.net.ssl.*; + +public class B6744329 { + + public static void main (String[] args) throws Exception { + Handler handler = new Handler(); + InetSocketAddress addr = new InetSocketAddress (0); + HttpServer server = HttpServer.create (addr, 0); + HttpContext ctx = server.createContext ("/test", handler); + ExecutorService executor = Executors.newCachedThreadPool(); + server.setExecutor (executor); + server.start (); + + URL url = new URL ("http://localhost:"+server.getAddress().getPort()+"/test/foo.html"); + HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); + try { + InputStream is = urlc.getInputStream(); + int c = 0; + while (is.read()!= -1) { + c ++; + } + System.out.println ("OK"); + } catch (IOException e) { + System.out.println ("exception"); + error = true; + } + server.stop(2); + executor.shutdown(); + if (error) { + throw new RuntimeException ("Test failed"); + } + } + + public static boolean error = false; + + /* this must be the same size as in ChunkedOutputStream.java + */ + final static int CHUNK_SIZE = 4096; + + static class Handler implements HttpHandler { + int invocation = 1; + public void handle (HttpExchange t) + throws IOException + { + InputStream is = t.getRequestBody(); + Headers map = t.getRequestHeaders(); + Headers rmap = t.getResponseHeaders(); + while (is.read () != -1) ; + is.close(); + /* chunked response */ + t.sendResponseHeaders (200, 0); + OutputStream os = t.getResponseBody(); + byte[] first = new byte [CHUNK_SIZE * 2]; + byte[] second = new byte [2]; + os.write (first); + os.write ('x'); + os.write ('x'); + /* An index out of bounds exception will be thrown + * below, which is caught by server, and connection + * will be closed. resulting in IOException to client + * - if bug present + */ + os.write ('x'); + os.write ('x'); + os.write ('x'); + t.close(); + } + } +} diff --git a/test/com/sun/tools/extcheck/TestExtcheckArgs.java b/test/com/sun/tools/extcheck/TestExtcheckArgs.java new file mode 100644 index 0000000000000000000000000000000000000000..0e5514b875aaa40677e7c77d4a7831657b8bd4a0 --- /dev/null +++ b/test/com/sun/tools/extcheck/TestExtcheckArgs.java @@ -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 --git a/test/com/sun/tools/extcheck/TestExtcheckArgs.sh b/test/com/sun/tools/extcheck/TestExtcheckArgs.sh new file mode 100644 index 0000000000000000000000000000000000000000..3c478c1e13df00180c616b30092819059d4816da --- /dev/null +++ b/test/com/sun/tools/extcheck/TestExtcheckArgs.sh @@ -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 --git a/test/java/awt/Container/CheckZOrderChange/CheckZOrderChange.java b/test/java/awt/Container/CheckZOrderChange/CheckZOrderChange.java new file mode 100644 index 0000000000000000000000000000000000000000..0814b52b25d383d5ef9ed3cdaf504a0099672102 --- /dev/null +++ b/test/java/awt/Container/CheckZOrderChange/CheckZOrderChange.java @@ -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 --git a/test/java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java b/test/java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b4bcdccfda01e6259a3b5fa41964e1ee08e456c8 --- /dev/null +++ b/test/java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java @@ -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 --git a/test/java/awt/Focus/RequestFocusToDisabledCompTest/RequestFocusToDisabledCompTest.java b/test/java/awt/Focus/RequestFocusToDisabledCompTest/RequestFocusToDisabledCompTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b86a792f42c5d9ba444cbf4f8b7e349580358e97 --- /dev/null +++ b/test/java/awt/Focus/RequestFocusToDisabledCompTest/RequestFocusToDisabledCompTest.java @@ -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 --git a/test/java/awt/Mixing/Validating.java b/test/java/awt/Mixing/Validating.java new file mode 100644 index 0000000000000000000000000000000000000000..a103def156b62a9262fed9468375b91d28546f1d --- /dev/null +++ b/test/java/awt/Mixing/Validating.java @@ -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 --git a/test/java/awt/Toolkit/HeadlessTray/HeadlessTray.java b/test/java/awt/Toolkit/HeadlessTray/HeadlessTray.java new file mode 100644 index 0000000000000000000000000000000000000000..2045052f68aab7aff90d5f9961318af509fd9153 --- /dev/null +++ b/test/java/awt/Toolkit/HeadlessTray/HeadlessTray.java @@ -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 --git a/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java b/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java index 45f57c57621210050b64fa8c16ae3e6c1fc8dcb7..a003c53df99a9163148a04ab5db6f8a723214033 100644 --- a/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java +++ b/test/java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java @@ -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 @@ public class SpuriousExitEnter_2 { 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 --git a/test/java/awt/regtesthelpers/Util.java b/test/java/awt/regtesthelpers/Util.java index bdabff33d373be9bbc37bb85feedeffd727576b6..e1c165912d1f470569c13e85e2baa9174abf96d6 100644 --- a/test/java/awt/regtesthelpers/Util.java +++ b/test/java/awt/regtesthelpers/Util.java @@ -123,6 +123,14 @@ public final class Util { throw new RuntimeException("Unexpected toolkit - " + tk); } + /** + * 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 final class Util { 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 --git a/test/java/lang/ThreadGroup/NullThreadName.java b/test/java/lang/ThreadGroup/NullThreadName.java new file mode 100644 index 0000000000000000000000000000000000000000..844fd93e2d815903b4994540027c76c95d0711cc --- /dev/null +++ b/test/java/lang/ThreadGroup/NullThreadName.java @@ -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 --git a/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java b/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java index f76794f407c42318b4feb5b02457178cef13aeac..75cee8fedbcb7cd831a9139f43269d8c3aa73c2f 100644 --- a/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java +++ b/test/java/lang/management/ManagementFactory/ThreadMXBeanProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -60,8 +60,8 @@ public class ThreadMXBeanProxy { thread.setDaemon(true); thread.start(); - // wait until myThread acquires mutex - while (!mutex.isLocked()) { + // wait until myThread acquires mutex and lock owner is set. + while (!(mutex.isLocked() && mutex.getLockOwner() == thread)) { try { Thread.sleep(100); } catch (InterruptedException e) { @@ -73,17 +73,17 @@ public class ThreadMXBeanProxy { // validate the local access ThreadInfo[] infos = getThreadMXBean().getThreadInfo(ids, true, true); - if (ids.length != 1) { + if (infos.length != 1) { throw new RuntimeException("Returned ThreadInfo[] of length=" + - ids.length + ". Expected to be 1."); + infos.length + ". Expected to be 1."); } thread.checkThreadInfo(infos[0]); // validate the remote access infos = mbean.getThreadInfo(ids, true, true); - if (ids.length != 1) { + if (infos.length != 1) { throw new RuntimeException("Returned ThreadInfo[] of length=" + - ids.length + ". Expected to be 1."); + infos.length + ". Expected to be 1."); } thread.checkThreadInfo(infos[0]); @@ -160,8 +160,7 @@ public class ThreadMXBeanProxy { LockInfo[] syncs = info.getLockedSynchronizers(); if (syncs.length != OWNED_SYNCS) { throw new RuntimeException("Number of locked syncs = " + - syncs.length + - " not matched. Expected: " + OWNED_SYNCS); + syncs.length + " not matched. Expected: " + OWNED_SYNCS); } AbstractOwnableSynchronizer s = mutex.getSync(); String lockName = s.getClass().getName(); @@ -174,7 +173,6 @@ public class ThreadMXBeanProxy { throw new RuntimeException("LockInfo: " + syncs[0] + " IdentityHashCode not matched. Expected: " + hcode); } - } } static class Mutex implements Lock, java.io.Serializable { @@ -214,6 +212,10 @@ public class ThreadMXBeanProxy { s.defaultReadObject(); setState(0); // reset to unlocked state } + + protected Thread getLockOwner() { + return getExclusiveOwnerThread(); + } } // The sync object does all the hard work. We just forward to it. @@ -232,6 +234,8 @@ public class ThreadMXBeanProxy { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } + public Thread getLockOwner() { return sync.getLockOwner(); } + public AbstractOwnableSynchronizer getSync() { return sync; } } } diff --git a/test/java/lang/management/ThreadMXBean/Locks.java b/test/java/lang/management/ThreadMXBean/Locks.java index 9819375d117006d2eb7d38e8cf4e51c1e656cc41..694a862c6f3a011d9c23b7f9c6bf7e0076f7a8fc 100644 --- a/test/java/lang/management/ThreadMXBean/Locks.java +++ b/test/java/lang/management/ThreadMXBean/Locks.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -197,8 +197,12 @@ public class Locks { synchronized (ready) { // wait until WaitingThread about to wait for objC thrsync.waitForSignal(); - // give chance to enter wait. - goSleep(100); + + int retryCount = 0; + while (waiter.getState() != Thread.State.WAITING + && retryCount++ < 500) { + goSleep(100); + } checkBlockedObject(waiter, objC, null, Thread.State.WAITING); synchronized (objC) { diff --git a/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java b/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java new file mode 100644 index 0000000000000000000000000000000000000000..63cb15a0c52761c15d391951a1c16ff9924ddd7f --- /dev/null +++ b/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java @@ -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 --git a/test/java/net/CookieHandler/TestHttpCookie.java b/test/java/net/CookieHandler/TestHttpCookie.java index c62722704addd993d43ae665ce6eca93b2e5f7de..43d5484e27cd954a965822225c9c4b03df67caca 100644 --- a/test/java/net/CookieHandler/TestHttpCookie.java +++ b/test/java/net/CookieHandler/TestHttpCookie.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -24,7 +24,7 @@ /** * @test * @summary Unit test for java.net.HttpCookie - * @bug 6244040 6277796 6277801 6277808 6294071 + * @bug 6244040 6277796 6277801 6277808 6294071 6692802 * @author Edward Wang */ @@ -178,6 +178,19 @@ public class TestHttpCookie { } TestHttpCookie port(String p) { return port(0, p); } + // check http only + TestHttpCookie httpOnly(int index, boolean b) { + HttpCookie cookie = cookies.get(index); + if (cookie == null || b != cookie.isHttpOnly()) { + raiseError("HttpOnly", String.valueOf(cookie.isHttpOnly()), String.valueOf(b)); + } + return this; + } + + TestHttpCookie httpOnly(boolean b) { + return httpOnly(0, b); + } + // check equality static void eq(HttpCookie ck1, HttpCookie ck2, boolean same) { testCount++; @@ -362,6 +375,10 @@ public class TestHttpCookie { } catch (IllegalArgumentException ignored) { // expected exception; no-op } + + // CR 6692802: HttpOnly flag + test("set-cookie: CUSTOMER=WILE_E_COYOTE;HttpOnly").httpOnly(true); + test("set-cookie: CUSTOMER=WILE_E_COYOTE").httpOnly(false); } static void header(String prompt) { diff --git a/test/java/net/Inet6Address/serialize/Serialize.java b/test/java/net/Inet6Address/serialize/Serialize.java index 17b5500576c63cf959bc29897f50f68b2b3209d9..b3511ee91144de5f157c1b119f789920383ab493 100644 --- a/test/java/net/Inet6Address/serialize/Serialize.java +++ b/test/java/net/Inet6Address/serialize/Serialize.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/java/net/NetworkInterface/IndexTest.java b/test/java/net/NetworkInterface/IndexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd6e4780dcfffebe4cd18520809cb791b68f6591 --- /dev/null +++ b/test/java/net/NetworkInterface/IndexTest.java @@ -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 6717876 + * @summary Make java.net.NetworkInterface.getIndex() public + */ + +import java.net.*; +import java.util.Enumeration; + +public class IndexTest { + public static void main(String[] args) throws Exception { + Enumeration netifs = NetworkInterface.getNetworkInterfaces(); + NetworkInterface nif = null; + while (netifs.hasMoreElements()) { + nif = netifs.nextElement(); + int index = nif.getIndex(); + if (index >= 0) { + NetworkInterface nif2 = NetworkInterface.getByIndex(index); + if (! nif.equals(nif2)) { + throw new RuntimeException("both interfaces should be equal"); + } + } + } + try { + nif = NetworkInterface.getByIndex(-1); + throw new RuntimeException("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // OK + } + // In all likelyhood, this interface should not exist. + nif = NetworkInterface.getByIndex(Integer.MAX_VALUE - 1); + if (nif != null) { + throw new RuntimeException("getByIndex() should have returned null"); + } + } +} diff --git a/test/java/nio/BufferPoolMXBean/Basic.java b/test/java/nio/BufferPoolMXBean/Basic.java new file mode 100644 index 0000000000000000000000000000000000000000..98e5f0e0bd9ba0c136711db0fe1ccc09b33e48a5 --- /dev/null +++ b/test/java/nio/BufferPoolMXBean/Basic.java @@ -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 --git a/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java new file mode 100644 index 0000000000000000000000000000000000000000..03b5daa68f10126f1675fbe68fece8ced9ce3b03 --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java @@ -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 --git a/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java new file mode 100644 index 0000000000000000000000000000000000000000..11e3b0be068c28d59baf9e60177dc88a543f6e9d --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java @@ -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 --git a/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..f1d7d5debc6f75fc9a27b44156857ac3c4b568f2 --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java @@ -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 --git a/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..e4e85b11fb45a9c05045cc2ed571bc6bfe7172fc --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -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 --git a/test/java/nio/channels/FileChannel/ExpandingMap.java b/test/java/nio/channels/FileChannel/ExpandingMap.java index 278badb970212c7518036926d66fe723a9afe84d..24820fd3a591db9e357a88275a7b7dd75310c1c1 100644 --- a/test/java/nio/channels/FileChannel/ExpandingMap.java +++ b/test/java/nio/channels/FileChannel/ExpandingMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/java/nio/channels/Selector/Wakeup.java b/test/java/nio/channels/Selector/Wakeup.java index 808ba831653322920e9d6aef3dccbea501a9e6b3..d4fa2493b2ecea91bb24c29799508a5956b2f7b7 100644 --- a/test/java/nio/channels/Selector/Wakeup.java +++ b/test/java/nio/channels/Selector/Wakeup.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2003 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 diff --git a/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..6c4a443ed0af23949405e9e17f084c20332fe5dd --- /dev/null +++ b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -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 --git a/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/test/java/nio/channels/SocketChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..b6fadced8e28c69ed078dd4609f75b5f8ecc429b --- /dev/null +++ b/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -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 --git a/test/java/nio/channels/TestUtil.java b/test/java/nio/channels/TestUtil.java index 63e8537eadf75577f3e5af1897d69bed48d49ab1..8a8449e0043332de2d866d91bb7daaffe4bcc901 100644 --- a/test/java/nio/channels/TestUtil.java +++ b/test/java/nio/channels/TestUtil.java @@ -38,7 +38,7 @@ public class TestUtil { // 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 @@ public class TestUtil { static boolean onWindows() { return osName.startsWith("Windows"); } - } diff --git a/test/java/nio/channels/etc/NetworkChannelTests.java b/test/java/nio/channels/etc/NetworkChannelTests.java new file mode 100644 index 0000000000000000000000000000000000000000..5f03453ca11aba193c5c0f8299f6b589956f4ea9 --- /dev/null +++ b/test/java/nio/channels/etc/NetworkChannelTests.java @@ -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 --git a/test/java/security/cert/CertPathValidator/nameConstraintsRFC822/ValidateCertPath.java b/test/java/security/cert/CertPathValidator/nameConstraintsRFC822/ValidateCertPath.java index d610262731917693d9def56ce25a1c7eba5e42f1..b2666a3105d5f1a7233b4c0964af4e3c3607e563 100644 --- a/test/java/security/cert/CertPathValidator/nameConstraintsRFC822/ValidateCertPath.java +++ b/test/java/security/cert/CertPathValidator/nameConstraintsRFC822/ValidateCertPath.java @@ -1,5 +1,5 @@ /* - * Copyright 2002 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 @@ -34,6 +34,7 @@ import java.io.InputStream; import java.io.IOException; import java.security.cert.*; +import java.security.cert.PKIXReason; import java.util.ArrayList; import java.util.Collections; @@ -69,6 +70,9 @@ public final class ValidateCertPath { validate(path, params); throw new Exception("Successfully validated invalid path."); } catch (CertPathValidatorException e) { + if (e.getReason() != PKIXReason.INVALID_NAME) { + throw new Exception("unexpected reason: " + e.getReason()); + } System.out.println("Path rejected as expected: " + e); } } @@ -86,14 +90,14 @@ public final class ValidateCertPath { args = new String[] {"jane2jane.cer", "jane2steve.cer", "steve2tom.cer"}; TrustAnchor anchor = new TrustAnchor(getCertFromFile(args[0]), null); - List list = new ArrayList(); + List list = new ArrayList(); for (int i = 1; i < args.length; i++) { list.add(0, getCertFromFile(args[i])); } CertificateFactory cf = CertificateFactory.getInstance("X509"); path = cf.generateCertPath(list); - Set anchors = Collections.singleton(anchor); + Set anchors = Collections.singleton(anchor); params = new PKIXParameters(anchors); params.setRevocationEnabled(false); } diff --git a/test/java/security/cert/CertPathValidatorException/ReasonTest.java b/test/java/security/cert/CertPathValidatorException/ReasonTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3702893ea2a28c7cf7aca76bf9da7de7d071116f --- /dev/null +++ b/test/java/security/cert/CertPathValidatorException/ReasonTest.java @@ -0,0 +1,67 @@ +/* + * 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 6465942 + * @summary unit test for CertPathValidatorException.Reason + */ + +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; + +public class ReasonTest { + private static volatile boolean failed = false; + public static void main(String[] args) throws Exception { + + // check that getReason returns UNSPECIFIED if reason not specified + CertPathValidatorException cpve = new CertPathValidatorException("abc"); + if (cpve.getReason() != BasicReason.UNSPECIFIED) { + failed = true; + System.err.println("FAILED: unexpected reason: " + cpve.getReason()); + } + + // check that getReason returns specified reason + cpve = new CertPathValidatorException + ("abc", null, null, -1, BasicReason.REVOKED); + if (cpve.getReason() != BasicReason.REVOKED) { + failed = true; + System.err.println("FAILED: unexpected reason: " + cpve.getReason()); + } + + // check that ctor throws NPE when reason is null + try { + cpve = new CertPathValidatorException("abc", null, null, -1, null); + failed = true; + System.err.println("ctor did not throw NPE for null reason"); + } catch (Exception e) { + if (!(e instanceof NullPointerException)) { + failed = true; + System.err.println("FAILED: unexpected exception: " + e); + } + } + if (failed) { + throw new Exception("Some tests FAILED"); + } + } +} diff --git a/test/java/security/cert/CertPathValidatorException/Serial.java b/test/java/security/cert/CertPathValidatorException/Serial.java new file mode 100644 index 0000000000000000000000000000000000000000..a6ffd3b4cd41bfec5a02f8b59d3c16ea806c5f9a --- /dev/null +++ b/test/java/security/cert/CertPathValidatorException/Serial.java @@ -0,0 +1,113 @@ +/* + * 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 6465942 + * @summary Test deserialization of CertPathValidatorException + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +//import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; +import java.util.Collections; + +/** + * This class tests to see if CertPathValidatorException can be serialized and + * deserialized properly. + */ +public class Serial { + private static volatile boolean failed = false; + public static void main(String[] args) throws Exception { + + File f = new File(System.getProperty("test.src", "."), "cert_file"); + FileInputStream fis = new FileInputStream(f); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate c = cf.generateCertificate(fis); + fis.close(); + CertPath cp = cf.generateCertPath(Collections.singletonList(c)); + + CertPathValidatorException cpve1 = + new CertPathValidatorException + ("Test", new Exception("Expired"), cp, 0, BasicReason.EXPIRED); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); +// FileOutputStream fos = new FileOutputStream("jdk7.serial"); + ObjectOutputStream oos = new ObjectOutputStream(baos); +// ObjectOutputStream foos = new ObjectOutputStream(fos); + oos.writeObject(cpve1); +// foos.writeObject(cpve1); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + CertPathValidatorException cpve2 = + (CertPathValidatorException) ois.readObject(); + check(!cpve1.getMessage().equals(cpve2.getMessage()), + "CertPathValidatorException messages not equal"); + check(!cpve1.getCause().getMessage().equals(cpve2.getCause().getMessage()), + "CertPathValidatorException causes not equal"); + check(!cpve1.getCertPath().equals(cpve2.getCertPath()), + "CertPathValidatorException certpaths not equal"); + check(cpve1.getIndex() != cpve2.getIndex(), + "CertPathValidatorException indexes not equal"); + check(cpve1.getReason() != cpve2.getReason(), + "CertPathValidatorException reasons not equal"); + oos.close(); + ois.close(); + + f = new File(System.getProperty("test.src", "."), "jdk6.serial"); + fis = new FileInputStream(f); + ois = new ObjectInputStream(fis); + cpve2 = (CertPathValidatorException) ois.readObject(); + check(!cpve1.getMessage().equals(cpve2.getMessage()), + "CertPathValidatorException messages not equal"); + check(!cpve1.getCause().getMessage().equals(cpve2.getCause().getMessage()), + "CertPathValidatorException causes not equal"); + check(!cpve1.getCertPath().equals(cpve2.getCertPath()), + "CertPathValidatorException certpaths not equal"); + check(cpve1.getIndex() != cpve2.getIndex(), + "CertPathValidatorException indexes not equal"); +// System.out.println(cpve2.getReason()); + check(cpve2.getReason() != BasicReason.UNSPECIFIED, + "CertPathValidatorException reasons not equal"); + oos.close(); + ois.close(); + if (failed) { + throw new Exception("Some tests FAILED"); + } + } + + private static void check(boolean expr, String message) { + if (expr) { + failed = true; + System.err.println("FAILED: " + message); + } + } +} diff --git a/test/java/security/cert/CertPathValidatorException/cert_file b/test/java/security/cert/CertPathValidatorException/cert_file new file mode 100644 index 0000000000000000000000000000000000000000..42af97b376221127bc892d2479e53655ac768b8b Binary files /dev/null and b/test/java/security/cert/CertPathValidatorException/cert_file differ diff --git a/test/java/security/cert/CertPathValidatorException/jdk6.serial b/test/java/security/cert/CertPathValidatorException/jdk6.serial new file mode 100644 index 0000000000000000000000000000000000000000..b76d0709c42bf1c9b75821f4434c3dd99aa9d787 Binary files /dev/null and b/test/java/security/cert/CertPathValidatorException/jdk6.serial differ diff --git a/test/java/security/cert/PolicyNode/GetPolicyQualifiers.java b/test/java/security/cert/PolicyNode/GetPolicyQualifiers.java index 0ef95a0a700910cc88aedabca9a9b6a61a00dd0a..b10951bab77e406bd4fd8035cc8e567ee60a4137 100644 --- a/test/java/security/cert/PolicyNode/GetPolicyQualifiers.java +++ b/test/java/security/cert/PolicyNode/GetPolicyQualifiers.java @@ -1,5 +1,5 @@ /* - * Copyright 2001 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 @@ -74,6 +74,10 @@ public class GetPolicyQualifiers { throw new Exception("Validation of CertPath containing critical " + "qualifiers should have failed when policyQualifiersRejected " + "flag is true"); - } catch (CertPathValidatorException cpve) {} + } catch (CertPathValidatorException cpve) { + if (cpve.getReason() != PKIXReason.INVALID_POLICY) { + throw new Exception("unexpected reason: " + cpve.getReason()); + } + } } } diff --git a/test/java/util/EnumSet/BogusEnumSet.java b/test/java/util/EnumSet/BogusEnumSet.java new file mode 100644 index 0000000000000000000000000000000000000000..3fcb0a7895d9d5d499221cafc58ff0bbff562d25 --- /dev/null +++ b/test/java/util/EnumSet/BogusEnumSet.java @@ -0,0 +1,93 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along 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 6739302 + * @summary Check that deserialization preserves EnumSet integrity + * @author Josh Bloch + */ + +import java.util.*; +import java.io.*; + +public class BogusEnumSet { + public static void main(String[] args) throws Throwable { + byte[] serializedForm = { + (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18, + 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, + 0x6c, 0x2e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, + 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0x2f, 0x58, 0x6f, (byte)0xc7, + 0x7e, (byte)0xb0, (byte)0xd0, 0x7e, 0x2, 0x0, 0x1, 0x4a, 0x0, 0x8, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x78, 0x72, 0x0, + 0x11, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, + 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0xe, + 0x3, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2, + 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76, + 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x3b, 0x5b, 0x0, 0x8, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x65, 0x74, 0x0, 0x11, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, + 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x45, 0x6e, 0x75, 0x6d, 0x3b, + 0x78, 0x70, 0x76, 0x72, 0x0, 0x16, 0x6a, 0x61, 0x76, 0x61, 0x2e, + 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78, 0x72, 0x0, 0xe, 0x6a, 0x61, + 0x76, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x45, 0x6e, 0x75, + 0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78, + 0x70, 0x75, 0x72, 0x0, 0x19, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, + 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3b, 0x68, (byte)0xa3, + (byte)0xb5, (byte)0xd5, 0x11, 0x7d, 0x1b, (byte)0xb3, 0x2, 0x0, + 0x0, 0x78, 0x70, 0x0, 0x0, 0x0, 0x6, 0x7e, 0x71, 0x0, 0x7e, 0x0, + 0x5, 0x74, 0x0, 0x3, 0x4e, 0x45, 0x57, 0x7e, 0x71, 0x0, 0x7e, 0x0, + 0x5, 0x74, 0x0, 0x8, 0x52, 0x55, 0x4e, 0x4e, 0x41, 0x42, 0x4c, 0x45, + 0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0, 0x7, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x45, 0x44, 0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0, + 0x7, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0, + 0x7e, 0x0, 0x5, 0x74, 0x0, 0xd, 0x54, 0x49, 0x4d, 0x45, 0x44, + 0x5f, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0, + 0x7e, 0x0, 0x5, 0x74, 0x0, 0xa, 0x54, 0x45, 0x52, 0x4d, 0x49, + 0x4e, 0x41, 0x54, 0x45, 0x44, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff + }; + + try { + // Should fail, but instead creates corrupt EnumSet + @SuppressWarnings("unchecked") + EnumSet es = (EnumSet) + deserialize(serializedForm); + + // Demonstrates corruption + System.out.println("Enum size: " + Thread.State.values().length); // 6 + System.out.println("Set size: " + es.size()); // 64 + System.out.println("Set: " + es); // Throws IndexOutOfBoundsException + throw new AssertionError("Expected exception InvalidObjectException not thrown"); + } catch (java.io.InvalidObjectException _) { /* OK */ } + } + + private static Object deserialize(byte[] sf) throws Throwable { + return new ObjectInputStream( + new ByteArrayInputStream(sf)) + .readObject(); + } +} diff --git a/test/java/util/Timer/DelayOverflow.java b/test/java/util/Timer/DelayOverflow.java new file mode 100644 index 0000000000000000000000000000000000000000..96e45d18f197db711c8c8fa12a74408b60b0ce13 --- /dev/null +++ b/test/java/util/Timer/DelayOverflow.java @@ -0,0 +1,115 @@ +/* + * 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 6730507 + * @summary java.util.Timer schedule delay Long.MAX_VALUE causes task to execute multiple times + * @author Chris Hegarty + * @author Martin Buchholz + */ + +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class DelayOverflow +{ + void scheduleNow(Timer timer, TimerTask task, int how) { + switch (how) { + case 0 : + timer.schedule(task, new Date(), Long.MAX_VALUE); + break; + case 1: + timer.schedule(task, 0L, Long.MAX_VALUE); + break; + case 2: + timer.scheduleAtFixedRate(task, new Date(), Long.MAX_VALUE); + break; + case 3: + timer.scheduleAtFixedRate(task, 0L, Long.MAX_VALUE); + break; + default: + fail(String.valueOf(how)); + } + } + + void sleep(long millis) { + try { Thread.sleep(millis); } + catch (Throwable t) { unexpected(t); } + } + + /** Checks that scheduledExecutionTime returns a "recent" time. */ + void checkScheduledExecutionTime(TimerTask task) { + long t = System.currentTimeMillis() + - task.scheduledExecutionTime(); + check(t >= 0 && t < 1000 * 600); + } + + void test(String[] args) throws Throwable { + for (int how=0; how<4; how++) { + final CountDownLatch done = new CountDownLatch(1); + final AtomicInteger count = new AtomicInteger(0); + final Timer timer = new Timer(); + final TimerTask task = new TimerTask() { + @Override + public void run() { + checkScheduledExecutionTime(this); + count.incrementAndGet(); + done.countDown(); + }}; + + scheduleNow(timer, task, how); + done.await(); + equal(count.get(), 1); + checkScheduledExecutionTime(task); + if (new java.util.Random().nextBoolean()) + sleep(10); + check(task.cancel()); + timer.cancel(); + checkScheduledExecutionTime(task); + } + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + Class k = new Object(){}.getClass().getEnclosingClass(); + try {k.getMethod("instanceMain",String[].class) + .invoke( k.newInstance(), (Object) args);} + catch (Throwable e) {throw e.getCause();}} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java b/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java new file mode 100644 index 0000000000000000000000000000000000000000..9df0235ec8f5f7c325d2355a77916311816e09d0 --- /dev/null +++ b/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java @@ -0,0 +1,161 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along 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 6725789 + * @summary Check for long overflow in task time comparison. + */ + +import java.util.concurrent.*; + +public class DelayOverflow { + static void waitForNanoTimeTick() { + for (long t0 = System.nanoTime(); t0 == System.nanoTime(); ) + ; + } + + void scheduleNow(ScheduledThreadPoolExecutor pool, + Runnable r, int how) { + switch (how) { + case 0: + pool.schedule(r, 0, TimeUnit.MILLISECONDS); + break; + case 1: + pool.schedule(Executors.callable(r), 0, TimeUnit.DAYS); + break; + case 2: + pool.scheduleWithFixedDelay(r, 0, 1000, TimeUnit.NANOSECONDS); + break; + case 3: + pool.scheduleAtFixedRate(r, 0, 1000, TimeUnit.MILLISECONDS); + break; + default: + fail(String.valueOf(how)); + } + } + + void scheduleAtTheEndOfTime(ScheduledThreadPoolExecutor pool, + Runnable r, int how) { + switch (how) { + case 0: + pool.schedule(r, Long.MAX_VALUE, TimeUnit.MILLISECONDS); + break; + case 1: + pool.schedule(Executors.callable(r), Long.MAX_VALUE, TimeUnit.DAYS); + break; + case 2: + pool.scheduleWithFixedDelay(r, Long.MAX_VALUE, 1000, TimeUnit.NANOSECONDS); + break; + case 3: + pool.scheduleAtFixedRate(r, Long.MAX_VALUE, 1000, TimeUnit.MILLISECONDS); + break; + default: + fail(String.valueOf(how)); + } + } + + /** + * Attempts to test exhaustively and deterministically, all 20 + * possible ways that one task can be scheduled in the maximal + * distant future, while at the same time an existing tasks's time + * has already expired. + */ + void test(String[] args) throws Throwable { + for (int nowHow = 0; nowHow < 4; nowHow++) { + for (int thenHow = 0; thenHow < 4; thenHow++) { + + final ScheduledThreadPoolExecutor pool + = new ScheduledThreadPoolExecutor(1); + final CountDownLatch runLatch = new CountDownLatch(1); + final CountDownLatch busyLatch = new CountDownLatch(1); + final CountDownLatch proceedLatch = new CountDownLatch(1); + final Runnable notifier = new Runnable() { + public void run() { runLatch.countDown(); }}; + final Runnable neverRuns = new Runnable() { + public void run() { fail(); }}; + final Runnable keepPoolBusy = new Runnable() { + public void run() { + try { + busyLatch.countDown(); + proceedLatch.await(); + } catch (Throwable t) { unexpected(t); } + }}; + pool.schedule(keepPoolBusy, 0, TimeUnit.SECONDS); + busyLatch.await(); + scheduleNow(pool, notifier, nowHow); + waitForNanoTimeTick(); + scheduleAtTheEndOfTime(pool, neverRuns, thenHow); + proceedLatch.countDown(); + + check(runLatch.await(10L, TimeUnit.SECONDS)); + equal(runLatch.getCount(), 0L); + + pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + pool.shutdown(); + } + + final int nowHowCopy = nowHow; + final ScheduledThreadPoolExecutor pool + = new ScheduledThreadPoolExecutor(1); + final CountDownLatch runLatch = new CountDownLatch(1); + final Runnable notifier = new Runnable() { + public void run() { runLatch.countDown(); }}; + final Runnable scheduleNowScheduler = new Runnable() { + public void run() { + try { + scheduleNow(pool, notifier, nowHowCopy); + waitForNanoTimeTick(); + } catch (Throwable t) { unexpected(t); } + }}; + pool.scheduleWithFixedDelay(scheduleNowScheduler, + 0, Long.MAX_VALUE, + TimeUnit.NANOSECONDS); + + check(runLatch.await(10L, TimeUnit.SECONDS)); + equal(runLatch.getCount(), 0L); + + pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + pool.shutdown(); + } + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + Class k = new Object(){}.getClass().getEnclosingClass(); + try {k.getMethod("instanceMain",String[].class) + .invoke( k.newInstance(), (Object) args);} + catch (Throwable e) {throw e.getCause();}} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/test/java/util/zip/TestEmptyZip.java b/test/java/util/zip/TestEmptyZip.java new file mode 100644 index 0000000000000000000000000000000000000000..d19dee4d4469d4c233a36a066570fd4ce6b95319 --- /dev/null +++ b/test/java/util/zip/TestEmptyZip.java @@ -0,0 +1,147 @@ +/* + * 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 6334003 6440786 + * @summary Test ability to write and read zip files that have no entries. + * @author Dave Bristor + */ + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +public class TestEmptyZip { + public static void realMain(String[] args) throws Throwable { + String zipName = "foo.zip"; + File f = new File(System.getProperty("test.scratch", "."), zipName); + if (f.exists() && !f.delete()) { + throw new Exception("failed to delete " + zipName); + } + + // Verify 0-length file cannot be read + f.createNewFile(); + ZipFile zf = null; + try { + zf = new ZipFile(f); + fail(); + } catch (Exception ex) { + check(ex.getMessage().contains("zip file is empty")); + } finally { + if (zf != null) { + zf.close(); + } + } + + ZipInputStream zis = null; + try { + zis = new ZipInputStream(new FileInputStream(f)); + ZipEntry ze = zis.getNextEntry(); + check(ze == null); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zis != null) { + zis.close(); + } + } + + f.delete(); + + // Verify 0-entries file can be written + write(f); + + // Verify 0-entries file can be read + readFile(f); + readStream(f); + + f.delete(); + } + + static void write(File f) throws Exception { + ZipOutputStream zos = null; + try { + zos = new ZipOutputStream(new FileOutputStream(f)); + zos.finish(); + zos.close(); + pass(); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zos != null) { + zos.close(); + } + } + } + + static void readFile(File f) throws Exception { + ZipFile zf = null; + try { + zf = new ZipFile(f); + + Enumeration e = zf.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = (ZipEntry) e.nextElement(); + fail(); + } + zf.close(); + pass(); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zf != null) { + zf.close(); + } + } + } + + static void readStream(File f) throws Exception { + ZipInputStream zis = null; + try { + zis = new ZipInputStream(new FileInputStream(f)); + ZipEntry ze = zis.getNextEntry(); + check(ze == null); + byte[] buf = new byte[1024]; + check(zis.read(buf, 0, 1024) == -1); + } finally { + if (zis != null) { + zis.close(); + } + } + } + + //--------------------- 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 --git a/test/javax/management/Introspector/AnnotatedMBeanTest.java b/test/javax/management/Introspector/AnnotatedMBeanTest.java index b0782d39c856b9291a7ffa4ba294c3ec1c7a2d69..382a1219c68f09e597e4a3f37ce15a7e7d647f38 100644 --- a/test/javax/management/Introspector/AnnotatedMBeanTest.java +++ b/test/javax/management/Introspector/AnnotatedMBeanTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java b/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java index bc6a335dfbecf0a70d063acebe247d48ac78e8cd..3db55b7447160182a8350f56a77e189f55a8f357 100644 --- a/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java +++ b/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/Introspector/MBeanDescriptionTest.java b/test/javax/management/Introspector/MBeanDescriptionTest.java index 5fc77f9c11934f0efc921e21736bc54b7a79caac..5a52b0b697bc24321537857a43854a92f5c43b6c 100644 --- a/test/javax/management/Introspector/MBeanDescriptionTest.java +++ b/test/javax/management/Introspector/MBeanDescriptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/Introspector/ParameterNameTest.java b/test/javax/management/Introspector/ParameterNameTest.java index fada6cccb17eb7c424db3b345b4aa28c09c99b1e..bf5649b8e768872a183f0f968c134a62b73fc6ed 100644 --- a/test/javax/management/Introspector/ParameterNameTest.java +++ b/test/javax/management/Introspector/ParameterNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/Introspector/ResourceInjectionTest.java b/test/javax/management/Introspector/ResourceInjectionTest.java index ad45ccc029f9175954bfdc7c7c6f62b48c90e8bb..0a8882b5463e99a7a9ab58167acc9d96ca840fcd 100644 --- a/test/javax/management/Introspector/ResourceInjectionTest.java +++ b/test/javax/management/Introspector/ResourceInjectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/Introspector/annot/Name.java b/test/javax/management/Introspector/annot/Name.java index 790e641552eb8d7e9017b7bf021e854485025d51..314497867316652cb645299e8dabf216d6b7fa74 100644 --- a/test/javax/management/Introspector/annot/Name.java +++ b/test/javax/management/Introspector/annot/Name.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/MBeanInfo/NotificationInfoTest.java b/test/javax/management/MBeanInfo/NotificationInfoTest.java index 2a78e0941d5ec83869b0b7d410c67caf88cf9c4e..71a95880c41c97ec566247d1e7b055975f3a3612 100644 --- a/test/javax/management/MBeanInfo/NotificationInfoTest.java +++ b/test/javax/management/MBeanInfo/NotificationInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -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 @@ import javax.management.relation.*; */ 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 @@ public class NotificationInfoTest { .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 @@ public class NotificationInfoTest { 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 @@ public class NotificationInfoTest { 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 @@ public class NotificationInfoTest { } 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 @@ public class NotificationInfoTest { } 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 @@ public class NotificationInfoTest { 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 @@ public class NotificationInfoTest { 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 --git a/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java b/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java new file mode 100644 index 0000000000000000000000000000000000000000..793419abf650b10938d4f115c71e9100fb888587 --- /dev/null +++ b/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java @@ -0,0 +1,164 @@ +/* + * 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 DynamicWrapperMBeanTest + * @bug 6624232 + * @summary Test the DynamicWrapperMBean interface + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.modelmbean.ModelMBeanInfo; +import javax.management.modelmbean.ModelMBeanInfoSupport; +import javax.management.modelmbean.ModelMBeanOperationInfo; +import javax.management.modelmbean.RequiredModelMBean; +import static javax.management.StandardMBean.Options; + +public class DynamicWrapperMBeanTest { + public static interface WrappedMBean { + public void sayHello(); + } + public static class Wrapped implements WrappedMBean { + public void sayHello() { + System.out.println("Hello"); + } + } + + private static String failure; + + public static void main(String[] args) throws Exception { + if (Wrapped.class.getClassLoader() == + StandardMBean.class.getClassLoader()) { + throw new Exception( + "TEST ERROR: Resource and StandardMBean have same ClassLoader"); + } + + Options wrappedVisOpts = new Options(); + wrappedVisOpts.setWrappedObjectVisible(true); + Options wrappedInvisOpts = new Options(); + wrappedInvisOpts.setWrappedObjectVisible(false); + assertEquals("Options withWrappedObjectVisible(false)", + new Options(), wrappedInvisOpts); + + Wrapped resource = new Wrapped(); + + StandardMBean visible = + new StandardMBean(resource, WrappedMBean.class, wrappedVisOpts); + StandardMBean invisible = + new StandardMBean(resource, WrappedMBean.class, wrappedInvisOpts); + + assertEquals("getResource withWrappedObjectVisible(true)", + resource, visible.getWrappedObject()); + assertEquals("getResource withWrappedObjectVisible(false)", + invisible, invisible.getWrappedObject()); + + System.out.println("===Testing StandardMBean==="); + + ObjectName visibleName = new ObjectName("a:type=visible"); + ObjectName invisibleName = new ObjectName("a:type=invisible"); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + mbs.registerMBean(visible, visibleName); + mbs.registerMBean(invisible, invisibleName); + + assertEquals("ClassLoader for visible resource", + Wrapped.class.getClassLoader(), + mbs.getClassLoaderFor(visibleName)); + assertEquals("ClassLoader for invisible resource", + StandardMBean.class.getClassLoader(), + mbs.getClassLoaderFor(invisibleName)); + + assertEquals("isInstanceOf(WrappedMBean) for visible wrapped", + true, mbs.isInstanceOf(visibleName, WrappedMBean.class.getName())); + assertEquals("isInstanceOf(WrappedMBean) for invisible wrapped", + false, mbs.isInstanceOf(invisibleName, WrappedMBean.class.getName())); + assertEquals("isInstanceOf(StandardMBean) for visible wrapped", + false, mbs.isInstanceOf(visibleName, StandardMBean.class.getName())); + assertEquals("isInstanceOf(StandardMBean) for invisible wrapped", + true, mbs.isInstanceOf(invisibleName, StandardMBean.class.getName())); + + mbs.unregisterMBean(visibleName); + mbs.unregisterMBean(invisibleName); + + System.out.println("===Testing RequiredModelMBean==="); + + // Godawful Model MBeans... + ModelMBeanOperationInfo mmboi = new ModelMBeanOperationInfo( + "say hello to the nice man", Wrapped.class.getMethod("sayHello")); + ModelMBeanInfo visibleMmbi = new ModelMBeanInfoSupport( + Wrapped.class.getName(), "Visible wrapped", null, null, + new ModelMBeanOperationInfo[] {mmboi}, null); + ModelMBeanInfo invisibleMmbi = new ModelMBeanInfoSupport( + Wrapped.class.getName(), "Invisible wrapped", null, null, + new ModelMBeanOperationInfo[] {mmboi}, null); + RequiredModelMBean visibleRmmb = new RequiredModelMBean(visibleMmbi); + RequiredModelMBean invisibleRmmb = new RequiredModelMBean(invisibleMmbi); + visibleRmmb.setManagedResource(resource, "VisibleObjectReference"); + invisibleRmmb.setManagedResource(resource, "ObjectReference"); + + mbs.registerMBean(visibleRmmb, visibleName); + mbs.registerMBean(invisibleRmmb, invisibleName); + + assertEquals("ClassLoader for visible wrapped", + Wrapped.class.getClassLoader(), + mbs.getClassLoaderFor(visibleName)); + assertEquals("ClassLoader for invisible wrapped", + StandardMBean.class.getClassLoader(), + mbs.getClassLoaderFor(invisibleName)); + + assertEquals("isInstanceOf(WrappedMBean) for visible resource", + true, mbs.isInstanceOf(visibleName, WrappedMBean.class.getName())); + assertEquals("isInstanceOf(WrappedMBean) for invisible resource", + false, mbs.isInstanceOf(invisibleName, WrappedMBean.class.getName())); + assertEquals("isInstanceOf(RequiredModelMBean) for visible resource", + false, mbs.isInstanceOf(visibleName, RequiredModelMBean.class.getName())); + assertEquals("isInstanceOf(RequiredModelMBean) for invisible resource", + true, mbs.isInstanceOf(invisibleName, RequiredModelMBean.class.getName())); + + if (failure != null) + throw new Exception("TEST FAILED: " + failure); + } + + private static void assertEquals(String what, Object expect, Object actual) { + if (equal(expect, actual)) + System.out.println("OK: " + what + " = " + expect); + else + fail(what + " should be " + expect + ", is " + actual); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + return x.equals(y); + } + + private static void fail(String why) { + failure = why; + System.out.println("FAIL: " + why); + } +} diff --git a/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3007965538583804ef01bd8afbe80e978cb826fe --- /dev/null +++ b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java @@ -0,0 +1,76 @@ +/* + * 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 6669137 + * @summary Test the constructors of InstanceNotFoundExceptionTest. + * @author Daniel Fuchs + * @compile InstanceNotFoundExceptionTest.java + * @run main InstanceNotFoundExceptionTest + */ + +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; + +public class InstanceNotFoundExceptionTest { + public static void main(String[] args) throws Exception { + final InstanceNotFoundException x = + new InstanceNotFoundException(); + System.out.println("InstanceNotFoundException(): "+x.getMessage()); + + final String msg = "who is toto?"; + final InstanceNotFoundException x2 = + new InstanceNotFoundException(msg); + if (!msg.equals(x2.getMessage())) + throw new Exception("Bad message: expected "+msg+ + ", got "+x2.getMessage()); + System.out.println("InstanceNotFoundException(" + + msg+"): "+x2.getMessage()); + + final InstanceNotFoundException x3 = + new InstanceNotFoundException((String)null); + if (x3.getMessage() != null) + throw new Exception("Bad message: expected "+null+ + ", got "+x3.getMessage()); + System.out.println("InstanceNotFoundException((String)null): "+ + x3.getMessage()); + + final ObjectName n = new ObjectName("who is toto?:type=msg"); + final InstanceNotFoundException x4 = + new InstanceNotFoundException(n); + if (!String.valueOf(n).equals(x4.getMessage())) + throw new Exception("Bad message: expected "+n+ + ", got "+x4.getMessage()); + System.out.println("InstanceNotFoundException(" + + n+"): "+x4.getMessage()); + + final InstanceNotFoundException x5 = + new InstanceNotFoundException((ObjectName)null); + if (!String.valueOf((ObjectName)null).equals(x5.getMessage())) + throw new Exception("Bad message: expected " + + String.valueOf((ObjectName)null)+" got "+x5.getMessage()); + System.out.println("InstanceNotFoundException((ObjectName)null): "+ + x5.getMessage()); + } +} diff --git a/test/javax/management/MBeanServer/MBeanServerNotificationTest.java b/test/javax/management/MBeanServer/MBeanServerNotificationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..54fd6ba2d86ad164641dd587f5541d0e0b68e8ec --- /dev/null +++ b/test/javax/management/MBeanServer/MBeanServerNotificationTest.java @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along 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 6689505 + * @summary Checks that MBeanServerNotification.toString contains the + * MBean name. + * @author Daniel Fuchs + * @compile MBeanServerNotificationTest.java + * @run main MBeanServerNotificationTest + */ + +import com.sun.jmx.mbeanserver.Util; +import javax.management.*; +import java.util.concurrent.*; + +public class MBeanServerNotificationTest { + final static String[] names = { + ":type=Wombat", "wombat:type=Wombat",null, + }; + public static void main(String[] args) throws Exception { + System.out.println("Test that MBeanServerNotification.toString " + + "contains the name of the MBean being registered " + + "or unregistered."); + int failures = 0; + final MBeanServer mbs = MBeanServerFactory.createMBeanServer(); + for (String str:names) { + try { + final ObjectName name = (str==null)?null:new ObjectName(str); + failures+=test(mbs, name, name!=null); + } catch(Exception x) { + x.printStackTrace(System.out); + System.out.println("Test failed for: "+str); + failures++; + } + } + if (failures == 0) + System.out.println("Test passed"); + else { + System.out.println("TEST FAILED: " + failures + " failure(s)"); + System.exit(1); + } + } + + private static enum Registration { + REGISTER(MBeanServerNotification.REGISTRATION_NOTIFICATION), + UNREGISTER(MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + final String type; + private Registration(String type) {this.type = type;} + public int test(MBeanServerNotification n, ObjectName name) { + int failures = 0; + System.out.println("Testing: "+n); + if (!n.toString().endsWith("[type="+type+ + "][message="+n.getMessage()+ + "][mbeanName="+name+"]")) { + System.err.println("Test failed for "+ type+ + " ["+name+"]: "+n); + failures++; + } + return failures; + } + public MBeanServerNotification create(ObjectName name) { + return new MBeanServerNotification(type, + MBeanServerDelegate.DELEGATE_NAME, next(), name); + } + private static long next = 0; + private static synchronized long next() {return next++;} + + } + + private static int test(MBeanServer mbs, ObjectName name, + boolean register) + throws Exception { + System.out.println("--------" + name + "--------"); + + int failures = 0; + for (Registration reg : Registration.values()) { + failures = reg.test(reg.create(name), name); + } + if (!register) return failures; + + final ArrayBlockingQueue queue = + new ArrayBlockingQueue(10); + final NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + try { + queue.put(notification); + } catch(Exception x) { + x.printStackTrace(System.out); + } + } + }; + mbs.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, + listener, null, name); + final ObjectInstance oi = mbs.registerMBean(new Wombat(), name); + try { + failures+=Registration.REGISTER.test((MBeanServerNotification) + queue.poll(2, TimeUnit.SECONDS), oi.getObjectName()); + } finally { + mbs.unregisterMBean(oi.getObjectName()); + failures+=Registration.UNREGISTER.test((MBeanServerNotification) + queue.poll(2, TimeUnit.SECONDS), oi.getObjectName()); + } + return failures; + } + + public static interface WombatMBean {} + public static class Wombat implements WombatMBean {} + +} diff --git a/test/javax/management/MBeanServer/OldMBeanServerTest.java b/test/javax/management/MBeanServer/OldMBeanServerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e33d993ccc32246d39c9109606dac94d17507864 --- /dev/null +++ b/test/javax/management/MBeanServer/OldMBeanServerTest.java @@ -0,0 +1,1410 @@ +/* + * 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.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.management.ManagementFactory; +import java.lang.ref.WeakReference; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +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.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.MalformedObjectNameException; +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; +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.RuntimeErrorException; +import javax.management.RuntimeMBeanException; +import javax.management.StandardMBean; +import javax.management.loading.ClassLoaderRepository; +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 OldMBeanServerTest.java + * @bug 5072268 + * @summary Test that nothing assumes a post-1.2 MBeanServer + * @author Eamonn McManus + * @run main/othervm -ea OldMBeanServerTest + */ + +/* + * We defined the MBeanServerBuilder class and the associated system + * property javax.management.builder.initial in version 1.2 of the JMX + * spec. That amounts to a guarantee that someone can set the property + * to an MBeanServer that only knows about JMX 1.2 semantics, and if they + * only do JMX 1.2 operations, everything should work. This test is a + * sanity check that ensures we don't inadvertently make any API changes + * that stop that from being true. It includes a complete (if slow) + * MBeanServer implementation. That implementation doesn't replicate the + * mandated exception behaviour everywhere, though, since there's lots of + * arbitrary cruft in that. Also, the behaviour of concurrent unregisterMBean + * calls is incorrect in detail. + */ + +public class OldMBeanServerTest { + private static MBeanServerConnection mbsc; + private static String failure; + + public static void main(String[] args) throws Exception { + if (!OldMBeanServerTest.class.desiredAssertionStatus()) + throw new Exception("Test must be run with -ea"); + + System.setProperty("javax.management.builder.initial", + OldMBeanServerBuilder.class.getName()); + assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer; + + System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ==="); + runTests(new Callable() { + public MBeanServerConnection call() { + return MBeanServerFactory.newMBeanServer(); + } + }, null); + + System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ==="); + ConnectionBuilder builder = new ConnectionBuilder(); + runTests(builder, builder); + + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + private static class ConnectionBuilder + implements Callable, Runnable { + private JMXConnector connector; + public MBeanServerConnection call() { + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + try { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer( + url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + connector = JMXConnectorFactory.connect(addr); + return connector.getMBeanServerConnection(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public void run() { + if (connector != null) { + try { + connector.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + + private static void runTests( + Callable maker, Runnable breaker) + throws Exception { + for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers()) && + m.getName().startsWith("test") && + m.getParameterTypes().length == 0) { + ExpectException expexc = m.getAnnotation(ExpectException.class); + mbsc = maker.call(); + try { + m.invoke(null); + if (expexc != null) { + failure = + m.getName() + " did not got expected exception " + + expexc.value().getName(); + System.out.println(failure); + } else + System.out.println(m.getName() + " OK"); + } catch (InvocationTargetException ite) { + Throwable t = ite.getCause(); + String prob = null; + if (expexc != null) { + if (expexc.value().isInstance(t)) { + System.out.println(m.getName() + " OK (got expected " + + expexc.value().getName() + ")"); + } else + prob = "got wrong exception"; + } else + prob = "got exception"; + if (prob != null) { + failure = m.getName() + ": " + prob + " " + + t.getClass().getName(); + System.out.println(failure); + t.printStackTrace(System.out); + } + } finally { + if (breaker != null) + breaker.run(); + } + } + } + } + + @Retention(RetentionPolicy.RUNTIME) + private static @interface ExpectException { + Class value(); + } + + public static interface BoringMBean { + public String getName(); + public int add(int x, int y); + } + + // This class is Serializable so we can createMBean a StandardMBean + // that contains it. Not recommended practice in general -- + // should we have a StandardMBean constructor that takes a class + // name and constructor parameters? + public static class Boring implements BoringMBean, Serializable { + public String getName() { + return "Jessica"; + } + + public int add(int x, int y) { + return x + y; + } + } + + public static interface BoringNotifierMBean extends BoringMBean { + public void send(); + } + + public static class BoringNotifier + extends Boring implements BoringNotifierMBean, NotificationBroadcaster { + private final NotificationBroadcasterSupport nbs = + new NotificationBroadcasterSupport(); + + public void addNotificationListener( + NotificationListener listener, NotificationFilter filter, Object handback) + throws IllegalArgumentException { + nbs.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + nbs.removeNotificationListener(listener); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return null; + } + + public void send() { + Notification n = new Notification("type.type", this, 0L); + nbs.sendNotification(n); + } + } + + private static class CountListener implements NotificationListener { + volatile int count; + public void handleNotification(Notification n, Object h) { + if (h == null) + h = 1; + count += (Integer) h; + } + void waitForCount(int expect) throws InterruptedException { + long deadline = System.currentTimeMillis() + 2000L; + while (count < expect && System.currentTimeMillis() < deadline) + Thread.sleep(1); + assert count == expect; + } + } + + private static void testBasic() throws Exception { + CountListener countListener = new CountListener(); + mbsc.addNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, countListener, null, null); + assert countListener.count == 0; + ObjectName name = new ObjectName("a:b=c"); + if (mbsc instanceof MBeanServer) + ((MBeanServer) mbsc).registerMBean(new Boring(), name); + else + mbsc.createMBean(Boring.class.getName(), name); + countListener.waitForCount(1); + assert mbsc.isRegistered(name); + assert mbsc.queryNames(null, null).contains(name); + assert mbsc.getAttribute(name, "Name").equals("Jessica"); + assert mbsc.invoke( + name, "add", new Object[] {2, 3}, new String[] {"int", "int"}) + .equals(5); + mbsc.unregisterMBean(name); + countListener.waitForCount(2); + assert !mbsc.isRegistered(name); + assert !mbsc.queryNames(null, null).contains(name); + + mbsc.createMBean(BoringNotifier.class.getName(), name); + countListener.waitForCount(3); + CountListener boringListener = new CountListener(); + class AlwaysNotificationFilter implements NotificationFilter { + public boolean isNotificationEnabled(Notification notification) { + return true; + } + } + mbsc.addNotificationListener( + name, boringListener, new AlwaysNotificationFilter(), 5); + mbsc.invoke(name, "send", null, null); + boringListener.waitForCount(5); + } + + private static void testPrintAttrs() throws Exception { + printAttrs(mbsc, null); + } + + private static void testPlatformMBeanServer() throws Exception { + MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer(); + assert pmbs instanceof OldMBeanServer; + // Preceding assertion could be violated if at some stage we wrap + // the Platform MBeanServer. In that case we can still check that + // it is ultimately an OldMBeanServer for example by adding a + // counter to getAttribute and checking that it is incremented + // when we call pmbs.getAttribute. + + printAttrs(pmbs, UnsupportedOperationException.class); + ObjectName memoryMXBeanName = + new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME); + pmbs.invoke(memoryMXBeanName, "gc", null, null); + } + + private static void printAttrs( + MBeanServerConnection mbsc1, Class expectX) + throws Exception { + Set names = mbsc1.queryNames(null, null); + for (ObjectName name : names) { + System.out.println(name + ":"); + MBeanInfo mbi = mbsc1.getMBeanInfo(name); + MBeanAttributeInfo[] mbais = mbi.getAttributes(); + for (MBeanAttributeInfo mbai : mbais) { + String attr = mbai.getName(); + Object value; + try { + value = mbsc1.getAttribute(name, attr); + } catch (Exception e) { + if (expectX != null && expectX.isInstance(e)) + value = "<" + e + ">"; + else + throw e; + } + String s = " " + attr + " = " + value; + if (s.length() > 80) + s = s.substring(0, 77) + "..."; + System.out.println(s); + } + } + } + + private static void testJavaxManagementStandardMBean() throws Exception { + ObjectName name = new ObjectName("a:b=c"); + Object mbean = new StandardMBean(new Boring(), BoringMBean.class); + mbsc.createMBean( + StandardMBean.class.getName(), name, + new Object[] {new Boring(), BoringMBean.class}, + new String[] {Object.class.getName(), Class.class.getName()}); + assert mbsc.getAttribute(name, "Name").equals("Jessica"); + assert mbsc.invoke( + name, "add", new Object[] {2, 3}, new String[] {"int", "int"}) + .equals(5); + mbsc.unregisterMBean(name); + } + + private static void testConnector() throws Exception { + } + + public static class OldMBeanServerBuilder extends MBeanServerBuilder { + public MBeanServer newMBeanServer( + String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) { + return new OldMBeanServer(defaultDomain, delegate); + } + } + + public static class OldMBeanServer implements MBeanServer { + // We pretend there's a ClassLoader MBean representing the Class Loader + // Repository and intercept references to it where necessary to keep up + // the pretence. This allows us to fake the right behaviour for + // the omitted-ClassLoader versions of createMBean and instantiate + // (which are not the same as passing a null for the ClassLoader parameter + // of the versions that have one). + private static final ObjectName clrName; + static { + try { + clrName = + new ObjectName("JMImplementation:type=ClassLoaderRepository"); + } catch (MalformedObjectNameException e) { + throw new RuntimeException(e); + } + } + + private final ConcurrentMap mbeans = + new ConcurrentHashMap(); + private final ConcurrentMap listenerMap = + new ConcurrentHashMap(); + private final String defaultDomain; + private final MBeanServerDelegate delegate; + private final ClassLoaderRepositoryImpl clr = + new ClassLoaderRepositoryImpl(); + + OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) { + this.defaultDomain = defaultDomain; + this.delegate = delegate; + try { + registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return createMBean(className, name, null, null); + } + + public ObjectInstance createMBean( + String className, ObjectName name, ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + return createMBean(className, name, loaderName, null, null); + } + + public ObjectInstance createMBean( + String className, ObjectName name, Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + return createMBean(className, name, clrName, params, signature); + } catch (InstanceNotFoundException ex) { + throw new RuntimeException(ex); // can't happen + } + } + + public ObjectInstance createMBean( + String className, ObjectName name, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + Object mbean = instantiate(className, loaderName, params, signature); + return registerMBean(mbean, name); + } + + private void forbidJMImpl(ObjectName name) { + if (name.getDomain().equals("JMImplementation") && + mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME)) + throw new IllegalArgumentException("JMImplementation reserved"); + } + + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + forbidJMImpl(name); + if (name.isPattern()) + throw new IllegalArgumentException(name.toString()); + // This is the only place we check for wildcards. Since you + // can't register a wildcard name, other operations that supply + // one will get InstanceNotFoundException when they look it up. + + DynamicMBean mbean; + if (object instanceof DynamicMBean) + mbean = (DynamicMBean) object; + else + mbean = standardToDynamic(object); + MBeanRegistration reg = mbeanRegistration(object); + try { + name = reg.preRegister(this, name); + } catch (Exception e) { + throw new MBeanRegistrationException(e); + } + DynamicMBean put = mbeans.putIfAbsent(name, mbean); + if (put != null) { + reg.postRegister(false); + throw new InstanceAlreadyExistsException(name.toString()); + } + reg.postRegister(true); + + if (object instanceof ClassLoader) + clr.addLoader((ClassLoader) object); + + Notification n = new MBeanServerNotification( + MBeanServerNotification.REGISTRATION_NOTIFICATION, + MBeanServerDelegate.DELEGATE_NAME, + 0, + name); + delegate.sendNotification(n); + + String className = mbean.getMBeanInfo().getClassName(); + return new ObjectInstance(name, className); + } + + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + + forbidJMImpl(name); + + DynamicMBean mbean = getMBean(name); + if (mbean == null) + throw new InstanceNotFoundException(name.toString()); + + MBeanRegistration reg = mbeanRegistration(mbean); + try { + reg.preDeregister(); + } catch (Exception e) { + throw new MBeanRegistrationException(e); + } + if (!mbeans.remove(name, mbean)) + throw new InstanceNotFoundException(name.toString()); + // This is incorrect because we've invoked preDeregister + + Object userMBean = getUserMBean(mbean); + if (userMBean instanceof ClassLoader) + clr.removeLoader((ClassLoader) userMBean); + + Notification n = new MBeanServerNotification( + MBeanServerNotification.REGISTRATION_NOTIFICATION, + MBeanServerDelegate.DELEGATE_NAME, + 0, + name); + delegate.sendNotification(n); + + reg.postDeregister(); + } + + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = getMBean(name); + return new ObjectInstance(name, mbean.getMBeanInfo().getClassName()); + } + + private static class TrueQueryExp implements QueryExp { + public boolean apply(ObjectName name) { + return true; + } + + public void setMBeanServer(MBeanServer s) {} + } + private static final QueryExp trueQuery = new TrueQueryExp(); + + public Set queryMBeans(ObjectName name, QueryExp query) { + Set instances = newSet(); + if (name == null) + name = ObjectName.WILDCARD; + if (query == null) + query = trueQuery; + MBeanServer oldMBS = QueryEval.getMBeanServer(); + try { + query.setMBeanServer(this); + for (ObjectName n : mbeans.keySet()) { + if (name.apply(n)) { + try { + if (query.apply(n)) + instances.add(getObjectInstance(n)); + } catch (Exception e) { + // OK: Ignore this MBean in the result + } + } + } + } finally { + query.setMBeanServer(oldMBS); + } + return instances; + } + + public Set queryNames(ObjectName name, QueryExp query) { + Set instances = queryMBeans(name, query); + Set names = newSet(); + for (ObjectInstance instance : instances) + names.add(instance.getObjectName()); + return names; + } + + public boolean isRegistered(ObjectName name) { + return mbeans.containsKey(name); + } + + public Integer getMBeanCount() { + return mbeans.size(); + } + + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + return getMBean(name).getAttribute(attribute); + } + + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + return getMBean(name).getAttributes(attributes); + } + + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + getMBean(name).setAttribute(attribute); + } + + public AttributeList setAttributes( + ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + return getMBean(name).setAttributes(attributes); + } + + public Object invoke( + ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException { + return getMBean(name).invoke(operationName, params, signature); + } + + public String getDefaultDomain() { + return defaultDomain; + } + + public String[] getDomains() { + Set domains = newSet(); + for (ObjectName name : mbeans.keySet()) + domains.add(name.getDomain()); + return domains.toArray(new String[0]); + } + + // ClassCastException if MBean is not a NotificationBroadcaster + public void addNotificationListener( + ObjectName name, NotificationListener listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + NotificationBroadcaster userMBean = + (NotificationBroadcaster) getUserMBean(name); + NotificationListener wrappedListener = + wrappedListener(name, userMBean, listener); + userMBean.addNotificationListener(wrappedListener, filter, handback); + } + + public void addNotificationListener( + ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + NotificationListener nl = + (NotificationListener) getUserMBean(listener); + addNotificationListener(name, nl, filter, handback); + } + + public void removeNotificationListener( + ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener nl = + (NotificationListener) getUserMBean(listener); + removeNotificationListener(name, nl); + } + + public void removeNotificationListener( + ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationListener nl = + (NotificationListener) getUserMBean(listener); + removeNotificationListener(name, nl, filter, handback); + } + + public void removeNotificationListener( + ObjectName name, NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationBroadcaster userMBean = + (NotificationBroadcaster) getUserMBean(name); + NotificationListener wrappedListener = + wrappedListener(name, userMBean, listener); + userMBean.removeNotificationListener(wrappedListener); + } + + public void removeNotificationListener( + ObjectName name, NotificationListener listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + NotificationEmitter userMBean = + (NotificationEmitter) getMBean(name); + NotificationListener wrappedListener = + wrappedListener(name, userMBean, listener); + userMBean.removeNotificationListener(wrappedListener, filter, handback); + } + + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + return getMBean(name).getMBeanInfo(); + } + + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + DynamicMBean mbean = getMBean(name); + String mbeanClassName = mbean.getMBeanInfo().getClassName(); + if (className.equals(mbeanClassName)) + return true; + ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader(); + try { + Class mbeanClass = Class.forName(mbeanClassName, false, loader); + Class isInstClass = Class.forName(className, false, loader); + return isInstClass.isAssignableFrom(mbeanClass); + } catch (ClassNotFoundException e) { + return false; + } + } + + public Object instantiate(String className) + throws ReflectionException, MBeanException { + return instantiate(className, null, null); + } + + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, InstanceNotFoundException { + return instantiate(className, loaderName, null, null); + } + + public Object instantiate( + String className, Object[] params, String[] signature) + throws ReflectionException, MBeanException { + try { + return instantiate(className, clrName, params, signature); + } catch (InstanceNotFoundException e) { + throw new RuntimeException(e); // can't happen + } + } + + public Object instantiate( + String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, InstanceNotFoundException { + + if (params == null) + params = new Object[0]; + if (signature == null) + signature = new String[0]; + + ClassLoader loader; + if (loaderName == null) + loader = this.getClass().getClassLoader(); + else if (loaderName.equals(clrName)) + loader = clr; + else + loader = (ClassLoader) getMBean(loaderName); + + Class c; + try { + c = Class.forName(className, false, loader); + } catch (ClassNotFoundException e) { + throw new ReflectionException(e); + } + + Constructor[] constrs = c.getConstructors(); + Constructor found = null; + findconstr: + for (Constructor constr : constrs) { + Class[] cTypes = constr.getParameterTypes(); + if (cTypes.length == signature.length) { + for (int i = 0; i < cTypes.length; i++) { + if (!cTypes[i].getName().equals(signature[i])) + continue findconstr; + } + found = constr; + break findconstr; + } + } + if (found == null) { + Exception x = new NoSuchMethodException( + className + Arrays.toString(signature)); + throw new ReflectionException(x); + } + return invokeSomething(found, null, params); + } + + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException(); + } + + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException(); + } + + @Deprecated + public ObjectInputStream deserialize( + String className, ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, ReflectionException { + throw new UnsupportedOperationException(); + } + + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + DynamicMBean mbean = getMBean(mbeanName); + Object userMBean = getUserMBean(mbean); + return userMBean.getClass().getClassLoader(); + } + + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + return (ClassLoader) getMBean(loaderName); + } + + public ClassLoaderRepository getClassLoaderRepository() { + return new ClassLoaderRepository() { + public Class loadClass(String className) + throws ClassNotFoundException { + return clr.loadClass(className); + } + + public Class loadClassWithout( + ClassLoader exclude, String className) + throws ClassNotFoundException { + return clr.loadClassWithout(exclude, className); + } + + public Class loadClassBefore( + ClassLoader stop, String className) + throws ClassNotFoundException { + return clr.loadClassBefore(stop, className); + } + }; + } + + private static class ClassLoaderRepositoryImpl + extends ClassLoader implements ClassLoaderRepository { + private List loaders = newList(); + { + loaders.add(this.getClass().getClassLoader()); + // We also behave as if the system class loader were in + // the repository, since we do nothing to stop delegation + // to the parent, which is the system class loader, and + // that delegation happens before our findClass is called. + } + + void addLoader(ClassLoader loader) { + loaders.add(loader); + } + + void removeLoader(ClassLoader loader) { + if (!loaders.remove(loader)) + throw new RuntimeException("Loader was not in CLR!"); + } + + public Class loadClassWithout( + ClassLoader exclude, String className) + throws ClassNotFoundException { + return loadClassWithoutBefore(exclude, null, className); + } + + public Class loadClassBefore(ClassLoader stop, String className) + throws ClassNotFoundException { + return loadClassWithoutBefore(null, stop, className); + } + + private Class loadClassWithoutBefore( + ClassLoader exclude, ClassLoader stop, String className) + throws ClassNotFoundException { + for (ClassLoader loader : loaders) { + if (loader == exclude) + continue; + if (loader == stop) + break; + try { + return Class.forName(className, false, loader); + } catch (ClassNotFoundException e) { + // OK: try others + } + } + throw new ClassNotFoundException(className); + } + + @Override + protected Class findClass(String className) + throws ClassNotFoundException { + return loadClassWithout(null, className); + } + } + + /* There is zero or one ListenerTable per MBean. + * The ListenerTable stuff is complicated. We want to rewrite the + * source of notifications so that if the source of a notification + * from the MBean X is a reference to X itself, it gets replaced + * by X's ObjectName. To do this, we wrap the user's listener in + * a RewriteListener. But if the same listener is added a second + * time (perhaps with a different filter or handback) we must + * reuse the same RewriteListener so that the two-argument + * removeNotificationListener(ObjectName,NotificationListener) will + * correctly remove both listeners. This means we must remember the + * mapping from listener to WrappedListener. But if the MBean + * discards its listeners (as a result of removeNL or spontaneously) + * then we don't want to keep a reference to the WrappedListener. + * So we have tons of WeakReferences. The key in the ListenerTable + * is an IdentityListener, which wraps the user's listener to ensure + * that identity and not equality is used during the lookup, even if + * the user's listener has an equals method. The value in the + * ListenerTable is a WeakReference wrapping a RewriteListener wrapping + * the same IdentityListener. Since the RewriteListener is what is + * added to the user's MBean, the WeakReference won't disappear as long + * as the MBean still has this listener. And since it references the + * IdentityListener, that won't disappear either. But once the + * RewriteListener is no longer referenced by the user's MBean, + * there's nothing to stop its WeakReference from being cleared, + * and then corresponding IdentityListener that is now only weakly + * referenced from the key in the table. + */ + private static class ListenerTable + extends WeakHashMap> { + } + + private static class IdentityListener implements NotificationListener { + private final NotificationListener userListener; + + IdentityListener(NotificationListener userListener) { + this.userListener = userListener; + } + + public void handleNotification( + Notification notification, Object handback) { + userListener.handleNotification(notification, handback); + } + + @Override + public boolean equals(Object o) { + return (this == o); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + } + + private static class RewriteListener implements NotificationListener { + private final ObjectName name; + private final Object userMBean; + private final NotificationListener userListener; + + RewriteListener( + ObjectName name, Object userMBean, + NotificationListener userListener) { + this.name = name; + this.userMBean = userMBean; + this.userListener = userListener; + } + + public void handleNotification( + Notification notification, Object handback) { + if (notification.getSource() == userMBean) + notification.setSource(name); + userListener.handleNotification(notification, handback); + } + } + + private NotificationListener wrappedListener( + ObjectName name, Object userMBean, NotificationListener userListener) + throws InstanceNotFoundException { + ListenerTable table = new ListenerTable(); + ListenerTable oldTable = listenerMap.putIfAbsent(name, table); + if (oldTable != null) + table = oldTable; + NotificationListener identityListener = + new IdentityListener(userListener); + synchronized (table) { + NotificationListener rewriteListener = null; + WeakReference wr = + table.get(identityListener); + if (wr != null) + rewriteListener = wr.get(); + if (rewriteListener == null) { + rewriteListener = new RewriteListener( + name, userMBean, identityListener); + wr = new WeakReference(rewriteListener); + table.put(identityListener, wr); + } + return rewriteListener; + } + } + + private DynamicMBean getMBean(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = mbeans.get(name); + if (mbean == null) + throw new InstanceNotFoundException(name.toString()); + return mbean; + } + + private static interface WrapDynamicMBean extends DynamicMBean { + public Object getWrappedMBean(); + } + + private static class StandardWrapper + implements WrapDynamicMBean, MBeanRegistration { + private final Map attrMap = newMap(); + private final Map> opMap = newMap(); + private static class AttrMethods { + Method getter, setter; + } + + private final Object std; + + StandardWrapper(Object std) throws NotCompliantMBeanException { + this.std = std; + Class intf = mbeanInterface(std.getClass()); + try { + initMaps(intf); + } catch (NotCompliantMBeanException e) { + throw e; + } catch (Exception e) { + NotCompliantMBeanException x = + new NotCompliantMBeanException(e.getMessage()); + x.initCause(e); + throw x; + } + } + + private static Class mbeanInterface(Class c) + throws NotCompliantMBeanException { + do { + Class[] intfs = c.getInterfaces(); + String intfName = c.getName() + "MBean"; + for (Class intf : intfs) { + if (intf.getName().equals(intfName)) + return intf; + } + c = c.getSuperclass(); + } while (c != null); + throw new NotCompliantMBeanException( + "Does not match Standard or Dynamic MBean patterns: " + + c.getName()); + } + + private void initMaps(Class intf) throws NotCompliantMBeanException { + Method[] methods = intf.getMethods(); + + for (Method m : methods) { + final String name = m.getName(); + final int nParams = m.getParameterTypes().length; + + String attrName = ""; + if (name.startsWith("get")) + attrName = name.substring(3); + else if (name.startsWith("is") + && m.getReturnType() == boolean.class) + attrName = name.substring(2); + + if (attrName.length() != 0 && m.getParameterTypes().length == 0 + && m.getReturnType() != void.class) { + // It's a getter + // Check we don't have both isX and getX + AttrMethods am = attrMap.get(attrName); + if (am == null) + am = new AttrMethods(); + else { + if (am.getter != null) { + final String msg = "Attribute " + attrName + + " has more than one getter"; + throw new NotCompliantMBeanException(msg); + } + } + am.getter = m; + attrMap.put(attrName, am); + } else if (name.startsWith("set") && name.length() > 3 + && m.getParameterTypes().length == 1 && + m.getReturnType() == void.class) { + // It's a setter + attrName = name.substring(3); + AttrMethods am = attrMap.get(attrName); + if (am == null) + am = new AttrMethods(); + else if (am.setter != null) { + final String msg = "Attribute " + attrName + + " has more than one setter"; + throw new NotCompliantMBeanException(msg); + } + am.setter = m; + attrMap.put(attrName, am); + } else { + // It's an operation + List ops = opMap.get(name); + if (ops == null) + ops = newList(); + ops.add(m); + opMap.put(name, ops); + } + } + /* Check that getters and setters are consistent. */ + for (Map.Entry entry : attrMap.entrySet()) { + AttrMethods am = entry.getValue(); + if (am.getter != null && am.setter != null && + am.getter.getReturnType() != am.setter.getParameterTypes()[0]) { + final String msg = "Getter and setter for " + entry.getKey() + + " have inconsistent types"; + throw new NotCompliantMBeanException(msg); + } + } + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, MBeanException, ReflectionException { + AttrMethods am = attrMap.get(attribute); + if (am == null || am.getter == null) + throw new AttributeNotFoundException(attribute); + return invokeMethod(am.getter); + } + + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, InvalidAttributeValueException, + MBeanException, ReflectionException { + String name = attribute.getName(); + AttrMethods am = attrMap.get(name); + if (am == null || am.setter == null) + throw new AttributeNotFoundException(name); + invokeMethod(am.setter, attribute.getValue()); + } + + public AttributeList getAttributes(String[] attributes) { + AttributeList list = new AttributeList(); + for (String attr : attributes) { + try { + list.add(new Attribute(attr, getAttribute(attr))); + } catch (Exception e) { + // OK: ignore per spec + } + } + return list; + } + + public AttributeList setAttributes(AttributeList attributes) { + AttributeList list = new AttributeList(); + // We carefully avoid using any new stuff from AttributeList here! + for (Iterator it = attributes.iterator(); it.hasNext(); ) { + Attribute attr = (Attribute) it.next(); + try { + setAttribute(attr); + list.add(attr); + } catch (Exception e) { + // OK: ignore per spec + } + } + return list; + } + + public Object invoke(String actionName, Object[] params, String[] signature) + throws MBeanException, ReflectionException { + if (params == null) + params = new Object[0]; + if (signature == null) + signature = new String[0]; + List methods = opMap.get(actionName); + if (methods == null) { + Exception x = new NoSuchMethodException(actionName); + throw new MBeanException(x); + } + Method found = null; + methodloop: + for (Method m : methods) { + Class[] msig = m.getParameterTypes(); + if (msig.length != signature.length) + continue methodloop; + for (int i = 0; i < msig.length; i++) { + if (!msig[i].getName().equals(signature[i])) + continue methodloop; + } + found = m; + break methodloop; + } + if (found == null) { + Exception x = new NoSuchMethodException( + actionName + Arrays.toString(signature)); + throw new MBeanException(x); + } + return invokeMethod(found, params); + } + + public MBeanInfo getMBeanInfo() { + // Attributes + List attrs = newList(); + for (Map.Entry attr : attrMap.entrySet()) { + String name = attr.getKey(); + AttrMethods am = attr.getValue(); + try { + attrs.add(new MBeanAttributeInfo( + name, name, am.getter, am.setter)); + } catch (IntrospectionException e) { // grrr + throw new RuntimeException(e); + } + } + + // Operations + List ops = newList(); + for (Map.Entry> op : opMap.entrySet()) { + String name = op.getKey(); + List methods = op.getValue(); + for (Method m : methods) + ops.add(new MBeanOperationInfo(name, m)); + } + + // Constructors + List constrs = newList(); + for (Constructor constr : std.getClass().getConstructors()) + constrs.add(new MBeanConstructorInfo("Constructor", constr)); + + // Notifications + MBeanNotificationInfo[] notifs; + if (std instanceof NotificationBroadcaster) + notifs = ((NotificationBroadcaster) std).getNotificationInfo(); + else + notifs = null; + + String className = std.getClass().getName(); + return new MBeanInfo( + className, className, + attrs.toArray(new MBeanAttributeInfo[0]), + constrs.toArray(new MBeanConstructorInfo[0]), + ops.toArray(new MBeanOperationInfo[0]), + notifs); + } + + private Object invokeMethod(Method m, Object... args) + throws MBeanException, ReflectionException { + return invokeSomething(m, std,args); + } + + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + return mbeanRegistration(std).preRegister(server, name); + } + + public void postRegister(Boolean registrationDone) { + mbeanRegistration(std).postRegister(registrationDone); + } + + public void preDeregister() throws Exception { + mbeanRegistration(std).preDeregister(); + } + + public void postDeregister() { + mbeanRegistration(std).postDeregister(); + } + + public Object getWrappedMBean() { + return std; + } + } + + private DynamicMBean standardToDynamic(Object std) + throws NotCompliantMBeanException { + return new StandardWrapper(std); + } + +// private static class NotifWrapper +// implements WrapDynamicMBean, NotificationEmitter { +// private final DynamicMBean mbean; +// +// NotifWrapper(DynamicMBean mbean) { +// this.mbean = mbean; +// } +// +// public Object getAttribute(String attribute) +// throws AttributeNotFoundException, MBeanException, ReflectionException { +// return mbean.getAttribute(attribute); +// } +// +// public void setAttribute(Attribute attribute) +// throws AttributeNotFoundException, InvalidAttributeValueException, +// MBeanException, ReflectionException { +// mbean.setAttribute(attribute); +// } +// +// public AttributeList getAttributes(String[] attributes) { +// return mbean.getAttributes(attributes); +// } +// +// public AttributeList setAttributes(AttributeList attributes) { +// return mbean.setAttributes(attributes); +// } +// +// public Object invoke( +// String actionName, Object[] params, String[] signature) +// throws MBeanException, ReflectionException { +// return mbean.invoke(actionName, params, signature); +// } +// +// public MBeanInfo getMBeanInfo() { +// return mbean.getMBeanInfo(); +// } +// +// public void removeNotificationListener( +// NotificationListener listener, NotificationFilter filter, Object handback) +// throws ListenerNotFoundException { +// ((NotificationEmitter) mbean).removeNotificationListener( +// listener, filter, handback); +// // ClassCastException if MBean is not an emitter +// } +// +// public void addNotificationListener( +// NotificationListener listener, NotificationFilter filter, Object handback) +// throws IllegalArgumentException { +// ((NotificationBroadcaster) mbean).addNotificationListener( +// listener, filter, handback); +// } +// +// public void removeNotificationListener(NotificationListener listener) +// throws ListenerNotFoundException { +// ((NotificationBroadcaster) mbean).removeNotificationListener(listener); +// } +// +// public MBeanNotificationInfo[] getNotificationInfo() { +// return ((NotificationBroadcaster) mbean).getNotificationInfo(); +// } +// +// public Object getWrappedMBean() { +// return getUserMBean(mbean); +// } +// } + + private static Object invokeSomething( + AccessibleObject ao, Object target, Object[] args) + throws MBeanException, ReflectionException { + try { + if (ao instanceof Method) + return ((Method) ao).invoke(target, args); + else + return ((Constructor) ao).newInstance(args); + } catch (InvocationTargetException e) { + try { + throw e.getCause(); + } catch (RuntimeException x) { + throw new RuntimeMBeanException(x); + } catch (Error x) { + throw new RuntimeErrorException(x); + } catch (Exception x) { + throw new MBeanException(x); + } catch (Throwable x) { + throw new RuntimeException(x); // neither Error nor Exception! + } + } catch (Exception e) { + throw new ReflectionException(e); + } + } + + private static Object getUserMBean(DynamicMBean mbean) { + if (mbean instanceof WrapDynamicMBean) + return ((WrapDynamicMBean) mbean).getWrappedMBean(); + return mbean; + } + + private Object getUserMBean(ObjectName name) + throws InstanceNotFoundException { + return getUserMBean(getMBean(name)); + } + + private static final MBeanRegistration noRegistration = + new MBeanRegistration() { + public ObjectName preRegister(MBeanServer server, ObjectName name) { + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + }; + + private static MBeanRegistration mbeanRegistration(Object object) { + if (object instanceof MBeanRegistration) + return (MBeanRegistration) object; + else + return noRegistration; + } + + private static List newList() { + return new ArrayList(); + } + + private static Map newMap() { + return new HashMap(); + } + + private static Set newSet() { + return new HashSet(); + } + } +} diff --git a/test/javax/management/MBeanServer/PostExceptionTest.java b/test/javax/management/MBeanServer/PostExceptionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d0e0aa3b8295852f1444797bb2b97d612b1f0265 --- /dev/null +++ b/test/javax/management/MBeanServer/PostExceptionTest.java @@ -0,0 +1,516 @@ +/* + * 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 6730926 + * @summary Check behaviour of MBeanServer when postRegister and postDeregister + * throw exceptions. + * @author Daniel Fuchs + * @compile PostExceptionTest.java + * @run main PostExceptionTest + */ + +import javax.management.*; +import java.io.Serializable; +import java.net.URL; +import java.util.EnumSet; +import javax.management.loading.MLet; + +public class PostExceptionTest { + + /** + * A test case where we instantiate an ExceptionalWombatMBean (or a + * subclass of it) which will throw the exception {@code t} from within + * the methods indicated by {@code where} + */ + public static class Case { + public final Throwable t; + public final EnumSet where; + public Case(Throwable t,EnumSet where) { + this.t=t; this.where=where; + } + } + + // Various methods to create an instance of Case in a single line + // -------------------------------------------------------------- + + public static Case caze(Throwable t, WHERE w) { + return new Case(t,EnumSet.of(w)); + } + public static Case caze(Throwable t, EnumSet where) { + return new Case(t,where); + } + public static Case caze(Throwable t, WHERE w, WHERE... rest) { + return new Case(t,EnumSet.of(w,rest)); + } + + /** + * Here is the list of our test cases: + */ + public static Case[] cases ={ + caze(new RuntimeException(),WHERE.PREREGISTER), + caze(new RuntimeException(),WHERE.POSTREGISTER), + caze(new RuntimeException(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER), + caze(new RuntimeException(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER), + caze(new Exception(),WHERE.PREREGISTER), + caze(new Exception(),WHERE.POSTREGISTER), + caze(new Exception(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER), + caze(new Exception(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER), + caze(new Error(),WHERE.PREREGISTER), + caze(new Error(),WHERE.POSTREGISTER), + caze(new Error(),WHERE.POSTREGISTER, WHERE.PREDEREGISTER), + caze(new Error(),WHERE.POSTREGISTER, WHERE.POSTDEREGISTER), + caze(new RuntimeException(),EnumSet.allOf(WHERE.class)), + caze(new Exception(),EnumSet.allOf(WHERE.class)), + caze(new Error(),EnumSet.allOf(WHERE.class)), + }; + + public static void main(String[] args) throws Exception { + System.out.println("Test behaviour of MBeanServer when postRegister " + + "or postDeregister throw exceptions"); + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + int failures = 0; + final ObjectName n = new ObjectName("test:type=Wombat"); + + // We're going to test each cases, using each of the 4 createMBean + // forms + registerMBean in turn to create the MBean. + // Wich method is used to create the MBean is indicated by "how" + // + for (Case caze:cases) { + for (CREATE how : CREATE.values()) { + failures+=test(mbs,n,how,caze.t,caze.where); + } + } + if (failures == 0) + System.out.println("Test passed"); + else { + System.out.println("TEST FAILED: " + failures + " failure(s)"); + System.exit(1); + } + } + + // Execute a test case composed of: + // mbs: The MBeanServer where the MBean will be registered, + // name: The name of that MBean + // how: How will the MBean be created/registered (which MBeanServer + // method) + // t: The exception/error that the MBean will throw + // where: In which pre/post register/deregister method the exception/error + // will be thrown + // + private static int test(MBeanServer mbs, ObjectName name, CREATE how, + Throwable t, EnumSet where) + throws Exception { + System.out.println("-------<"+how+"> / <"+t+"> / "+ where + "-------"); + + int failures = 0; + ObjectInstance oi = null; + Exception reg = null; // exception thrown by create/register + Exception unreg = null; // exception thrown by unregister + try { + // Create the MBean + oi = how.create(t, where, mbs, name); + } catch (Exception xx) { + reg=xx; + } + final ObjectName n = (oi==null)?name:oi.getObjectName(); + final boolean isRegistered = mbs.isRegistered(n); + try { + // If the MBean is registered, unregister it + if (isRegistered) mbs.unregisterMBean(n); + } catch (Exception xxx) { + unreg=xxx; + } + final boolean isUnregistered = !mbs.isRegistered(n); + if (!isUnregistered) { + // if the MBean is still registered (preDeregister threw an + // exception) signify to the MBean that it now should stop + // throwing anaything and unregister it. + JMX.newMBeanProxy(mbs, n, ExceptionalWombatMBean.class).end(); + mbs.unregisterMBean(n); + } + + // Now analyze the result. If we didn't ask the MBean to throw any + // exception then reg should be null. + if (where.isEmpty() && reg!=null) { + System.out.println("Unexpected registration exception: "+ + reg); + throw new RuntimeException("Unexpected registration exception: "+ + reg,reg); + } + + // If we didn't ask the MBean to throw any exception then unreg should + // also be null. + if (where.isEmpty() && unreg!=null) { + System.out.println("Unexpected unregistration exception: "+ + unreg); + throw new RuntimeException("Unexpected unregistration exception: "+ + unreg,unreg); + } + + // If we asked the MBean to throw an exception in either of preRegister + // or postRegister, then reg should not be null. + if ((where.contains(WHERE.PREREGISTER) + || where.contains(WHERE.POSTREGISTER))&& reg==null) { + System.out.println("Expected registration exception not " + + "thrown by "+where); + throw new RuntimeException("Expected registration exception not " + + "thrown by "+where); + } + + // If we asked the MBean not to throw any exception in preRegister + // then the MBean should have been registered, unregisterMBean should + // have been called. + // If we asked the MBean to throw an exception in either of preDeregister + // or postDeregister, then unreg should not be null. + if ((where.contains(WHERE.PREDEREGISTER) + || where.contains(WHERE.POSTDEREGISTER))&& unreg==null + && !where.contains(WHERE.PREREGISTER)) { + System.out.println("Expected unregistration exception not " + + "thrown by "+where); + throw new RuntimeException("Expected unregistration exception not " + + "thrown by "+where); + } + + // If we asked the MBean to throw an exception in preRegister + // then the MBean should not have been registered. + if (where.contains(WHERE.PREREGISTER)) { + if (isRegistered) { + System.out.println("MBean is still registered [" + + where+ + "]: "+name+" / "+reg); + throw new RuntimeException("MBean is still registered [" + + where+ + "]: "+name+" / "+reg,reg); + } + } + + // If we asked the MBean not to throw an exception in preRegister, + // but to throw an exception in postRegister, then the MBean should + // have been registered. + if (where.contains(WHERE.POSTREGISTER) && + !where.contains(WHERE.PREREGISTER)) { + if (!isRegistered) { + System.out.println("MBean is already unregistered [" + + where+ + "]: "+name+" / "+reg); + throw new RuntimeException("MBean is already unregistered [" + + where+ + "]: "+name+" / "+reg,reg); + } + } + + // If we asked the MBean to throw an exception in preRegister, + // check that the exception we caught was as expected. + // + if (where.contains(WHERE.PREREGISTER)) { + WHERE.PREREGISTER.check(reg, t); + } else if (where.contains(WHERE.POSTREGISTER)) { + // If we asked the MBean to throw an exception in postRegister, + // check that the exception we caught was as expected. + // We don't do this check if we asked the MBean to also throw an + // exception in pre register, because postRegister will not have + // been called. + WHERE.POSTREGISTER.check(reg, t); + } + + if (!isRegistered) return failures; + + // The MBean was registered, so unregisterMBean was called. Check + // unregisterMBean exceptions... + // + + // If we asked the MBean to throw an exception in preDeregister + // then the MBean should not have been deregistered. + if (where.contains(WHERE.PREDEREGISTER)) { + if (isUnregistered) { + System.out.println("MBean is already unregistered [" + + where+ + "]: "+name+" / "+unreg); + throw new RuntimeException("MBean is already unregistered [" + + where+ + "]: "+name+" / "+unreg,unreg); + } + } + + // If we asked the MBean not to throw an exception in preDeregister, + // but to throw an exception in postDeregister, then the MBean should + // have been deregistered. + if (where.contains(WHERE.POSTDEREGISTER) && + !where.contains(WHERE.PREDEREGISTER)) { + if (!isUnregistered) { + System.out.println("MBean is not unregistered [" + + where+ + "]: "+name+" / "+unreg); + throw new RuntimeException("MBean is not unregistered [" + + where+ + "]: "+name+" / "+unreg,unreg); + } + } + + // If we asked the MBean to throw an exception in preDeregister, + // check that the exception we caught was as expected. + // + if (where.contains(WHERE.PREDEREGISTER)) { + WHERE.PREDEREGISTER.check(unreg, t); + } else if (where.contains(WHERE.POSTDEREGISTER)) { + // If we asked the MBean to throw an exception in postDeregister, + // check that the exception we caught was as expected. + // We don't do this check if we asked the MBean to also throw an + // exception in pre register, because postRegister will not have + // been called. + WHERE.POSTDEREGISTER.check(unreg, t); + } + return failures; + } + + /** + * This enum lists the 4 methods in MBeanRegistration. + */ + public static enum WHERE { + + PREREGISTER, POSTREGISTER, PREDEREGISTER, POSTDEREGISTER; + + // Checks that an exception thrown by the MBeanServer correspond to + // what is expected when an MBean throws an exception in this + // MBeanRegistration method ("this" is one of the 4 enum values above) + // + public void check(Exception thrown, Throwable t) + throws Exception { + if (t instanceof RuntimeException) { + if (!(thrown instanceof RuntimeMBeanException)) { + System.out.println("Expected RuntimeMBeanException, got "+ + thrown); + throw new Exception("Expected RuntimeMBeanException, got "+ + thrown); + } + } else if (t instanceof Error) { + if (!(thrown instanceof RuntimeErrorException)) { + System.out.println("Expected RuntimeErrorException, got "+ + thrown); + throw new Exception("Expected RuntimeErrorException, got "+ + thrown); + } + } else if (t instanceof Exception) { + if (EnumSet.of(POSTDEREGISTER,POSTREGISTER).contains(this)) { + if (!(thrown instanceof RuntimeMBeanException)) { + System.out.println("Expected RuntimeMBeanException, got "+ + thrown); + throw new Exception("Expected RuntimeMBeanException, got "+ + thrown); + } + if (! (thrown.getCause() instanceof RuntimeException)) { + System.out.println("Bad cause: " + + "expected RuntimeException, " + + "got <"+thrown.getCause()+">"); + throw new Exception("Bad cause: " + + "expected RuntimeException, " + + "got <"+thrown.getCause()+">"); + } + } + if (EnumSet.of(PREDEREGISTER,PREREGISTER).contains(this)) { + if (!(thrown instanceof MBeanRegistrationException)) { + System.out.println("Expected " + + "MBeanRegistrationException, got "+ + thrown); + throw new Exception("Expected " + + "MBeanRegistrationException, got "+ + thrown); + } + if (! (thrown.getCause() instanceof Exception)) { + System.out.println("Bad cause: " + + "expected Exception, " + + "got <"+thrown.getCause()+">"); + throw new Exception("Bad cause: " + + "expected Exception, " + + "got <"+thrown.getCause()+">"); + } + } + } + + } + } + + /** + * This enum lists the 5 methods to create and register an + * ExceptionalWombat MBean + */ + public static enum CREATE { + + CREATE1() { + // Creates an ExceptionalWombat MBean using createMBean form #1 + public ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception { + ExceptionallyHackyWombat.t = t; + ExceptionallyHackyWombat.w = where; + return server.createMBean( + ExceptionallyHackyWombat.class.getName(), + name); + } + }, + CREATE2() { + // Creates an ExceptionalWombat MBean using createMBean form #2 + public ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception { + ExceptionallyHackyWombat.t = t; + ExceptionallyHackyWombat.w = where; + final ObjectName loaderName = registerMLet(server); + return server.createMBean( + ExceptionallyHackyWombat.class.getName(), + name, loaderName); + } + }, + CREATE3() { + // Creates an ExceptionalWombat MBean using createMBean form #3 + public ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception { + final Object[] params = {t, where}; + final String[] signature = {Throwable.class.getName(), + EnumSet.class.getName() + }; + return server.createMBean( + ExceptionalWombat.class.getName(), name, + params, signature); + } + }, + CREATE4() { + // Creates an ExceptionalWombat MBean using createMBean form #4 + public ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception { + final Object[] params = {t, where}; + final String[] signature = {Throwable.class.getName(), + EnumSet.class.getName() + }; + return server.createMBean( + ExceptionalWombat.class.getName(), name, + registerMLet(server), params, signature); + } + }, + REGISTER() { + // Creates an ExceptionalWombat MBean using registerMBean + public ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception { + final ExceptionalWombat wombat = + new ExceptionalWombat(t, where); + return server.registerMBean(wombat, name); + } + }; + + // Creates an ExceptionalWombat MBean using the method denoted by this + // Enum value - one of CREATE1, CREATE2, CREATE3, CREATE4, or REGISTER. + public abstract ObjectInstance create(Throwable t, EnumSet where, + MBeanServer server, ObjectName name) throws Exception; + + // This is a bit of a hack - we use an MLet that delegates to the + // System ClassLoader so that we can use createMBean form #2 and #3 + // while still using the same class loader (system). + // This is necessary to make the ExceptionallyHackyWombatMBean work ;-) + // + public ObjectName registerMLet(MBeanServer server) throws Exception { + final ObjectName name = new ObjectName("test:type=MLet"); + if (server.isRegistered(name)) { + return name; + } + final MLet mlet = new MLet(new URL[0], + ClassLoader.getSystemClassLoader()); + return server.registerMBean(mlet, name).getObjectName(); + } + } + + /** + *A Wombat MBean that can throw exceptions or errors in any of the + * MBeanRegistration methods. + */ + public static interface ExceptionalWombatMBean { + // Tells the MBean to stop throwing exceptions - we sometime + // need to call this at the end of the test so that we can + // actually unregister the MBean. + public void end(); + } + + /** + *A Wombat MBean that can throw exceptions or errors in any of the + * MBeanRegistration methods. + */ + public static class ExceptionalWombat + implements ExceptionalWombatMBean, MBeanRegistration { + + private final Throwable throwable; + private final EnumSet where; + private volatile boolean end=false; + + public ExceptionalWombat(Throwable t, EnumSet where) { + this.throwable=t; this.where=where; + } + private Exception doThrow() { + if (throwable instanceof Error) + throw (Error)throwable; + if (throwable instanceof RuntimeException) + throw (RuntimeException)throwable; + return (Exception)throwable; + } + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (!end && where.contains(WHERE.PREREGISTER)) + throw doThrow(); + return name; + } + + public void postRegister(Boolean registrationDone) { + if (!end && where.contains(WHERE.POSTREGISTER)) + throw new RuntimeException(doThrow()); + } + + public void preDeregister() throws Exception { + if (!end && where.contains(WHERE.PREDEREGISTER)) + throw doThrow(); + } + + public void postDeregister() { + if (!end && where.contains(WHERE.POSTREGISTER)) + throw new RuntimeException(doThrow()); + } + + public void end() { + this.end=true; + } + } + + /** + * This is a big ugly hack to call createMBean form #1 and #2 - where + * the empty constructor is used. Since we still want to supply parameters + * to the ExceptionalWombat super class, we temporarily store these + * parameter value in a static volatile before calling create MBean. + * Of course this only works because our test is sequential and single + * threaded, and nobody but our test uses this ExceptionallyHackyWombat. + */ + public static class ExceptionallyHackyWombat extends ExceptionalWombat { + public static volatile Throwable t; + public static volatile EnumSet w; + public ExceptionallyHackyWombat() { + super(t,w); + } + } + +} diff --git a/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f2114f967a06d83d3f9e9739cf237338799bc833 --- /dev/null +++ b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java @@ -0,0 +1,441 @@ +/* + * Copyright 2003-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 + * @summary Test named MBeanServers. + * @author Daniel Fuchs + * @bug 6299231 + * @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 --git a/test/javax/management/ObjectName/ApplyWildcardTest.java b/test/javax/management/ObjectName/ApplyWildcardTest.java index b265e7bf6e1041f8feb682cda88df9c4c6ac683c..0301636e96f16b7b12f80d903c4552934ed44259 100644 --- a/test/javax/management/ObjectName/ApplyWildcardTest.java +++ b/test/javax/management/ObjectName/ApplyWildcardTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -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 @@ public class ApplyWildcardTest { { "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 @@ public class ApplyWildcardTest { { "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 @@ public class ApplyWildcardTest { 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 @@ public class ApplyWildcardTest { 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 @@ public class ApplyWildcardTest { 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 --git a/test/javax/management/ObjectName/SerialCompatTest.java b/test/javax/management/ObjectName/SerialCompatTest.java index baa748a5fd73d0763b8a887baabc3d68485cb81f..ff7b20d335a3903245339d9f8d0c555a1adf9ec6 100644 --- a/test/javax/management/ObjectName/SerialCompatTest.java +++ b/test/javax/management/ObjectName/SerialCompatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -23,9 +23,9 @@ /* * @test - * @bug 6211220 + * @bug 6211220 6616825 * @summary Test that jmx.serial.form=1.0 works for ObjectName - * @author Eamonn McManus + * @author Eamonn McManus, Daniel Fuchs * @run clean SerialCompatTest * @run build SerialCompatTest * @run main/othervm SerialCompatTest @@ -36,19 +36,8 @@ import java.util.*; import javax.management.ObjectName; public class SerialCompatTest { - public static void main(String[] args) throws Exception { - System.setProperty("jmx.serial.form", "1.0"); - /* Check that we really are in jmx.serial.form=1.0 mode. - The property is frozen the first time the ObjectName class - is referenced so checking that it is set to the correct - value now is not enough. */ - ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class); - if (osc.getFields().length != 6) { - throw new Exception("Not using old serial form: fields: " + - Arrays.asList(osc.getFields())); - // new serial form has no fields, uses writeObject - } + public static void check6211220() throws Exception { ObjectName on = new ObjectName("a:b=c"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -62,56 +51,214 @@ public class SerialCompatTest { // if the bug is present, these will get NullPointerException for (int i = 0; i <= 11; i++) { + String msg = "6211220 case(" + i + ")"; + try { + switch (i) { + case 0: + check(msg, on1.getDomain().equals("a")); + break; + case 1: + check(msg, on1.getCanonicalName().equals("a:b=c")); + break; + case 2: + check(msg, on1.getKeyPropertyListString() + .equals("b=c")); + break; + case 3: + check(msg, on1.getCanonicalKeyPropertyListString() + .equals("b=c")); + break; + case 4: + check(msg, on1.getKeyProperty("b").equals("c")); + break; + case 5: + check(msg, on1.getKeyPropertyList() + .equals(Collections.singletonMap("b", "c"))); + break; + case 6: + check(msg, !on1.isDomainPattern()); + break; + case 7: + check(msg, !on1.isPattern()); + break; + case 8: + check(msg, !on1.isPropertyPattern()); + break; + case 9: + check(msg, on1.equals(on)); + break; + case 10: + check(msg, on.equals(on1)); + break; + case 11: + check(msg, on1.apply(on)); + break; + default: + throw new Exception(msg + ": Test incorrect"); + } + } catch (Exception e) { + System.out.println(msg + ": Test failed with exception:"); + e.printStackTrace(System.out); + failed = true; + } + } + + if (failed) { + throw new Exception("Some tests for 6211220 failed"); + } else { + System.out.println("All tests for 6211220 passed"); + } + } + + static void checkName(String testname, ObjectName on) + throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(on); + oos.close(); + byte[] bytes = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bis); + ObjectName on1 = (ObjectName) ois.readObject(); + // if the bug is present, these will get NullPointerException + for (int i = 0; i <= 11; i++) { + String msg = testname + " case(" + i + ")"; try { switch (i) { - case 0: - check(on1.getDomain().equals("a")); break; - case 1: - check(on1.getCanonicalName().equals("a:b=c")); break; - case 2: - check(on1.getKeyPropertyListString().equals("b=c")); break; - case 3: - check(on1.getCanonicalKeyPropertyListString().equals("b=c")); - break; - case 4: - check(on1.getKeyProperty("b").equals("c")); break; - case 5: - check(on1.getKeyPropertyList() - .equals(Collections.singletonMap("b", "c"))); break; - case 6: - check(!on1.isDomainPattern()); break; - case 7: - check(!on1.isPattern()); break; - case 8: - check(!on1.isPropertyPattern()); break; - case 9: - check(on1.equals(on)); break; - case 10: - check(on.equals(on1)); break; - case 11: - check(on1.apply(on)); break; - default: - throw new Exception("Test incorrect: case: " + i); + case 0: + check(msg, on1.getDomain().equals(on.getDomain())); + break; + case 1: + check(msg, on1.getCanonicalName(). + equals(on.getCanonicalName())); + break; + case 2: + check(msg, on1.getKeyPropertyListString(). + equals(on.getKeyPropertyListString())); + break; + case 3: + check(msg, on1.getCanonicalKeyPropertyListString(). + equals(on.getCanonicalKeyPropertyListString())); + break; + case 4: + for (Object ko : on1.getKeyPropertyList().keySet()) { + final String key = (String) ko; + check(msg, on1.getKeyProperty(key). + equals(on.getKeyProperty(key))); + } + for (Object ko : on.getKeyPropertyList().keySet()) { + final String key = (String) ko; + check(msg, on1.getKeyProperty(key). + equals(on.getKeyProperty(key))); + } + case 5: + check(msg, on1.getKeyPropertyList() + .equals(on.getKeyPropertyList())); + break; + case 6: + check(msg, on1.isDomainPattern()==on.isDomainPattern()); + break; + case 7: + check(msg, on1.isPattern() == on.isPattern()); + break; + case 8: + check(msg, + on1.isPropertyPattern()==on.isPropertyPattern()); + break; + case 9: + check(msg, on1.equals(on)); + break; + case 10: + check(msg, on.equals(on1)); + break; + case 11: + if (!on.isPattern()) { + check(msg, on1.apply(on)); + } + break; + default: + throw new Exception("Test incorrect: case: " + i); } } catch (Exception e) { - System.out.println("Test failed with exception:"); + System.out.println("Test (" + i + ") failed with exception:"); e.printStackTrace(System.out); failed = true; } } - if (failed) + } + private static String[] names6616825 = { + "a:b=c", "a:b=c,*", "*:*", ":*", ":b=c", ":b=c,*", + "a:*,b=c", ":*", ":*,b=c", "*x?:k=\"x\\*z\"", "*x?:k=\"x\\*z\",*", + "*x?:*,k=\"x\\*z\"", "*x?:k=\"x\\*z\",*,b=c" + }; + + static void check6616825() throws Exception { + System.out.println("Testing 616825"); + for (String n : names6616825) { + final ObjectName on; + try { + on = new ObjectName(n); + } catch (Exception x) { + failed = true; + System.out.println("Unexpected failure for 6616825 [" + n + + "]: " + x); + x.printStackTrace(System.out); + continue; + } + try { + checkName("616825 " + n, on); + } catch (Exception x) { + failed = true; + System.out.println("6616825 failed for [" + n + "]: " + x); + x.printStackTrace(System.out); + } + } + + if (failed) { + throw new Exception("Some tests for 6616825 failed"); + } else { + System.out.println("All tests for 6616825 passed"); + } + } + + public static void main(String[] args) throws Exception { + System.setProperty("jmx.serial.form", "1.0"); + + /* Check that we really are in jmx.serial.form=1.0 mode. + The property is frozen the first time the ObjectName class + is referenced so checking that it is set to the correct + value now is not enough. */ + ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class); + if (osc.getFields().length != 6) { + throw new Exception("Not using old serial form: fields: " + + Arrays.asList(osc.getFields())); + // new serial form has no fields, uses writeObject + } + + try { + check6211220(); + } catch (Exception x) { + System.err.println(x.getMessage()); + } + try { + check6616825(); + } catch (Exception x) { + System.err.println(x.getMessage()); + } + + if (failed) { throw new Exception("Some tests failed"); - else + } else { System.out.println("All tests passed"); + } } - private static void check(boolean condition) { + private static void check(String msg, boolean condition) { if (!condition) { - new Throwable("Test failed").printStackTrace(System.out); + new Throwable("Test failed " + msg).printStackTrace(System.out); failed = true; } } - private static boolean failed; } diff --git a/test/javax/management/ObjectName/ValueOfTest.java b/test/javax/management/ObjectName/ValueOfTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4a68a3d4c5ce55d73ae344490c40468f15ce693a --- /dev/null +++ b/test/javax/management/ObjectName/ValueOfTest.java @@ -0,0 +1,175 @@ +/* + * 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 6734813 + * @summary Test the ObjectName.valueOf methods + * @author Eamonn McManus + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Hashtable; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +public class ValueOfTest { + public static void main(String[] args) throws Exception { + // Calls that should work + testPositive("d:foo=bar,baz=buh"); + testPositive("foo", "bar", "baz"); + Hashtable h = new Hashtable(); + h.put("foo", "bar"); + h.put("baz", "buh"); + testPositive("domain", h); + + // Calls that should not work + testNegative("d"); + testNegative("d:"); + testNegative("d::foo=bar"); + testNegative("d:", "foo", "bar"); + testNegative("d", "foo=", "bar"); + testNegative("d:", h); + testNegative("d", new Hashtable()); + } + + private static void testPositive(Object... args) throws Exception { + Method valueOf = valueOfMethod(args); + Method getInstance = getInstanceMethod(args); + Constructor constructor = constructor(args); + + Object valueOfValue = valueOf.invoke(null, args); + Object getInstanceValue = getInstance.invoke(null, args); + Object constructorValue = constructor.newInstance(args); + + String argString = + Arrays.toString(args).replace('[', '(').replace(']', ')'); + + if (!valueOfValue.equals(getInstanceValue)) { + throw new Exception( + "valueOf" + argString + " differs from getInstance" + + argString); + } + + if (!valueOfValue.equals(constructorValue)) { + throw new Exception( + "valueOf" + argString + " differs from new ObjectName " + + argString); + } + + System.out.println("OK: valueOf" + argString); + } + + private static void testNegative(Object... args) throws Exception { + Method valueOf = valueOfMethod(args); + Method getInstance = getInstanceMethod(args); + + String argString = + Arrays.toString(args).replace('[', '(').replace(']', ')'); + + final Throwable valueOfException; + try { + valueOf.invoke(null, args); + throw new Exception("valueOf" + argString + " did not fail but should"); + } catch (InvocationTargetException e) { + valueOfException = e.getCause(); + } + if (!(valueOfException instanceof IllegalArgumentException)) { + throw new Exception( + "valueOf" + argString + " threw " + + valueOfException.getClass().getName() + " instead of " + + "IllegalArgumentException", valueOfException); + } + + final Throwable valueOfCause = valueOfException.getCause(); + if (!(valueOfCause instanceof MalformedObjectNameException)) { + throw new Exception( + "valueOf" + argString + " threw exception with wrong " + + "type of cause", valueOfCause); + } + + if (!valueOfException.getMessage().equals(valueOfCause.getMessage())) { + // The IllegalArgumentException should have the same message as + // the MalformedObjectNameException it wraps. + // This isn't specified but is desirable. + throw new Exception( + "valueOf" + argString + ": message in wrapping " + + "IllegalArgumentException (" + valueOfException.getMessage() + + ") differs from message in wrapped " + + "MalformedObjectNameException (" + valueOfCause.getMessage() + + ")"); + } + + final Throwable getInstanceException; + try { + getInstance.invoke(null, args); + throw new Exception("getInstance" + argString + " did not fail but should"); + } catch (InvocationTargetException e) { + getInstanceException = e.getCause(); + } + if (!(getInstanceException instanceof MalformedObjectNameException)) { + throw new Exception( + "getInstance" + argString + " threw wrong exception", + getInstanceException); + } + + if (!valueOfException.getMessage().equals(getInstanceException.getMessage())) { + // Again this is not specified. + throw new Exception( + "Exception message from valueOf" + argString + " (" + + valueOfException.getMessage() + ") differs from message " + + "from getInstance" + argString + " (" + + getInstanceException.getMessage() + ")"); + } + + System.out.println("OK (correct exception): valueOf" + argString); + } + + private static Method valueOfMethod(Object[] args) throws Exception { + return method("valueOf", args); + } + + private static Method getInstanceMethod(Object[] args) throws Exception { + return method("getInstance", args); + } + + private static Method method(String name, Object[] args) throws Exception { + Class[] argTypes = argTypes(args); + return ObjectName.class.getMethod(name, argTypes); + } + + private static Constructor constructor(Object[] args) throws Exception { + Class[] argTypes = argTypes(args); + return ObjectName.class.getConstructor(argTypes); + } + + private static Class[] argTypes(Object[] args) { + Class[] argTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) + argTypes[i] = args[i].getClass(); + return argTypes; + } +} diff --git a/test/javax/management/eventService/AddRemoveListenerTest.java b/test/javax/management/eventService/AddRemoveListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..72a8c6926a08a72680976cc101c671c8d1225282 --- /dev/null +++ b/test/javax/management/eventService/AddRemoveListenerTest.java @@ -0,0 +1,371 @@ +/* + * 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 AddRemoveListenerTest.java + * @bug 5108776 + * @summary Basic test for EventClient to see internal thread management. + * @author Shanliang JIANG + * @run clean AddRemoveListenerTest + * @run build AddRemoveListenerTest + * @run main AddRemoveListenerTest + */ + +import java.io.IOException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.FetchingEventRelay; +import javax.management.event.RMIPushEventRelay; +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; + + +// This thread creates a single MBean that emits a number of parallel +// sequences of notifications. Each sequence is distinguished by an id +// and each id corresponds to a thread that is filtering the notifications +// so it only sees its own ones. The notifications for a given id have +// contiguous sequence numbers and each thread checks that the notifications +// it receives do indeed have these numbers. If notifications are lost or +// if the different sequences interfere with each other then the test will +// fail. As an added tweak, a "noise" thread periodically causes notifications +// to be emitted that do not correspond to any sequence and do not have any id. +public class AddRemoveListenerTest { + + private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(); + private static ObjectName emitter; + private static NotificationSender emitterImpl; + private static JMXServiceURL url; + private static JMXConnectorServer server; + + private static int toSend = 100; + private static final long bigWaiting = 10000; + private static int counter = 0; + private static int jobs = 10; + private static int endedJobs = 0; + + private static volatile String failure; + + public static void main(String[] args) throws Exception { + System.out.println(">>> Test on multiple adding/removing listeners."); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + emitter = new ObjectName("Default:name=NotificationSender"); + emitterImpl = new NotificationSender(); + mbeanServer.registerMBean(emitterImpl, emitter); + + String[] types = new String[]{"PushEventRelay", "FetchingEventRelay"}; + String[] protos = new String[]{"rmi", "iiop", "jmxmp"}; + for (String prot : protos) { + url = new JMXServiceURL(prot, null, 0); + + try { + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + null, mbeanServer); + server.start(); + } catch (Exception e) { + System.out.println(">>> Skip "+prot+", not supported."); + continue; + } + + url = server.getAddress(); + + // noise + Thread noise = new Thread(new Runnable() { + public void run() { + while (true) { + emitterImpl.sendNotif(1, null); + try { + Thread.sleep(10); + } catch (Exception e) { + // OK + } + } + } + }); + noise.setDaemon(true); + noise.start(); + + try { + for (String type: types) { + System.out.println("\n\n>>> Testing "+type+" on "+url+" ..."); + JMXConnector conn = newConn(); + try { + testType(type, conn); + } finally { + conn.close(); + System.out.println(">>> Testing "+type+" on "+url+" ... done"); + } + } + } finally { + server.stop(); + } + } + } + + private static void testType(String type, JMXConnector conn) throws Exception { + Thread[] threads = new Thread[jobs]; + for (int i=0; i 0 && failure == null) { + AddRemoveListenerTest.class.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + if (endedJobs != jobs && failure == null) { + throw new RuntimeException("Need to set bigger waiting timeout?"); + } + + endedJobs = 0; + } + + public static class Job implements Runnable { + public Job(String type, JMXConnector conn) { + this.type = type; + this.conn = conn; + } + public void run() { + try { + test(type, conn); + + synchronized(AddRemoveListenerTest.class) { + endedJobs++; + if (endedJobs>=jobs) { + AddRemoveListenerTest.class.notify(); + } + } + } catch (RuntimeException re) { + throw re; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private final String type; + private final JMXConnector conn; + } + + private static void test(String type, JMXConnector conn) throws Exception { + EventClient ec = newEventClient(type, conn); + try { + test(type, conn, ec); + } finally { + ec.close(); + } + } + + private static void test(String type, JMXConnector conn, EventClient ec) + throws Exception { + String id = getId(); + + Listener listener = new Listener(id); + Filter filter = new Filter(id); + + System.out.println(">>> ("+id+") To receive notifications "+toSend); + ec.addNotificationListener(emitter, + listener, filter, null); + + emitterImpl.sendNotif(toSend, id); + listener.waitNotifs(bigWaiting, toSend); + if (listener.received != toSend) { + throw new RuntimeException(">>> ("+id+") Expected to receive: " + +toSend+", but got: "+listener.received); + } + + listener.clear(); + ec.removeNotificationListener(emitter, listener, filter, null); + + System.out.println(">>> ("+id+") Repeat adding and removing ..."); + for (int j=0; j<10; j++) { + ec.addNotificationListener(emitter, dummyListener, null, id); + Thread.yield(); // allow to start listening + ec.removeNotificationListener(emitter, dummyListener, null, id); + } + + System.out.println(">>> ("+id+") To receive again notifications "+toSend); + ec.addNotificationListener(emitter, + listener, filter, null); + + emitterImpl.sendNotif(toSend, id); + listener.waitNotifs(bigWaiting, toSend); + Thread.yield(); //any duplicated? + if (listener.received != toSend) { + throw new RuntimeException("("+id+") Expected to receive: " + +toSend+", but got: "+listener.received); + } + } + +//-------------------------- +// private classes +//-------------------------- + + private static class Listener implements NotificationListener { + public Listener(String id) { + this.id = id; + } + public void handleNotification(Notification notif, Object handback) { + if (!id.equals(notif.getUserData())) { + System.out.println("("+id+") Filter error, my id is: "+id+ + ", but got "+notif.getUserData()); + System.exit(1); + } + + synchronized (this) { + received++; + + if(++sequenceNB != notif.getSequenceNumber()) { + fail("(" + id + ") Wrong sequence number, expected: " + +sequenceNB+", but got: "+notif.getSequenceNumber()); + } + if (received >= toSend || failure != null) { + this.notify(); + } + } + } + + public void waitNotifs(long timeout, int nb) throws Exception { + long toWait = timeout; + long stopTime = System.currentTimeMillis() + timeout; + synchronized(this) { + while (received < nb && toWait > 0 && failure == null) { + this.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + } + + public void clear() { + synchronized(this) { + received = 0; + sequenceNB = -1; + } + } + + private String id; + private int received = 0; + + private long sequenceNB = -1; + } + + private static class Filter implements NotificationFilter { + public Filter(String id) { + this.id = id; + } + + public boolean isNotificationEnabled(Notification n) { + return id.equals(n.getUserData()); + } + private String id; + } + + private static NotificationListener dummyListener = new NotificationListener() { + public void handleNotification(Notification notif, Object handback) { + } + }; + + public static class NotificationSender extends NotificationBroadcasterSupport + implements NotificationSenderMBean { + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotif(int nb, String userData) { + long sequenceNumber = 0; + for (int i = 0; i notifQueue = + new ArrayBlockingQueue(10); + NotificationListener countListener = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + System.out.println("Received: " + notification); + notifQueue.add(notification); + if (!"tiddly".equals(handback)) { + System.err.println("TEST FAILED: bad handback: " + handback); + System.exit(1); + } + } + }; + + final AtomicInteger filterCount = new AtomicInteger(0); + NotificationFilter countFilter = new NotificationFilter() { + private static final long serialVersionUID = 1234L; + + public boolean isNotificationEnabled(Notification notification) { + System.out.println("Filter called for: " + notification); + filterCount.incrementAndGet(); + return true; + } + }; + + client.addNotificationListener(name, countListener, countFilter, "tiddly"); + + assertEquals("Initial notif count", 0, notifQueue.size()); + assertEquals("Initial filter count", 0, filterCount.get()); + + Notification n = nextNotif(name); + mbean.send(n); + + System.out.println("Waiting for notification to arrive..."); + + Notification n1 = notifQueue.poll(10, TimeUnit.SECONDS); + + assertEquals("Received notif", n, n1); + assertEquals("Notif queue size after receive", 0, notifQueue.size()); + assertEquals("Filter count after notif", 1, filterCount.get()); + assertEquals("Lost notif count", 0, lostCountSema.availablePermits()); + + System.out.println("Dropping notifs"); + + UdpEventForwarder.setDrop(true); + for (int i = 0; i < 3; i++) + mbean.send(nextNotif(name)); + UdpEventForwarder.setDrop(false); + + Thread.sleep(2); + assertEquals("Notif queue size after drops", 0, notifQueue.size()); + + System.out.println("Turning off dropping and sending a notif"); + n = nextNotif(name); + mbean.send(n); + + System.out.println("Waiting for dropped notifications to be detected..."); + boolean acquired = lostCountSema.tryAcquire(3, 5, TimeUnit.SECONDS); + assertEquals("Correct count of lost notifs", true, acquired); + + n1 = notifQueue.poll(10, TimeUnit.SECONDS); + assertEquals("Received non-dropped notif", n, n1); + + assertEquals("Notif queue size", 0, notifQueue.size()); + assertEquals("Filter count after drops", 5, filterCount.get()); + + Thread.sleep(10); + assertEquals("Further lost-notifs", 0, lostCountSema.availablePermits()); + + client.close(); + + System.out.println("TEST PASSED"); + } + + private static AtomicLong nextSeqNo = new AtomicLong(0); + private static Notification nextNotif(ObjectName name) { + long n = nextSeqNo.incrementAndGet(); + return new Notification("type", name, n, "" + n); + } + + private static void assertEquals(String what, Object expected, Object got) { + if (equals(expected, got)) + System.out.println(what + " = " + expected + ", as expected"); + else { + Map traces = Thread.getAllStackTraces(); + for (Thread t : traces.keySet()) { + System.out.println(t.getName()); + for (StackTraceElement elmt : traces.get(t)) { + System.out.println(" " + elmt); + } + } + throw new RuntimeException( + "TEST FAILED: " + what + " is " + got + "; should be " + + expected); + } + } + + private static boolean equals(Object expected, Object got) { + if (!(expected instanceof Notification)) + return expected.equals(got); + if (expected.getClass() != got.getClass()) + return false; + // Notification doesn't override Object.equals so two distinct + // notifs are never equal even if they have the same contents. + // Although the test doesn't serialize the notifs, if at some + // stage it did then it would fail because the deserialized notif + // was not equal to the original one. Therefore we compare enough + // notif fields to detect when notifs really are different. + Notification en = (Notification) expected; + Notification gn = (Notification) got; + return (en.getType().equals(gn.getType()) && + en.getSource().equals(gn.getSource()) && + en.getSequenceNumber() == gn.getSequenceNumber()); + } +} diff --git a/test/javax/management/eventService/EventClientExecutorTest.java b/test/javax/management/eventService/EventClientExecutorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..19d6afdf8144e0d65c8249be6d1b84158e2c2a00 --- /dev/null +++ b/test/javax/management/eventService/EventClientExecutorTest.java @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along 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 that the various Executor parameters in an EventClient do + * what they are supposed to. + * @author Eamonn McManus + */ + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.FetchingEventRelay; +import javax.management.remote.MBeanServerForwarder; + +public class EventClientExecutorTest { + private static volatile String failure; + private static final Set testedPrefixes = new HashSet(); + + public static void main(String[] args) throws Exception { + Executor fetchExecutor = Executors.newSingleThreadExecutor( + new NamedThreadFactory("FETCH")); + Executor listenerExecutor = Executors.newSingleThreadExecutor( + new NamedThreadFactory("LISTENER")); + ScheduledExecutorService leaseScheduler = + Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("LEASE")); + + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(); + mbsf.setMBeanServer(mbs); + mbs = mbsf; + + EventClientDelegateMBean ecd = EventClientDelegate.getProxy(mbs); + ecd = (EventClientDelegateMBean) Proxy.newProxyInstance( + EventClientDelegateMBean.class.getClassLoader(), + new Class[] {EventClientDelegateMBean.class}, + new DelegateCheckIH(ecd)); + + ObjectName mbeanName = new ObjectName("d:type=Notifier"); + Notifier notifier = new Notifier(); + mbs.registerMBean(notifier, mbeanName); + + FetchingEventRelay eventRelay = new FetchingEventRelay( + ecd, fetchExecutor); + EventClient ec = new EventClient( + ecd, eventRelay, listenerExecutor, leaseScheduler, 1000L); + NotificationListener checkListener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + assertThreadName("listener dispatch", "LISTENER"); + } + }; + ec.addNotificationListener(mbeanName, checkListener, null, null); + + mbs.invoke(mbeanName, "send", null, null); + + // Now wait until we have seen all three thread types. + long deadline = System.currentTimeMillis() + 5000; + synchronized (testedPrefixes) { + while (testedPrefixes.size() < 3 && failure == null) { + long remain = deadline - System.currentTimeMillis(); + if (remain <= 0) { + fail("Timed out waiting for all three thread types to show, " + + "saw only " + testedPrefixes); + break; + } + try { + testedPrefixes.wait(remain); + } catch (InterruptedException e) { + fail("Unexpected InterruptedException"); + break; + } + } + } + + // We deliberately don't close the EventClient to check that it has + // not created any non-daemon threads. + + if (failure != null) + throw new Exception("TEST FAILED: " + failure); + else + System.out.println("TEST PASSED"); + } + + public static interface NotifierMBean { + public void send(); + } + + public static class Notifier extends NotificationBroadcasterSupport + implements NotifierMBean { + public void send() { + Notification n = new Notification("a.b.c", this, 0L); + sendNotification(n); + } + } + + static void fail(String why) { + System.out.println("FAIL: " + why); + failure = why; + } + + static void assertThreadName(String what, String prefix) { + String name = Thread.currentThread().getName(); + if (!name.startsWith(prefix)) { + fail("Wrong thread for " + what + ": " + name); + return; + } + + synchronized (testedPrefixes) { + if (testedPrefixes.add(prefix)) + testedPrefixes.notify(); + } + } + + private static class DelegateCheckIH implements InvocationHandler { + private final EventClientDelegateMBean ecd; + + public DelegateCheckIH(EventClientDelegateMBean ecd) { + this.ecd = ecd; + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + String methodName = method.getName(); + if (methodName.equals("fetchNotifications")) + assertThreadName("fetchNotifications", "FETCH"); + else if (methodName.equals("lease")) + assertThreadName("lease renewal", "LEASE"); + try { + return method.invoke(ecd, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + } + + private static class NamedThreadFactory implements ThreadFactory { + private final String namePrefix; + private int count; + + NamedThreadFactory(String namePrefix) { + this.namePrefix = namePrefix; + } + + public synchronized Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setName(namePrefix + " " + ++count); + t.setDaemon(true); + return t; + } + } +} diff --git a/test/javax/management/eventService/EventClientThreadTest.java b/test/javax/management/eventService/EventClientThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..910bc9cc2d2bc04a690fe71fa4e79f508b2440bc --- /dev/null +++ b/test/javax/management/eventService/EventClientThreadTest.java @@ -0,0 +1,176 @@ +/* + * 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 6747411 + * @summary Check that EventClient instances don't leak threads. + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Set; +import java.util.TreeSet; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +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; + +public class EventClientThreadTest { + private static final int MAX_TIME_SECONDS = 20; + + private static final BlockingQueue queue = + new ArrayBlockingQueue(100); + + private static final NotificationListener queueListener = + new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + }; + + private static final NotificationFilter dummyFilter = + new NotificationFilter() { + public boolean isNotificationEnabled(Notification notification) { + return true; + } + }; + + public static void main(String[] args) throws Exception { + long start = System.currentTimeMillis(); + long deadline = start + MAX_TIME_SECONDS * 1000; + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer( + url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + JMXConnector cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + + ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + + System.out.println("Opening and closing some EventClients..."); + // If we create a connection, then create and destroy EventClients + // over it, then close it, there should be no "JMX *" threads left. + for (int i = 0; i < 5; i++) + test(mbsc); + + cc.close(); + + showTime("opening and closing initial EventClients", start); + + Set jmxThreads = threadsMatching("JMX .*"); + while (!jmxThreads.isEmpty() && System.currentTimeMillis() < deadline) { + Set jmxThreadsNow = threadsMatching("JMX .*"); + Set gone = new TreeSet(jmxThreads); + gone.removeAll(jmxThreadsNow); + for (String s : gone) + showTime("expiry of \"" + s + "\"", start); + jmxThreads = jmxThreadsNow; + Thread.sleep(10); + } + if (System.currentTimeMillis() >= deadline) { + showThreads(threads); + throw new Exception("Timed out waiting for JMX threads to expire"); + } + + showTime("waiting for JMX threads to expire", start); + + System.out.println("TEST PASSED"); + } + + static void showThreads(ThreadMXBean threads) throws Exception { + long[] ids = threads.getAllThreadIds(); + for (long id : ids) { + ThreadInfo ti = threads.getThreadInfo(id); + String name = (ti == null) ? "(defunct)" : ti.getThreadName(); + System.out.printf("%4d %s\n", id, name); + } + } + + static void showTime(String what, long start) { + long elapsed = System.currentTimeMillis() - start; + System.out.printf("Time after %s: %.3f s\n", what, elapsed / 1000.0); + } + + static Set threadsMatching(String pattern) { + Set matching = new TreeSet(); + ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + long[] ids = threads.getAllThreadIds(); + for (long id : ids) { + ThreadInfo ti = threads.getThreadInfo(id); + String name = (ti == null) ? "(defunct)" : ti.getThreadName(); + if (name.matches(pattern)) + matching.add(name); + } + return matching; + } + + static void test(MBeanServerConnection mbsc) throws Exception { + final ObjectName delegateName = MBeanServerDelegate.DELEGATE_NAME; + final ObjectName testName = new ObjectName("test:type=Test"); + EventClient ec = new EventClient(mbsc); + ec.addNotificationListener(delegateName, queueListener, null, null); + mbsc.createMBean(MBeanServerDelegate.class.getName(), testName); + mbsc.unregisterMBean(testName); + final String[] expectedTypes = { + MBeanServerNotification.REGISTRATION_NOTIFICATION, + MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + }; + for (String s : expectedTypes) { + Notification n = queue.poll(3, TimeUnit.SECONDS); + if (n == null) + throw new Exception("Timed out waiting for notif: " + s); + if (!(n instanceof MBeanServerNotification)) + throw new Exception("Got notif of wrong class: " + n.getClass()); + if (!n.getType().equals(s)) { + throw new Exception("Got notif of wrong type: " + n.getType() + + " (expecting " + s + ")"); + } + } + ec.removeNotificationListener(delegateName, queueListener); + + ec.addNotificationListener(delegateName, queueListener, dummyFilter, "foo"); + ec.removeNotificationListener(delegateName, queueListener, dummyFilter, "foo"); + + ec.close(); + } +} \ No newline at end of file diff --git a/test/javax/management/eventService/EventDelegateSecurityTest.java b/test/javax/management/eventService/EventDelegateSecurityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a227e13f5d2e1643f5109942e8f6c09f5dc2ee24 --- /dev/null +++ b/test/javax/management/eventService/EventDelegateSecurityTest.java @@ -0,0 +1,289 @@ +/* + * 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 that the EventClientDelegate MBean does not require extra + * permissions compared with plain addNotificationListener. + * @author Eamonn McManus + * @run main/othervm -Dxjava.security.debug=policy,access,failure EventDelegateSecurityTest + */ + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +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.security.AccessControlContext; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; +import javax.management.MBeanPermission; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +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.JMXPrincipal; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.security.auth.Subject; + +public class EventDelegateSecurityTest { + private static final BlockingQueue notifQ = + new SynchronousQueue(); + + private static volatile long seqNo; + private static volatile long expectSeqNo; + + private static class QueueListener implements NotificationListener { + public void handleNotification(Notification notification, + Object handback) { + try { + notifQ.put(notification); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + } + private static final NotificationListener queueListener = new QueueListener(); + + public static interface SenderMBean { + public void send(); + } + + public static class Sender + extends NotificationBroadcasterSupport implements SenderMBean { + public void send() { + Notification n = new Notification("x", this, seqNo++); + sendNotification(n); + } + } + + private static class LimitInvocationHandler implements InvocationHandler { + private MBeanServer nextMBS; + private final Set allowedMethods = new HashSet(); + + void allow(String... names) { + synchronized (allowedMethods) { + allowedMethods.addAll(Arrays.asList(names)); + } + } + + public Object invoke(Object proxy, Method m, Object[] args) + throws Throwable { + System.out.println( + "filter: " + m.getName() + + ((args == null) ? "[]" : Arrays.deepToString(args))); + String name = m.getName(); + + if (name.equals("getMBeanServer")) + return nextMBS; + + if (name.equals("setMBeanServer")) { + nextMBS = (MBeanServer) args[0]; + return null; + } + + if (m.getDeclaringClass() == Object.class || + allowedMethods.contains(name)) { + try { + return m.invoke(nextMBS, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } else { + System.out.println("...refused"); + throw new SecurityException( + "Method refused: " + m.getDeclaringClass().getName() + + "." + m.getName() + + ((args == null) ? "[]" : Arrays.deepToString(args))); + } + } + + } + + private static interface MakeConnectorServer { + public JMXConnectorServer make(JMXServiceURL url) throws IOException; + } + + + public static void main(String[] args) throws Exception { + JMXPrincipal rootPrincipal = new JMXPrincipal("root"); + Subject rootSubject = new Subject(); + rootSubject.getPrincipals().add(rootPrincipal); + Subject.doAsPrivileged(rootSubject, new PrivilegedExceptionAction() { + public Void run() throws Exception { + mainAsRoot(); + return null; + } + }, null); + } + + private static void mainAsRoot() throws Exception { + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + System.out.println("Subject: " + subject); + final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName("a:b=c"); + mbs.registerMBean(new Sender(), name); + + System.out.println("Test with no installed security"); + test(mbs, name, new MakeConnectorServer() { + public JMXConnectorServer make(JMXServiceURL url) throws IOException { + return + JMXConnectorServerFactory.newJMXConnectorServer(url, null, null); + } + }); + + System.out.println("Test with filtering MBeanServerForwarder"); + LimitInvocationHandler limitIH = new LimitInvocationHandler(); + // We allow getClassLoaderRepository because the ConnectorServer + // calls it so any real checking MBeanServerForwarder must accept it. + limitIH.allow( + "addNotificationListener", "removeNotificationListener", + "getClassLoaderRepository" + ); + final MBeanServerForwarder limitMBSF = (MBeanServerForwarder) + Proxy.newProxyInstance( + MBeanServerForwarder.class.getClassLoader(), + new Class[] {MBeanServerForwarder.class}, + limitIH); + // We go to considerable lengths to ensure that the ConnectorServer has + // no MBeanServer when the EventClientDelegate forwarder is activated, + // so that the calls it makes when it is later linked to an MBeanServer + // go through the limitMBSF. + test(mbs, name, new MakeConnectorServer() { + public JMXConnectorServer make(JMXServiceURL url) throws IOException { + JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, null); + limitMBSF.setMBeanServer(mbs); + cs.setMBeanServerForwarder(limitMBSF); + return cs; + } + }); + + final File policyFile = + File.createTempFile("EventDelegateSecurityTest", ".policy"); + PrintWriter pw = new PrintWriter(policyFile); + String JMXPrincipal = JMXPrincipal.class.getName(); + String AllPermission = AllPermission.class.getName(); + String MBeanPermission = MBeanPermission.class.getName(); + pw.println("grant principal " + JMXPrincipal + " \"root\" {"); + pw.println(" permission " + AllPermission + ";"); + pw.println("};"); + pw.println("grant principal " + JMXPrincipal + " \"user\" {"); + pw.println(" permission " + MBeanPermission + " \"*\", " + + " \"addNotificationListener\";"); + pw.println(" permission " + MBeanPermission + " \"*\", " + + " \"removeNotificationListener\";"); + pw.println("};"); + pw.close(); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + policyFile.delete(); + } + }); + System.setProperty("java.security.policy", policyFile.getAbsolutePath()); + System.setSecurityManager(new SecurityManager()); + test(mbs, name, new MakeConnectorServer() { + public JMXConnectorServer make(JMXServiceURL url) throws IOException { + Map env = new HashMap(); + env.put(JMXConnectorServer.AUTHENTICATOR, new JMXAuthenticator() { + public Subject authenticate(Object credentials) { + Subject s = new Subject(); + s.getPrincipals().add(new JMXPrincipal("user")); + return s; + } + }); + return + JMXConnectorServerFactory.newJMXConnectorServer(url, env, null); + } + }); + } + + private static void test(MBeanServer mbs, ObjectName name) throws Exception { + test(mbs, name, null); + } + + private static void test( + MBeanServer mbs, ObjectName name, MakeConnectorServer make) + throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///"); + JMXConnectorServer cs = make.make(url); + ObjectName csName = new ObjectName("a:type=ConnectorServer"); + mbs.registerMBean(cs, csName); + cs.start(); + try { + JMXServiceURL addr = cs.getAddress(); + JMXConnector cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + test(mbs, mbsc, name); + cc.close(); + mbs.unregisterMBean(csName); + } finally { + cs.stop(); + } + } + + private static void test( + MBeanServer mbs, MBeanServerConnection mbsc, ObjectName name) + throws Exception { + EventClient ec = new EventClient(mbsc); + ec.addNotificationListener(name, queueListener, null, null); + mbs.invoke(name, "send", null, null); + + Notification n = notifQ.poll(5, TimeUnit.SECONDS); + if (n == null) + throw new Exception("FAILED: notif not delivered"); + if (n.getSequenceNumber() != expectSeqNo) { + throw new Exception( + "FAILED: notif seqno " + n.getSequenceNumber() + + " should be " + expectSeqNo); + } + expectSeqNo++; + + ec.removeNotificationListener(name, queueListener); + ec.close(); + } +} diff --git a/test/javax/management/eventService/EventManagerTest.java b/test/javax/management/eventService/EventManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2717c0e51035f8de4140278e4d45935665a531cf --- /dev/null +++ b/test/javax/management/eventService/EventManagerTest.java @@ -0,0 +1,221 @@ +/* + * 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 EventManagerTest.java 1.8 08/01/22 + * @bug 5108776 + * @summary Basic test for EventManager. + * @author Shanliang JIANG + * @run clean EventManagerTest + * @run build EventManagerTest + * @run main EventManagerTest + */ + +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.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.*; +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; + +/** + * + */ +public class EventManagerTest { + private static MBeanServer mbeanServer; + private static ObjectName emitter; + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static MBeanServerConnection client; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + System.out.println(">>> EventManagerTest-main basic tests ..."); + mbeanServer = MBeanServerFactory.createMBeanServer(); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + emitter = new ObjectName("Default:name=NotificationEmitter"); + + url = new JMXServiceURL("rmi", null, 0) ; + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer); + server.start(); + + url = server.getAddress(); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + mbeanServer.registerMBean(new NotificationEmitter(), emitter); + + boolean succeed; + + System.out.println(">>> EventManagerTest-main: using the fetching EventRelay..."); + succeed = test(new EventClient(client)); + + System.out.println(">>> EventManagerTest-main: using the pushing EventRelay..."); + EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client); + succeed &= test(new EventClient(ecd, + new RMIPushEventRelay(ecd), + null, null, + EventClient.DEFAULT_LEASE_TIMEOUT)); + + conn.close(); + server.stop(); + + if (succeed) { + System.out.println(">>> EventManagerTest-main: PASSE!"); + } else { + System.out.println("\n>>> EventManagerTest-main: FAILED!"); + System.exit(1); + } + } + + public static boolean test(EventClient efClient) throws Exception { + // add listener from the client side + Listener listener = new Listener(); + efClient.subscribe(emitter, listener, null, null); + + // ask to send notifs + Object[] params = new Object[] {new Integer(sendNB)}; + String[] signatures = new String[] {"java.lang.Integer"}; + client.invoke(emitter, "sendNotifications", params, signatures); + + // waiting + long toWait = 6000; + long stopTime = System.currentTimeMillis() + toWait; + + synchronized(listener) { + while(listener.received < sendNB && toWait > 0) { + listener.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + // clean + System.out.println(">>> EventManagerTest-test: cleaning..."); + efClient.unsubscribe(emitter, listener); + efClient.close(); + + if (listener.received != sendNB) { + System.out.println(">>> EventManagerTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received); + + return false; + } else if (listener.seqErr > 0) { + System.out.println(">>> EventManagerTest-test: FAILED! The receiving sequence is not correct."); + + return false; + } else { + System.out.println(">>> EventManagerTest-test: got all expected "+listener.received); + return true; + } + } + + private static class Listener implements NotificationListener { + public int received = 0; + public int seqErr = 0; + + private long lastSeq = -1; + + public void handleNotification(Notification notif, Object handback) { + if (!myType.equals(notif.getType())) { + System.out.println(">>> EventManagerTest-Listener: got unexpected notif: "+notif); + System.exit(1); + } + + if (lastSeq == -1) { + lastSeq = notif.getSequenceNumber(); + } else if (notif.getSequenceNumber() - lastSeq++ != 1) { + seqErr++; + } + + //System.out.println(">>> EventManagerTest-Listener: got notif "+notif.getSequenceNumber()); + + synchronized(this) { + if (++received >= sendNB) { + this.notify(); + } + } + } + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + public MBeanNotificationInfo[] getNotificationInfo() { + final String[] ntfTypes = {myType}; + + final MBeanNotificationInfo[] ntfInfoArray = { + new MBeanNotificationInfo(ntfTypes, + "javax.management.Notification", + "Notifications sent by the NotificationEmitter")}; + + return ntfInfoArray; + } + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotifications(Integer nb) { + Notification notif; + for (int i=1; i<=nb.intValue(); i++) { + notif = new Notification(myType, this, count++); + notif.setUserData("jsl"); + //System.out.println(">>> EventManagerService-NotificationEmitter-sendNotifications: "+i); + + sendNotification(notif); + } + } + } + + public interface NotificationEmitterMBean { + public void sendNotifications(Integer nb); + } + + private static int sendNB = 120; + private static long count = 0; + + private static final String myType = "notification.my_notification"; +} diff --git a/test/javax/management/eventService/FetchingTest.java b/test/javax/management/eventService/FetchingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f6fc91691ca3046f7d6722028eee336ab250b8f2 --- /dev/null +++ b/test/javax/management/eventService/FetchingTest.java @@ -0,0 +1,276 @@ +/* + * 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 5108776 + * @summary Basic test for EventClient. + * @author Shanliang JIANG + * @run clean FetchingTest MyFetchingEventForwarder + * @run build FetchingTest MyFetchingEventForwarder + * @run main FetchingTest MyFetchingEventForwarder + */ + +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.FetchingEventRelay; +import javax.management.event.RMIPushEventForwarder; +import javax.management.event.RMIPushServer; +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; + +public class FetchingTest { + private static MBeanServer mbeanServer; + private static ObjectName emitter; + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static MBeanServerConnection client; + private static long WAITING_TIME = 6000; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + + System.out.println(">>> FetchingTest-main basic tests ..."); + mbeanServer = MBeanServerFactory.createMBeanServer(); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + emitter = new ObjectName("Default:name=NotificationEmitter"); + mbeanServer.registerMBean(new NotificationEmitter(), emitter); + boolean succeed = true; + + final String[] protos = new String[] {"rmi", "iiop", "jmxmp"}; + for (String proto : protos) { + System.out.println(">>> FetchingTest-main: testing on "+proto); + + try { + url = new JMXServiceURL(proto, null, 0) ; + server = JMXConnectorServerFactory. + newJMXConnectorServer(url, null, mbeanServer); + server.start(); + } catch (Exception e) { + // OK + System.out.println(">>> FetchingTest-main: skip the proto "+proto); + continue; + } + + url = server.getAddress(); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + succeed &= test(); + + conn.close(); + server.stop(); + + System.out.println( + ">>> FetchingTest-main: testing on "+proto+" done."); + } + + if (succeed) { + System.out.println(">>> FetchingTest-main: PASSED!"); + } else { + System.out.println("\n>>> FetchingTest-main: FAILED!"); + System.exit(1); + } + } + + public static boolean test() throws Exception { + System.out.println(">>> FetchingTest-test: " + + "using the default fetching forwarder ..."); + EventClient eventClient = + new EventClient(client); + + Listener listener = new Listener(); + eventClient.addNotificationListener(emitter, listener, null, null); + + // ask to send notifs + Object[] params = new Object[] {new Integer(sendNB)}; + String[] signatures = new String[] {"java.lang.Integer"}; + conn.getMBeanServerConnection().invoke(emitter, + "sendNotifications", params, signatures); + + if (listener.waitNotif(WAITING_TIME) != sendNB) { + System.out.println( + ">>> FetchingTest-test: FAILED! Expected to receive "+ + sendNB+", but got "+listener.received); + + return false; + } + + System.out.println( + ">>> ListenerTest-test: got all expected "+listener.received); + //eventClient.removeNotificationListener(emitter, listener); + eventClient.close(); + + System.out.println(">>> FetchingTest-test: " + + "using a user specific List ..."); + + FetchingEventRelay fer = new FetchingEventRelay( + EventClientDelegate.getProxy(client), + 1000, 1000L, 1000, null, + MyFetchingEventForwarder.class.getName(), + null, null); + + eventClient = new EventClient( + EventClientDelegate.getProxy(client), fer, null, null, 10000); + + eventClient.addNotificationListener(emitter, listener, null, null); + listener.received = 0; + + conn.getMBeanServerConnection().invoke(emitter, + "sendNotifications", params, signatures); + + if (listener.waitNotif(WAITING_TIME) != sendNB) { + System.out.println( + ">>> FetchingTest-test: FAILED! Expected to receive "+ + sendNB+", but got "+listener.received); + + return false; + } + + System.out.println( + ">>> FetchingTest-test: got all expected "+listener.received); + + if (!MyFetchingEventForwarder.shared.isUsed()) { + System.out.println( + ">>> FetchingTest-test: FAILED! The user specific list" + + "is not used!"); + + return false; + } + + System.out.println(">>> Negative test to add an EventClient" + + " with a non EventForwarder object."); + try { + MyFetchingEventForwarder.shared.setAgain(); + + System.out.println( + ">>> FetchingTest-test: FAILED! No expected exception" + + "when setting the list after the forwarder started."); + + return false; + } catch (IllegalStateException ise) { + // OK + System.out.println( + ">>> FetchingTest-test: Got expected exception: " + ise); + } + + eventClient.close(); + + try { + fer = new FetchingEventRelay( + EventClientDelegate.getProxy(client), + 1000, 1000L, 1000, null, + Object.class.getName(), + null, null); + + eventClient = new EventClient( + EventClientDelegate.getProxy(client), fer, null, null, 10000); + + System.out.println( + ">>> FetchingTest-test: FAILED! No expected exception" + + "when creating an illegal EventForwarder"); + } catch (IllegalArgumentException iae) { + // OK + // iae.printStackTrace(); + } + + return true; + } + + private static class Listener implements NotificationListener { + public void handleNotification(Notification notif, Object handback) { + synchronized(this) { + if (++received >= sendNB) { + this.notify(); + } + } + + //System.out.println(">>> FetchingTest-Listener: received = "+received); + } + + public int waitNotif(long timeout) throws Exception { + synchronized(this) { + long stopTime = System.currentTimeMillis() + timeout; + long toWait = timeout; + while (toWait > 0 && received < sendNB) { + this.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + return received; + } + + public static int received = 0; + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + public void sendNotifications(Integer nb) { + System.out.println( + ">>> FetchingTest-NotificationEmitter-sendNotifications: "+nb); + Notification notif; + for (int i=1; i<=nb.intValue(); i++) { + notif = new Notification(myType, this, count++); + sendNotification(notif); + } + } + } + + public interface NotificationEmitterMBean { + public void sendNotifications(Integer nb); + } + + + + private static int sendNB = 20; + private static int count = 0; + + private static final String myType = "notification.my_notification"; +} diff --git a/test/javax/management/eventService/LeaseManagerDeadlockTest.java b/test/javax/management/eventService/LeaseManagerDeadlockTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ab7d14d54f2e663d544718ae4ec8151a1c238e7b --- /dev/null +++ b/test/javax/management/eventService/LeaseManagerDeadlockTest.java @@ -0,0 +1,98 @@ +/* + * 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 6717789 + * @summary Check that a lock is not held when a LeaseManager expires. + * @author Eamonn McManus + * @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java + * @run main LeaseManagerDeadlockTest + */ + +import com.sun.jmx.event.LeaseManager; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.Arrays; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class LeaseManagerDeadlockTest { + public static String failure; + public static LeaseManager leaseManager; + public static Semaphore callbackThreadCompleted = new Semaphore(0); + public static Object lock = new Object(); + + public static Runnable triggerDeadlock = new Runnable() { + public void run() { + Runnable pingLeaseManager = new Runnable() { + public void run() { + System.out.println("Ping thread starts"); + synchronized (lock) { + leaseManager.lease(1); + } + System.out.println("Ping thread completes"); + } + }; + Thread t = new Thread(pingLeaseManager); + t.start(); + try { + Thread.sleep(10); // enough time for ping thread to grab lock + synchronized (lock) { + t.join(); + } + } catch (InterruptedException e) { + fail(e.toString()); + } + System.out.println("Callback thread completes"); + callbackThreadCompleted.release(); + } + }; + + public static void main(String[] args) throws Exception { + // Also test that we can shorten the lease from its initial value. + leaseManager = new LeaseManager(triggerDeadlock, 1000000); + leaseManager.lease(1L); + + boolean callbackRan = + callbackThreadCompleted.tryAcquire(3, TimeUnit.SECONDS); + + if (!callbackRan) { + fail("Callback did not complete - probable deadlock"); + ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + System.out.println(Arrays.toString(threads.findDeadlockedThreads())); + System.out.println("PRESS RETURN"); + System.in.read(); + } + + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + public static void fail(String why) { + System.out.println("TEST FAILS: " + why); + failure = why; + } +} diff --git a/test/javax/management/eventService/LeaseTest.java b/test/javax/management/eventService/LeaseTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fb056ad638d72fc845a58ca96567e386089f1e50 --- /dev/null +++ b/test/javax/management/eventService/LeaseTest.java @@ -0,0 +1,361 @@ +/* + * 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 LeaseTest.java 1.6 08/01/22 + * @bug 5108776 + * @summary Basic test for Event service leasing. + * @author Shanliang JIANG + * @run clean LeaseTest + * @run build LeaseTest + * @run main LeaseTest + */ + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.EventClientNotFoundException; +import javax.management.event.FetchingEventRelay; +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; + +public class LeaseTest { + + private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(); + private static List notifList = new ArrayList(); + private static ObjectName emitter; + private static NotificationEmitter emitterImpl; + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static Listener listener = new Listener(); + + private static long leaseTime = 100; + private static final int multiple = 5; + private static final long bigWaiting = 6000; + + public static void main(String[] args) throws Exception { + System.out.println(">>> Test the event service lease"); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + System.setProperty("com.sun.event.lease.time", + String.valueOf(leaseTime)); + emitter = new ObjectName("Default:name=NotificationEmitter"); + emitterImpl = new NotificationEmitter(); + mbeanServer.registerMBean(emitterImpl, emitter); + + String[] types = new String[]{"PushingEventRelay", "FetchingEventRelay"}; + String[] protos = new String[]{"rmi", "iiop", "jmxmp"}; + for (String prot : protos) { + url = new JMXServiceURL(prot, null, 0); + + try { + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + null, mbeanServer); + server.start(); + } catch (Exception e) { + System.out.println(">>> Skip "+prot+", not support."); + continue; + } + + url = server.getAddress(); + + try { + for (String type: types) { + test(type); + } + } finally { + server.stop(); + } + } + } + + private static void test(String type) throws Exception { + System.out.println("\n\n>>> Testing "+type+" on "+url+" ..."); + newConn(); + EventClient ec = newEventClient(type); + + ec.addNotificationListener(emitter, + listener, null, null); + + System.out.println(">>> Send a notification and should receive it."); + emitterImpl.sendNotif(++counter); + + if (!waitNotif(bigWaiting, counter)) { + throw new RuntimeException(">>> Failed to receive notif."); + } + + System.out.println(">>> Sleep 3 times of requested lease time."); + Thread.sleep(leaseTime*3); + System.out.println(">>> Send again a notification and should receive it."); + emitterImpl.sendNotif(++counter); + + if (!waitNotif(bigWaiting, counter)) { + throw new RuntimeException(">>> Failed to receive notif."); + } + + System.out.println(">>> Close the client connection: "+ + conn.getConnectionId()); + conn.close(); + + System.out.println(">>> Waiting lease timeout to do clean."); + + if (!emitterImpl.waitingClean(leaseTime*multiple)) { + throw new RuntimeException( + ">>> The event lease failed to do clean: "+ + emitterImpl.listenerSize); + } else { + System.out.println(">>> The listener has been removed."); + } + + // Check that the client id has indeed been removed, by trying to + // remove it again, which should fail. + newConn(); + try { + EventClientDelegateMBean proxy = + EventClientDelegate.getProxy(conn.getMBeanServerConnection()); + proxy.removeClient(ec.getEventRelay().getClientId()); + + throw new RuntimeException( + ">>> The client id is not removed."); + } catch (EventClientNotFoundException ecnfe) { + // OK + System.out.println(">>> The client id has been removed."); + } + conn.close(); + + System.out.println(">>> Reconnect to the server."); + newConn(); + + System.out.println(">>> Create a new EventClient and add the listeners" + + " in the failed EventClient into new EventClient"); + EventClient newEC = newEventClient(type); + newEC.addListeners(ec.getListeners()); + // We expect ec.close() to get IOException because we closed the + // underlying connection. + try { + ec.close(); + throw new RuntimeException(">>> EventClient.close did not throw " + + "expected IOException"); + } catch (IOException e) { + System.out.println(">>> EventClient.close threw expected exception: " + e); + } + + emitterImpl.sendNotif(++counter); + + if (!waitNotif(bigWaiting, counter)) { + throw new RuntimeException(">>> The event client failed to add " + + "all old registered listeners after re-connection."); + } else { + System.out.println(">>> Successfully received notification from" + + " new EventClient."); + } + + System.out.println(">>> Clean the failed EventClient."); + ec.close(); + if (ec.getListeners().size() != 0) { + throw new RuntimeException(">>> The event client fails to do clean."); + } + + System.out.println(">>> Clean the new EventClient."); + newEC.close(); + if (newEC.getListeners().size() != 0) { + throw new RuntimeException(">>> The event client fails to do clean."); + } + + conn.close(); + System.out.println(">>> Testing "+type+" on "+url+" ... done"); + } + + private static boolean waitNotif(long time, int sequenceNumber) + throws Exception { + synchronized(notifList) { + if (search(sequenceNumber)) { + return true; + } + + long stopTime = System.currentTimeMillis() + time; + long toWait = time; + while (toWait > 0) { + notifList.wait(toWait); + + if (search(sequenceNumber)) { + return true; + } + + toWait = stopTime - System.currentTimeMillis(); + } + + return false; + } + } + + private static boolean search(int sequenceNumber) { + while(notifList.size() > 0) { + Notification n = notifList.remove(0); + if (n.getSequenceNumber() == sequenceNumber) { + return true; + } + } + + return false; + } + +//-------------------------- +// private classes +//-------------------------- + + private static class Listener implements NotificationListener { + public void handleNotification(Notification notif, Object handback) { + synchronized (notifList) { + notifList.add(notif); + notifList.notify(); + } + } + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + public MBeanNotificationInfo[] getNotificationInfo() { + final String[] ntfTypes = {myType}; + + final MBeanNotificationInfo[] ntfInfoArray = { + new MBeanNotificationInfo(ntfTypes, + "javax.management.Notification", + "Notifications sent by the NotificationEmitter")}; + + return ntfInfoArray; + } + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotif(int sequenceNumber) { + Notification notif = new Notification(myType, this, sequenceNumber); + sendNotification(notif); + } + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) { + super.addNotificationListener(listener, filter, handback); + + listenerSize++; + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + super.removeNotificationListener(listener); + listenerSize--; + + synchronized(this) { + if (listenerSize == 0) { + this.notifyAll(); + } + } + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + super.removeNotificationListener(listener, filter, handback); + listenerSize--; + + synchronized(this) { + if (listenerSize == 0) { + this.notifyAll(); + } + } + } + + public boolean waitingClean(long timeout) throws Exception { + synchronized(this) { + long stopTime = System.currentTimeMillis() + timeout; + long toWait = timeout; + while (listenerSize != 0 && toWait > 0) { + this.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + return listenerSize == 0; + } + + public int listenerSize = 0; + + private final String myType = "notification.my_notification"; + } + + public interface NotificationEmitterMBean { + public void sendNotif(int sequenceNumber); + } + + private static void newConn() throws IOException { + conn = JMXConnectorFactory.connect(url); + } + + private static EventClient newEventClient(String type) throws Exception { + EventClientDelegateMBean proxy = + EventClientDelegate.getProxy(conn.getMBeanServerConnection()); + if (type.equals("PushingEventRelay")) { + return new EventClient(proxy, + new FetchingEventRelay(proxy), null, null, leaseTime); + } else if (type.equals("FetchingEventRelay")) { + return new EventClient(proxy, + new FetchingEventRelay(proxy), null, null, leaseTime); + } else { + throw new RuntimeException("Wrong event client type: "+type); + } + } + + private static int counter = 0; +} diff --git a/test/javax/management/eventService/ListenerTest.java b/test/javax/management/eventService/ListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7195736b66264abd53e4303de2eee6ebe947cd8d --- /dev/null +++ b/test/javax/management/eventService/ListenerTest.java @@ -0,0 +1,224 @@ +/* + * 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 ListenerTest.java 1.7 08/01/22 + * @bug 5108776 + * @summary Basic test for EventClient. + * @author Shanliang JIANG + * @run clean ListenerTest + * @run build ListenerTest + * @run main ListenerTest + */ + +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.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.*; +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; + +/** + * + */ +public class ListenerTest { + private static MBeanServer mbeanServer; + private static ObjectName emitter; + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static MBeanServerConnection client; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + + System.out.println(">>> ListenerTest-main basic tests ..."); + mbeanServer = MBeanServerFactory.createMBeanServer(); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + emitter = new ObjectName("Default:name=NotificationEmitter"); + + url = new JMXServiceURL("rmi", null, 0) ; + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer); + server.start(); + + url = server.getAddress(); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + mbeanServer.registerMBean(new NotificationEmitter(), emitter); + + boolean succeed; + + System.out.println(">>> ListenerTest-main: using the fetching EventRelay..."); + succeed = test(new EventClient(client)); + + System.out.println(">>> ListenerTest-main: using the pushing EventRelay..."); + EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client); + succeed &= test(new EventClient(ecd, + new RMIPushEventRelay(ecd), + null, null, + EventClient.DEFAULT_LEASE_TIMEOUT)); + + conn.close(); + server.stop(); + + if (succeed) { + System.out.println(">>> ListenerTest-main: PASSED!"); + } else { + System.out.println("\n>>> ListenerTest-main: FAILED!"); + System.exit(1); + } + } + + public static boolean test(EventClient efClient) throws Exception { + // add listener from the client side + Listener listener = new Listener(); + efClient.addNotificationListener(emitter, listener, null, null); + + // ask to send notifs + Object[] params = new Object[] {new Integer(sendNB)}; + String[] signatures = new String[] {"java.lang.Integer"}; + client.invoke(emitter, "sendNotifications", params, signatures); + + // waiting + long toWait = 6000; + long stopTime = System.currentTimeMillis() + toWait; + + synchronized(listener) { + while(listener.received < sendNB && toWait > 0) { + listener.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + // clean + efClient.removeNotificationListener(emitter, listener, null, null); + efClient.close(); + + if (listener.received != sendNB) { + System.out.println(">>> ListenerTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received); + + return false; + } else if (listener.seqErr > 0) { + System.out.println(">>> ListenerTest-test: FAILED! The receiving sequence is not correct."); + + return false; + } else { + System.out.println(">>> ListenerTest-test: got all expected "+listener.received); + return true; + } + } + + private static class Listener implements NotificationListener { + public int received = 0; + public int seqErr = 0; + + private long lastSeq = -1; + + public void handleNotification(Notification notif, Object handback) { + if (!myType.equals(notif.getType())) { + System.out.println(">>> EventManagerTest-Listener: got unexpected notif: "+notif); + System.exit(1); + } + + if (lastSeq == -1) { + lastSeq = notif.getSequenceNumber(); + } else if (notif.getSequenceNumber() - lastSeq++ != 1) { + seqErr++; + } + + System.out.println(">>> ListenerTest-Listener: got notif "+notif.getSequenceNumber()); + + synchronized(this) { + if (++received >= sendNB) { + this.notify(); + } + } + + System.out.println(">>> ListenerTest-Listener: received = "+received); + } + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + public MBeanNotificationInfo[] getNotificationInfo() { + final String[] ntfTypes = {myType}; + + final MBeanNotificationInfo[] ntfInfoArray = { + new MBeanNotificationInfo(ntfTypes, + "javax.management.Notification", + "Notifications sent by the NotificationEmitter")}; + + return ntfInfoArray; + } + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotifications(Integer nb) { + Notification notif; + for (int i=1; i<=nb.intValue(); i++) { + notif = new Notification(myType, this, count++); + //System.out.println(">>> ListenerTest-NotificationEmitter-sendNotifications: "+i); + + sendNotification(notif); + } + } + + + } + + public interface NotificationEmitterMBean { + public void sendNotifications(Integer nb); + } + + private static int sendNB = 20; + private static int count = 0; + + private static final String myType = "notification.my_notification"; +} diff --git a/test/javax/management/eventService/MyFetchingEventForwarder.java b/test/javax/management/eventService/MyFetchingEventForwarder.java new file mode 100644 index 0000000000000000000000000000000000000000..25d308af66c9729431d8b289f70416ee1c5dee0e --- /dev/null +++ b/test/javax/management/eventService/MyFetchingEventForwarder.java @@ -0,0 +1,53 @@ +/* + * MyList.java + * + * Created on Oct 23, 2007, 2:45:57 PM + * + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +/** + * + * @author sjiang + */ + +import java.io.IOException; +import java.util.ArrayList; +import javax.management.event.FetchingEventForwarder; + +public class MyFetchingEventForwarder extends FetchingEventForwarder { + + public MyFetchingEventForwarder() { + super(1000); + shared = this; + setList(myList); + } + + public void setAgain() { + setList(myList); + } + + public void setClientId(String clientId) throws IOException { + used = true; + super.setClientId(clientId); + } + + public boolean isUsed() { + return used; + } + + private class MyList + extends ArrayList { + + public boolean add(TargetedNotification e) { + used = true; + + return super.add(e); + } + } + + public MyList myList = new MyList(); + public static MyFetchingEventForwarder shared; + private boolean used = false; +} diff --git a/test/javax/management/eventService/NotSerializableNotifTest.java b/test/javax/management/eventService/NotSerializableNotifTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0bf0bc5faae6c6e545d998d9d510def15a292bb0 --- /dev/null +++ b/test/javax/management/eventService/NotSerializableNotifTest.java @@ -0,0 +1,227 @@ +/* + * 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 NotSerializableNotifTest.java 1.5 08/01/22 + * @bug 5108776 + * @summary Basic test for EventClient. + * @author Shanliang JIANG + * @run clean NotSerializableNotifTest + * @run build NotSerializableNotifTest + * @run main NotSerializableNotifTest + */ + + +// JMX imports +// +import javax.management.* ; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.EventRelay; +import javax.management.event.FetchingEventRelay; + +import javax.management.remote.*; +import javax.management.remote.JMXServiceURL; + +public class NotSerializableNotifTest { + private static MBeanServer mbeanServer = + MBeanServerFactory.createMBeanServer(); + private static ObjectName emitter; + private static int port = 2468; + + private static String[] protocols; + + private static final int sentNotifs = 50; + + public static void main(String[] args) throws Exception { + System.out.println(">>> Test to send a not serializable notification"); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + NotificationEmitter nm = new NotificationEmitter(); + emitter = new ObjectName("Default:name=NotificationEmitter"); + mbeanServer.registerMBean(nm, emitter); + String proto = "rmi"; + + System.out.println(">>> Test for protocol " + proto); + + JMXServiceURL url = new JMXServiceURL(proto, null, 0); + + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer); + + server.start(); + + url = server.getAddress(); + JMXConnector conn = JMXConnectorFactory.connect(url, null); + MBeanServerConnection client = conn.getMBeanServerConnection(); + + EventClientDelegateMBean ecd = EventClientDelegate.getProxy(client); + EventRelay eventRelay = new FetchingEventRelay( + ecd, + FetchingEventRelay.DEFAULT_BUFFER_SIZE, + 10, + FetchingEventRelay.DEFAULT_MAX_NOTIFICATIONS, + null); + EventClient ec = new EventClient(ecd, eventRelay, null, null, + EventClient.DEFAULT_LEASE_TIMEOUT); + + // add listener from the client side + Listener listener = new Listener(); + ec.addNotificationListener(emitter, listener, null, null); + + LostListener lostListener = new LostListener(); + ec.addEventClientListener(lostListener, null, null); + + // ask to send one not serializable notif + System.out.println(">>> sending not serializable notifs ..."); + + Object[] params = new Object[] {new Integer(sentNotifs)}; + String[] signatures = new String[] {"java.lang.Integer"}; + client.invoke(emitter, "sendNotserializableNotifs", params, signatures); + +// nm.sendNotserializableNotifs(sentNotifs); +// nm.sendNotifications(1); + + // waiting + synchronized(lostListener) { + if (lostListener.lostCount != sentNotifs) { + lostListener.wait(6000); + } + } + + Thread.sleep(100); + + if (lostListener.lostCount != sentNotifs) { + System.out.println(">>> FAILED. Expected "+sentNotifs+", but got "+lostListener.lostCount); + System.exit(1); + } + + System.out.println(">>> Passed."); + + ec.close(); + conn.close(); + server.stop(); + } + + +//-------------------------- +// private classes +//-------------------------- + private static class Listener implements NotificationListener { + public void handleNotification(Notification n, Object handback) { + System.out.println(">>> Listener: receive: "+n); + } + } + + + private static class LostListener implements NotificationListener { + public void handleNotification(Notification n, Object handback) { + if (!EventClient.NOTIFS_LOST.equals(n.getType())) { + return; + } + + if (!(n.getUserData() instanceof Long)) { + System.out.println(">>> Listener: JMXConnectionNotification userData " + + "not a Long: " + n.getUserData()); + System.exit(1); + } else { + int lost = ((Long) n.getUserData()).intValue(); + lostCount += lost; + if (lostCount >= sentNotifs) { + synchronized(this) { + this.notifyAll(); + } + } + } + + } + + + private int lostCount = 0; + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + public MBeanNotificationInfo[] getNotificationInfo() { + final String[] ntfTypes = {myType}; + + final MBeanNotificationInfo[] ntfInfoArray = { + new MBeanNotificationInfo(ntfTypes, + "javax.management.Notification", + "Notifications sent by the NotificationEmitter")}; + + return ntfInfoArray; + } + + /** + * Send not serializable Notifications. + * + * @param nb The number of notifications to send + */ + public void sendNotserializableNotifs(Integer nb) { + + Notification notif; + for (int i=1; i<=nb.intValue(); i++) { + notif = new Notification(myType, this, i); + + notif.setUserData(new Object()); + sendNotification(notif); + } + } + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotifications(Integer nb) { + Notification notif; + for (int i=1; i<=nb.intValue(); i++) { + notif = new Notification(myType, this, i); + + sendNotification(notif); + } + } + + private final String myType = "notification.my_notification"; + } + + public interface NotificationEmitterMBean { + public void sendNotifications(Integer nb); + + public void sendNotserializableNotifs(Integer nb); + } +} diff --git a/test/javax/management/eventService/PublishTest.java b/test/javax/management/eventService/PublishTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c1e27b2d2798eebb171c1def2e177950b961760d --- /dev/null +++ b/test/javax/management/eventService/PublishTest.java @@ -0,0 +1,184 @@ +/* + * 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 javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.*; +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; + +/** + * + */ +public class PublishTest { + private static MBeanServer mbeanServer; + private static EventManager eventManager; + private static ObjectName emitter; + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static MBeanServerConnection client; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + System.out.println(">>> PublishTest-main basic tests ..."); + mbeanServer = MBeanServerFactory.createMBeanServer(); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + } + + eventManager = EventManager.getEventManager(mbeanServer); + + emitter = new ObjectName("Default:name=NotificationEmitter"); + + url = new JMXServiceURL("rmi", null, 0) ; + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer); + server.start(); + + url = server.getAddress(); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + boolean succeed; + + System.out.println(">>> PublishTest-main: using the fetching EventRelay..."); + succeed = test(new EventClient(client)); + + System.out.println(">>> PublishTest-main: using the pushing EventRelay..."); + succeed &= test(new EventClient(client, + new RMIPushEventRelay(EventClientDelegate.getProxy(client)), + null, + EventClient.DEFAULT_LEASE_TIMEOUT)); + + conn.close(); + server.stop(); + + if (succeed) { + System.out.println(">>> PublishTest-main: PASSE!"); + } else { + System.out.println("\n>>> PublishTest-main: FAILED!"); + System.exit(1); + } + } + + public static boolean test(EventClient efClient) throws Exception { + // add listener from the client side + Listener listener = new Listener(); + efClient.subscribe(emitter, listener, null, null); + + ObjectName other = new ObjectName("Default:name=other"); + // publish notifs + for (int i=0; i>> EventManagerService-NotificationEmitter-sendNotifications: "+i); + + eventManager.publish(emitter, notif); + eventManager.publish(other, notif2); // should not received + } + + // waiting + long toWait = 6000; + long stopTime = System.currentTimeMillis() + toWait; + + synchronized(listener) { + while(listener.received < sendNB && toWait > 0) { + listener.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + // clean + efClient.unsubscribe(emitter, listener); + efClient.close(); + + if (listener.received != sendNB) { + System.out.println(">>> PublishTest-test: FAILED! Expected to receive "+sendNB+", but got "+listener.received); + + return false; + } else if (listener.seqErr > 0) { + System.out.println(">>> PublishTest-test: FAILED! The receiving sequence is not correct."); + + return false; + } else { + System.out.println(">>> PublishTest-test: got all expected "+listener.received); + return true; + } + } + + private static class Listener implements NotificationListener { + public int received = 0; + public int seqErr = 0; + + private long lastSeq = -1; + + public void handleNotification(Notification notif, Object handback) { + if (!myType.equals(notif.getType())) { + System.out.println(">>> PublishTest-Listener: got unexpected notif: "+notif); + System.exit(1); + } else if (!emitter.equals(notif.getSource())) { + System.out.println(">>> PublishTest-Listener: unknown ObjectName: "+notif.getSource()); + System.exit(1); + } + + if (lastSeq == -1) { + lastSeq = notif.getSequenceNumber(); + } else if (notif.getSequenceNumber() - lastSeq++ != 1) { + seqErr++; + } + + System.out.println(">>> PublishTest-Listener: got notif "+notif.getSequenceNumber()); + + synchronized(this) { + if (++received >= sendNB) { + this.notify(); + } + } + + System.out.println(">>> PublishTest-Listener: received = "+received); + } + } + + private static int sendNB = 20; + private static long count = 0; + + private static final String myType = "notification.my_notification"; +} diff --git a/test/javax/management/eventService/ReconnectableConnectorTest.java b/test/javax/management/eventService/ReconnectableConnectorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d4b1564397aff11332de0085d30c6ed736382dce --- /dev/null +++ b/test/javax/management/eventService/ReconnectableConnectorTest.java @@ -0,0 +1,488 @@ +/* + * 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 ReconnectableJMXConnector + * @bug 5108776 + * @summary Check that the Event Service can be used to build a + * ReconnectableJMXConnector. + * @author Eamonn McManus + */ + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Date; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +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.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +/* + * This test checks that it is possible to use the Event Service to create + * a "reconnectable connector". + * + * In the JMX Remote API, we deliberately specified that a connector client + * (JMXConnector) that encounters a network failure is then permanently broken. + * The idea being that adding recovery logic to the basic connector client + * would make it much more complicated and less reliable, and the logic would + * in any case never correspond to what a given situation needs. Some of + * the tough questions are: Should the connector try to mask the failure by + * blocking operations until the failure is resolved? How long should the + * connector try to reestablish the connection before giving up? Rather than + * try to solve this problem in the connector, we suggested that people who + * wanted to recover from network failures could implement the JMXConnector + * interface themselves so that it forwards to a wrapped JMXConnector that can + * be replaced in case of network failure. + * + * This works fine except that the connector client has state, + * in the form of listeners added by the user through the + * MBeanServerConnection.addNotificationListener method. It's possible + * for the wrapper to keep track of these listeners as well as forwarding + * them to the wrapped JMXConnector, so that it can reapply them to + * a replacement JMXConnector after failure recover. But it's quite + * tricky, particularly because of the two- and four-argument versions of + * removeNotificationListener. + * + * The Event Service can take care of this for you through the EventClient + * class. Listeners added through that class are implemented in a way that + * doesn't require the connector client to maintain any state, so they should + * continue to work transparently after replacing the wrapped JMXConnector. + * This test is a proof of concept that shows it works. Quite a number of + * details would need to be changed to build a reliable reconnectable + * connector. + * + * The test simulates network failure by rewrapping the wrapped JMXConnector's + * MBeanServerConnection (MBSC) in a "breakable" MBSC which we can cause + * to stop working. We do this in two phases. The first phase suspends + * any MBSC calls just at the point where they would return to the caller. + * The goal here is to block an EventClientDelegateMBean.fetchNotifications + * operation when it has received notifications but not yet delivered them + * to the EventClient. This is the most delicate point where a breakage + * can occur, because the EventClientDelegate must not drop those notifs + * from its buffer until another fetchNotifs call arrives with a later + * sequence number (which is an implicit ack of the previous set of + * notifs). Once the fetchNotifs call is suspended, we "kill" the MBSC, + * causing it to throw IOException from this and any other calls. That + * triggers the reconnect logic, which will make a new MBSC and issue + * the same fetchNotifs call to it. + * + * The test could be improved by synchronizing explicitly between the + * breakable MBSC and the mainline, so we only proceed to kill the MBSC + * when we are sure that the fetchNotifs call is blocked. As it is, + * we have a small delay which both ensures that no notifs are delivered + * while the connection is suspended, and if the machine is fast enough + * allows the fetchNotifs call to reach the blocking point. + */ +public class ReconnectableConnectorTest { + private static class ReconnectableJMXConnector implements JMXConnector { + private final JMXServiceURL url; + private AtomicReference wrappedJMXC = + new AtomicReference(); + private AtomicReference wrappedMBSC = + new AtomicReference(); + private final NotificationBroadcasterSupport broadcaster = + new NotificationBroadcasterSupport(); + private final Lock connectLock = new ReentrantLock(); + + ReconnectableJMXConnector(JMXServiceURL url) { + this.url = url; + } + + private class ReconnectIH implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + try { + return method.invoke(wrappedMBSC.get(), args); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof IOException) { + connect(); + try { + return method.invoke(wrappedMBSC.get(),args); + } catch (InvocationTargetException ee) { + throw ee.getCause(); + } + } + throw e.getCause(); + } + } + } + + private class FailureListener implements NotificationListener { + public void handleNotification(Notification n, Object h) { + String type = n.getType(); + if (type.equals(JMXConnectionNotification.FAILED)) { + try { + connect(); + } catch (IOException e) { + broadcaster.sendNotification(n); + } + } else if (type.equals(JMXConnectionNotification.NOTIFS_LOST)) + broadcaster.sendNotification(n); + } + } + + public void connect() throws IOException { + connectLock.lock(); + try { + connectWithLock(); + } finally { + connectLock.unlock(); + } + } + + private void connectWithLock() throws IOException { + MBeanServerConnection mbsc = wrappedMBSC.get(); + if (mbsc != null) { + try { + mbsc.getDefaultDomain(); + return; // the connection works + } catch (IOException e) { + // OK: the connection doesn't work, so make a new one + } + } + // This is where we would need to add the fancy logic that + // allows the connection to keep failing for a while + // before giving up. + JMXConnector jmxc = JMXConnectorFactory.connect(url); + jmxc.addConnectionNotificationListener( + new FailureListener(), null, null); + wrappedJMXC.set(jmxc); + if (false) + wrappedMBSC.set(jmxc.getMBeanServerConnection()); + else { + mbsc = jmxc.getMBeanServerConnection(); + InvocationHandler ih = new BreakableIH(mbsc); + mbsc = (MBeanServerConnection) Proxy.newProxyInstance( + MBeanServerConnection.class.getClassLoader(), + new Class[] {MBeanServerConnection.class}, + ih); + wrappedMBSC.set(mbsc); + } + } + + private BreakableIH breakableIH() { + MBeanServerConnection mbsc = wrappedMBSC.get(); + return (BreakableIH) Proxy.getInvocationHandler(mbsc); + } + + void suspend() { + BreakableIH ih = breakableIH(); + ih.suspend(); + } + + void kill() throws IOException { + BreakableIH ih = breakableIH(); + wrappedJMXC.get().close(); + ih.kill(); + } + + public void connect(Map env) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + private final AtomicReference mbscRef = + new AtomicReference(); + + public MBeanServerConnection getMBeanServerConnection() + throws IOException { + connect(); + // Synchro here is not strictly correct: two threads could make + // an MBSC at the same time. OK for a test but beware for real + // code. + MBeanServerConnection mbsc = mbscRef.get(); + if (mbsc != null) + return mbsc; + mbsc = (MBeanServerConnection) Proxy.newProxyInstance( + MBeanServerConnection.class.getClassLoader(), + new Class[] {MBeanServerConnection.class}, + new ReconnectIH()); + mbsc = EventClient.getEventClientConnection(mbsc); + mbscRef.set(mbsc); + return mbsc; + } + + public MBeanServerConnection getMBeanServerConnection( + Subject delegationSubject) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void close() throws IOException { + wrappedJMXC.get().close(); + } + + public void addConnectionNotificationListener( + NotificationListener l, NotificationFilter f, Object h) { + broadcaster.addNotificationListener(l, f, h); + } + + public void removeConnectionNotificationListener(NotificationListener l) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(l); + } + + public void removeConnectionNotificationListener( + NotificationListener l, NotificationFilter f, Object h) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(l, f, h); + } + + public String getConnectionId() throws IOException { + return wrappedJMXC.get().getConnectionId(); + } + } + + // InvocationHandler that allows us to perform a two-phase "break" of + // an object. The first phase suspends the object, so that calls to + // it are blocked just before they return. The second phase unblocks + // suspended threads and causes them to throw IOException. + private static class BreakableIH implements InvocationHandler { + private final Object wrapped; + private final Holder state = new Holder("running"); + + BreakableIH(Object wrapped) { + this.wrapped = wrapped; + } + + void suspend() { + state.set("suspended"); + } + + void kill() { + state.set("killed"); + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + Object result; + try { + result = method.invoke(wrapped, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + String s = state.get(); + if (s.equals("suspended")) + state.waitUntilEqual("killed", 3, TimeUnit.SECONDS); + else if (s.equals("killed")) + throw new IOException("Broken"); + return result; + } + } + + private static class Holder { + private T held; + private Lock lock = new ReentrantLock(); + private Condition changed = lock.newCondition(); + + Holder(T value) { + lock.lock(); + this.held = value; + lock.unlock(); + } + + void waitUntilEqual(T value, long timeout, TimeUnit units) + throws InterruptedException { + long millis = units.toMillis(timeout); + long stop = System.currentTimeMillis() + millis; + Date stopDate = new Date(stop); + lock.lock(); + try { + while (!value.equals(held)) { + boolean ok = changed.awaitUntil(stopDate); + if (!ok) + throw new InterruptedException("Timed out"); + } + } finally { + lock.unlock(); + } + } + + void set(T value) { + lock.lock(); + try { + held = value; + changed.signalAll(); + } finally { + lock.unlock(); + } + } + + T get() { + lock.lock(); + try { + return held; + } finally { + lock.unlock(); + } + } + } + + private static class StoreListener implements NotificationListener { + final BlockingQueue queue = + new ArrayBlockingQueue(100); + + public void handleNotification(Notification n, Object h) { + queue.add(n); + } + + Notification nextNotification(long time, TimeUnit units) + throws InterruptedException { + Notification n = queue.poll(time, units); + if (n == null) + throw new NoSuchElementException("Notification wait timed out"); + return n; + } + + int notifCount() { + return queue.size(); + } + } + + public static interface SenderMBean {} + public static class Sender + extends NotificationBroadcasterSupport implements SenderMBean { + private AtomicLong seqNo = new AtomicLong(0); + + void send() { + Notification n = + new Notification("type", this, seqNo.getAndIncrement()); + sendNotification(n); + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + Sender sender = new Sender(); + ObjectName name = new ObjectName("a:b=c"); + mbs.registerMBean(sender, name); + + System.out.println("Creating connector server"); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer( + url, null, mbs); + cs.start(); + + StoreListener csListener = new StoreListener(); + cs.addNotificationListener(csListener, null, null); + + System.out.println("Creating reconnectable client"); + JMXServiceURL addr = cs.getAddress(); + ReconnectableJMXConnector cc = new ReconnectableJMXConnector(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + + System.out.println("Checking server has sent new-client notif"); + Notification csn = csListener.nextNotification(1, TimeUnit.SECONDS); + assertEquals("CS notif type", + JMXConnectionNotification.OPENED, csn.getType()); + + StoreListener listener = new StoreListener(); + mbsc.addNotificationListener(name, listener, null, null); + + System.out.println("Sending 10 notifs and checking they are received"); + for (int i = 0; i < 10; i++) + sender.send(); + checkNotifs(listener, 0, 10); + + System.out.println("Suspending the fetchNotifs operation"); + cc.suspend(); + System.out.println("Sending a notif while fetchNotifs is suspended"); + sender.send(); + System.out.println("Brief wait before checking no notif is received"); + Thread.sleep(2); + // dumpThreads(); + assertEquals("notif queue while connector suspended", + 0, listener.notifCount()); + assertEquals("connector server notif queue while connector suspended", + 0, csListener.notifCount()); + + System.out.println("Breaking the connection so fetchNotifs will fail over"); + cc.kill(); + + System.out.println("Checking that client has reconnected"); + csn = csListener.nextNotification(1, TimeUnit.SECONDS); + assertEquals("First CS notif type after kill", + JMXConnectionNotification.CLOSED, csn.getType()); + csn = csListener.nextNotification(1, TimeUnit.SECONDS); + assertEquals("Second CS notif type after kill", + JMXConnectionNotification.OPENED, csn.getType()); + + System.out.println("Checking that suspended notif has been received"); + checkNotifs(listener, 10, 11); + } + + private static void checkNotifs( + StoreListener sl, long start, long stop) + throws Exception { + for (long i = start; i < stop; i++) { + Notification n = sl.nextNotification(1, TimeUnit.SECONDS); + assertEquals("received sequence number", i, n.getSequenceNumber()); + } + } + + private static void assertEquals(String what, Object expect, Object actual) + throws Exception { + if (!expect.equals(actual)) { + fail(what + " should be " + expect + " but is " + actual); + } + } + + private static void fail(String why) throws Exception { + throw new Exception("TEST FAILED: " + why); + } + + private static void dumpThreads() { + System.out.println("Thread stack dump"); + Map traces = Thread.getAllStackTraces(); + for (Map.Entry entry : traces.entrySet()) { + Thread t = entry.getKey(); + System.out.println("===Thread " + t.getName() + "==="); + for (StackTraceElement ste : entry.getValue()) + System.out.println(" " + ste); + } + } +} diff --git a/test/javax/management/eventService/SharingThreadTest.java b/test/javax/management/eventService/SharingThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..32c9dd3cf3c12bf60d9d66a3d3c94b3f65e5a94a --- /dev/null +++ b/test/javax/management/eventService/SharingThreadTest.java @@ -0,0 +1,365 @@ +/* + * 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 SharingThreadTest.java 1.3 08/01/22 + * @bug 5108776 + * @summary Basic test for EventClient to see internal thread management. + * @author Shanliang JIANG + * @run clean SharingThreadTest + * @run build SharingThreadTest + * @run main SharingThreadTest + */ + +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegate; +import javax.management.event.EventClientDelegateMBean; +import javax.management.event.FetchingEventRelay; +import javax.management.event.RMIPushEventRelay; +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; + + +public class SharingThreadTest { + + private static MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(); + private static ObjectName emitter; + private static NotificationEmitter emitterImpl; + private static JMXServiceURL url; + private static JMXConnectorServer server; + + + private static int toSend = 10; + private static final long bigWaiting = 6000; + private static int counter = 0; + private static int jobs = 10; + private static int endedJobs = 0; + + private static volatile String failure; + + private static Executor sharedExecutor = new ThreadPoolExecutor(0, 1, 1000, + TimeUnit.MILLISECONDS, new ArrayBlockingQueue(jobs)); + //Executors.newFixedThreadPool(1); + + public static void main(String[] args) throws Exception { + System.out.println(">>> Test on sharing threads for multiple EventClient."); + + // for 1.5 + if (System.getProperty("java.version").startsWith("1.5") && + !mbeanServer.isRegistered(EventClientDelegateMBean.OBJECT_NAME)) { + System.out.print("Working on "+System.getProperty("java.version")+ + " register "+EventClientDelegateMBean.OBJECT_NAME); + + mbeanServer.registerMBean(EventClientDelegate. + getEventClientDelegate(mbeanServer), + EventClientDelegateMBean.OBJECT_NAME); + + sharedExecutor = new ThreadPoolExecutor(1, 1, 1000, + TimeUnit.MILLISECONDS, new ArrayBlockingQueue(jobs)); + } + + emitter = new ObjectName("Default:name=NotificationEmitter"); + emitterImpl = new NotificationEmitter(); + mbeanServer.registerMBean(emitterImpl, emitter); + + String[] types = new String[]{"PushEventRelay", "FetchingEventRelay"}; + String[] protos = new String[]{"rmi", "iiop", "jmxmp"}; + for (String prot : protos) { + url = new JMXServiceURL(prot, null, 0); + + try { + server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + null, mbeanServer); + server.start(); + } catch (Exception e) { + System.out.println(">>> Skip "+prot+", not support."); + continue; + } + + url = server.getAddress(); + + // noise + Thread noise = new Thread(new Runnable() { + public void run() { + while (true) { + emitterImpl.sendNotif(1, null); + try { + Thread.sleep(10); + } catch (Exception e) { + // OK + } + } + } + }); + noise.setDaemon(true); + noise.start(); + + try { + for (String type: types) { + System.out.println("\n\n>>> Testing "+type+" on "+url+" ..."); + JMXConnector conn = newConn(); + try { + testType(type, conn); + } finally { + conn.close(); + System.out.println(">>> Testing "+type+" on "+url+" ... done"); + } + } + } finally { + server.stop(); + } + } + } + + private static void testType(String type, JMXConnector conn) throws Exception { + Thread[] threads = new Thread[jobs]; + for (int i=0; i 0 && failure == null) { + SharingThreadTest.class.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + + if (endedJobs != jobs && failure == null) { + throw new RuntimeException("Need to set bigger waiting timeout?"); + } + + endedJobs = 0; + } + + public static class Job implements Runnable { + public Job(String type, JMXConnector conn) { + this.type = type; + this.conn = conn; + } + public void run() { + try { + test(type, conn); + + synchronized(SharingThreadTest.class) { + endedJobs++; + if (endedJobs>=jobs) { + SharingThreadTest.class.notify(); + } + } + } catch (RuntimeException re) { + re.printStackTrace(System.out); + throw re; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private final String type; + private final JMXConnector conn; + } + + private static void test(String type, JMXConnector conn) throws Exception { + String id = getId(); + + Listener listener = new Listener(id); + Filter filter = new Filter(id); + + //newConn(); + EventClient ec = newEventClient(type, conn); + + System.out.println(">>> ("+id+") To receive notifications "+toSend); + ec.addNotificationListener(emitter, + listener, filter, null); + + emitterImpl.sendNotif(toSend, id); + listener.waitNotifs(bigWaiting, toSend); + if (listener.received != toSend) { + throw new RuntimeException(">>> ("+id+") Expected to receive: " + +toSend+", but got: "+listener.received); + } + + ec.close(); + } + +//-------------------------- +// private classes +//-------------------------- + + private static class Listener implements NotificationListener { + public Listener(String id) { + this.id = id; + } + public void handleNotification(Notification notif, Object handback) { + if (!id.equals(notif.getUserData())) { + System.out.println("("+id+") Filter error, my id is: "+id+ + ", but got "+notif.getUserData()); + System.exit(1); + } + System.out.println("("+id+") received "+notif.getSequenceNumber()); + synchronized (this) { + received++; + + if (sequenceNB < 0) { + sequenceNB = notif.getSequenceNumber(); + } else if(++sequenceNB != notif.getSequenceNumber()) { + fail("(" + id + ") Wrong sequence number, expected: " + +sequenceNB+", but got: "+notif.getSequenceNumber()); + } + if (received >= toSend || failure != null) { + this.notify(); + } + } + } + + public void waitNotifs(long timeout, int nb) throws Exception { + long toWait = timeout; + long stopTime = System.currentTimeMillis() + timeout; + synchronized(this) { + while (received < nb && toWait > 0 && failure == null) { + this.wait(toWait); + toWait = stopTime - System.currentTimeMillis(); + } + } + } + + private String id; + private int received = 0; + + private long sequenceNB = -1; + } + + private static class Filter implements NotificationFilter { + public Filter(String id) { + this.id = id; + } + + public boolean isNotificationEnabled(Notification n) { + return id.equals(n.getUserData()); + } + private String id; + } + + public static class NotificationEmitter extends NotificationBroadcasterSupport + implements NotificationEmitterMBean { + + /** + * Send Notification objects. + * + * @param nb The number of notifications to send + */ + public void sendNotif(int nb, String userData) { + new Thread(new SendJob(nb, userData)).start(); + } + + private class SendJob implements Runnable { + public SendJob(int nb, String userData) { + this.nb = nb; + this.userData = userData; + } + + public void run() { + if (userData != null) { + System.out.println(">>> ("+userData+") sending "+nb); + } + long sequenceNumber = 0; + for (int i = 0; i>> ("+userData+") sending done"); + } + } + private int nb; + private String userData; + } + private final String myType = "notification.my_notification"; + } + + public interface NotificationEmitterMBean { + public void sendNotif(int nb, String userData); + } + + private static JMXConnector newConn() throws IOException { + return JMXConnectorFactory.connect(url); + } + + private static EventClient newEventClient(String type, JMXConnector conn) + throws Exception { + EventClientDelegateMBean proxy = + EventClientDelegate.getProxy(conn.getMBeanServerConnection()); + if (type.equals("PushEventRelay")) { + return new EventClient(proxy, + new RMIPushEventRelay(proxy), sharedExecutor, null, 600); + } else if (type.equals("FetchingEventRelay")) { + return new EventClient(proxy, + new FetchingEventRelay(proxy, + FetchingEventRelay.DEFAULT_BUFFER_SIZE, + 10, + FetchingEventRelay.DEFAULT_MAX_NOTIFICATIONS, + sharedExecutor), + null, null, 600); + } else { + throw new RuntimeException("Wrong event client type: "+type); + } + } + + private static String getId() { + synchronized(SharingThreadTest.class) { + return String.valueOf(counter++); + } + } + + private static void fail(String msg) { + System.out.println("FAIL: " + msg); + failure = msg; + } +} diff --git a/test/javax/management/eventService/SubUnsubTest.java b/test/javax/management/eventService/SubUnsubTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f8889882317fb043cfb6df6ba7e60120b2189c9b --- /dev/null +++ b/test/javax/management/eventService/SubUnsubTest.java @@ -0,0 +1,125 @@ +/* + * 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 SubUnsubTest + * @bug 6736611 + * @summary Test not to remove other listeners when calling unsubscribe + * @author Shanliang JIANG + * @run clean SubUnsubTest + * @run build SubUnsubTest + * @run main SubUnsubTest + */ + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventSubscriber; +import javax.management.event.EventClient; +public class SubUnsubTest { + private static class CountListener implements NotificationListener { + volatile int count; + + public void handleNotification(Notification n, Object h) { + count++; + } + } + + public static interface SenderMBean {} + + public static class Sender extends NotificationBroadcasterSupport + implements SenderMBean { + void send() { + Notification n = new Notification("type", this, 1L); + sendNotification(n); + } + } + + public static void main(String[] args) throws Exception { + System.out.println("Testing EventSubscriber-unsubscribe method."); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name1 = new ObjectName("d:type=Sender,id=1"); + ObjectName name2 = new ObjectName("d:type=Sender,id=2"); + ObjectName pattern = new ObjectName("d:type=Sender,*"); + Sender sender1 = new Sender(); + Sender sender2 = new Sender(); + mbs.registerMBean(sender1, name1); + mbs.registerMBean(sender2, name2); + + EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs); + + System.out.println("Single subscribe covering both MBeans"); + CountListener listener = new CountListener(); + + System.out.println("Subscribing and adding listeners ..."); + sub.subscribe(pattern, listener, null, null); + sub.subscribe(name2, listener, null, null); + mbs.addNotificationListener(name2, listener, null, null); + + sender1.send(); + sender2.send(); + if (listener.count != 4) { + throw new RuntimeException("Do not receive all notifications: "+ + "Expect 4, got "+listener.count); + } + + System.out.println("Unsubscribe the listener with the pattern."); + sub.unsubscribe(pattern, listener); + listener.count = 0; + sender1.send(); + sender2.send(); + if (listener.count != 2) { + throw new RuntimeException("The method unsubscribe removes wrong listeners."); + } + + System.out.println("Unsubscribe the listener with the ObjectName."); + sub.unsubscribe(name2, listener); + listener.count = 0; + sender1.send(); + sender2.send(); + if (listener.count != 1) { + throw new RuntimeException("The method unsubscribe removes wrong listeners."); + } + + System.out.println("Subscribe twice to same MBean with same listener " + + "but different handback."); + sub.subscribe(name1, listener, null, new Object()); + sub.subscribe(name1, listener, null, new Object()); + listener.count = 0; + + sub.unsubscribe(name1, listener); + sender1.send(); + if (listener.count > 0) { + throw new RuntimeException("EventSubscriber: the method unsubscribe" + + " does not remove a listener which was subscribed 2 times."); + } + + System.out.println("Bye bye!"); + return; + } +} \ No newline at end of file diff --git a/test/javax/management/eventService/SubscribeTest.java b/test/javax/management/eventService/SubscribeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fa2df8dad3b1f61ee07547c1cc9fb735a0027f82 --- /dev/null +++ b/test/javax/management/eventService/SubscribeTest.java @@ -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 + * @bug 5108776 + * @summary Test that EventSubscriber.subscribe works + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventSubscriber; + +public class SubscribeTest { + private static class CountListener implements NotificationListener { + volatile int count; + + public void handleNotification(Notification n, Object h) { + count++; + } + } + + private static class SwitchFilter implements NotificationFilter { + volatile boolean enabled; + + public boolean isNotificationEnabled(Notification n) { + return enabled; + } + } + + public static interface SenderMBean {} + + public static class Sender extends NotificationBroadcasterSupport + implements SenderMBean { + void send() { + Notification n = new Notification("type", this, 1L); + sendNotification(n); + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name1 = new ObjectName("d:type=Sender,id=1"); + ObjectName name2 = new ObjectName("d:type=Sender,id=2"); + ObjectName pattern = new ObjectName("d:type=Sender,*"); + Sender sender1 = new Sender(); + Sender sender2 = new Sender(); + mbs.registerMBean(sender1, name1); + mbs.registerMBean(sender2, name2); + + EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs); + + System.out.println("Single subscribe covering both MBeans"); + CountListener listen1 = new CountListener(); + sub.subscribe(pattern, listen1, null, null); + sender1.send(); + assertEquals("Notifs after sender1 send", 1, listen1.count); + sender2.send(); + assertEquals("Notifs after sender2 send", 2, listen1.count); + + System.out.println("Unsubscribe"); + sub.unsubscribe(pattern, listen1); + sender1.send(); + assertEquals("Notifs after sender1 send", 2, listen1.count); + + System.out.println("Subscribe twice to same MBean with same listener " + + "but different filters"); + SwitchFilter filter1 = new SwitchFilter(); + sub.subscribe(name1, listen1, null, null); + sub.subscribe(name1, listen1, filter1, null); + listen1.count = 0; + sender1.send(); + // switch is off, so only one notif expected + assertEquals("Notifs after sender1 send", 1, listen1.count); + filter1.enabled = true; + sender1.send(); + // switch is on, so two more notifs expected + assertEquals("Notifs after sender1 send", 3, listen1.count); + + System.out.println("Remove those subscriptions"); + sub.unsubscribe(name1, listen1); + sender1.send(); + assertEquals("Notifs after sender1 send", 3, listen1.count); + } + + private static void assertEquals(String what, Object expected, Object actual) + throws Exception { + if (!equal(expected, actual)) { + String msg = "Expected " + expected + "; got " + actual; + throw new Exception("TEST FAILED: " + what + ": " + msg); + } + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null) + return false; + return (x.equals(y)); + } +} diff --git a/test/javax/management/eventService/UsingEventService.java b/test/javax/management/eventService/UsingEventService.java new file mode 100644 index 0000000000000000000000000000000000000000..3d768ed8d6faa420b691f08d26e7aebd7f375fc6 --- /dev/null +++ b/test/javax/management/eventService/UsingEventService.java @@ -0,0 +1,84 @@ +/* + * @test UsingEventService.java 1.10 08/01/22 + * @bug 5108776 + * @summary Basic test for EventManager. + * @author Shanliang JIANG + * @run clean UsingEventService + * @run build UsingEventService + * @run main UsingEventService + */ + +import java.util.HashMap; +import java.util.Map; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventConsumer; +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; + +public class UsingEventService { + private static JMXServiceURL url; + private static JMXConnectorServer server; + private static JMXConnector conn; + private static MBeanServerConnection client; + + public static void main(String[] args) throws Exception { + if (System.getProperty("java.version").startsWith("1.5")) { + System.out.println(">>> UsingEventService-main not available for JDK1.5, bye"); + return; + } + + ObjectName oname = new ObjectName("test:t=t"); + Notification n = new Notification("", oname, 0); + + System.out.println(">>> UsingEventService-main basic tests ..."); + MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(); + + url = new JMXServiceURL("rmi", null, 0) ; + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer); + server.start(); + url = server.getAddress(); + + System.out.println(">>> UsingEventService-main test to not use the event service..."); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + System.out.println(">>> UsingEventService-main test to use the event service..."); + Map env = new HashMap(1); + env.put("jmx.remote.use.event.service", "true"); + conn = JMXConnectorFactory.connect(url, env); + client = conn.getMBeanServerConnection(); + + ((EventConsumer)client).subscribe(oname, listener, null, null); + + System.out.println(">>> UsingEventService-main using event service as expected!"); + + System.out.println(">>> UsingEventService-main test to use" + + " the event service with system property..."); + + System.setProperty("jmx.remote.use.event.service", "true"); + conn = JMXConnectorFactory.connect(url, null); + client = conn.getMBeanServerConnection(); + + ((EventConsumer)client).subscribe(oname, listener, null, null); + + System.out.println("" + + ">>> UsingEventService-main using event service as expected!"); + + System.out.println(">>> Happy bye bye!"); + } + + private final static NotificationListener listener = new NotificationListener() { + public void handleNotification(Notification n, Object hk) { + // + } + }; +} diff --git a/test/javax/management/mxbean/ComparatorExceptionTest.java b/test/javax/management/mxbean/ComparatorExceptionTest.java index cd88a161b02ff064064ee6bbb6b5a54eed0973ea..fb10a6eece3707b6e8cb8c65826736fba8cd5c7b 100644 --- a/test/javax/management/mxbean/ComparatorExceptionTest.java +++ b/test/javax/management/mxbean/ComparatorExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/mxbean/GenericArrayTypeTest.java b/test/javax/management/mxbean/GenericArrayTypeTest.java index b99ba96db19922c006731f5fc6816e0e10d2ce3e..b5f6de3ab2c9f7cf394d7e4ebe72a960337ab1cf 100644 --- a/test/javax/management/mxbean/GenericArrayTypeTest.java +++ b/test/javax/management/mxbean/GenericArrayTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -32,17 +32,19 @@ */ import java.lang.management.ManagementFactory; -import java.lang.management.MonitorInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import javax.management.Attribute; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.openmbean.CompositeData; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorServer; @@ -50,6 +52,58 @@ import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; public class GenericArrayTypeTest { + // A version of java.lang.management.MonitorInfo so we can run this test + // on JDK 5, where that class didn't exist. + public static class MonitorInfo { + private final String className; + private final int identityHashCode; + private final int lockedStackDepth; + private final StackTraceElement lockedStackFrame; + + public MonitorInfo( + String className, int identityHashCode, + int lockedStackDepth, StackTraceElement lockedStackFrame) { + this.className = className; + this.identityHashCode = identityHashCode; + this.lockedStackDepth = lockedStackDepth; + this.lockedStackFrame = lockedStackFrame; + } + + public static MonitorInfo from(CompositeData cd) { + try { + CompositeData stecd = (CompositeData) cd.get("lockedStackFrame"); + StackTraceElement ste = new StackTraceElement( + (String) stecd.get("className"), + (String) stecd.get("methodName"), + (String) stecd.get("fileName"), + (Integer) stecd.get("lineNumber")); + return new MonitorInfo( + (String) cd.get("className"), + (Integer) cd.get("identityHashCode"), + (Integer) cd.get("lockedStackDepth"), + ste); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public String getClassName() { + return className; + } + + public int getIdentityHashCode() { + return identityHashCode; + } + + public int getLockedStackDepth() { + return lockedStackDepth; + } + + public StackTraceElement getLockedStackFrame() { + return lockedStackFrame; + } + } + public interface TestMXBean { diff --git a/test/javax/management/mxbean/JMXServiceURLTest.java b/test/javax/management/mxbean/JMXServiceURLTest.java index 12646cf7cd3f21423cc4cbee7f77ee2446d1873e..a688ee701d5911593c4141c69fe90281c39fa782 100644 --- a/test/javax/management/mxbean/JMXServiceURLTest.java +++ b/test/javax/management/mxbean/JMXServiceURLTest.java @@ -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 @@ public class JMXServiceURLTest { } } + 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 @@ public class JMXServiceURLTest { 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 --git a/test/javax/management/mxbean/LeakTest.java b/test/javax/management/mxbean/LeakTest.java index f9248dacb28897fd94d57fa5394c3dd30f2e48bc..f0be0401e21c7e7cff6299fe192056bd9880d77e 100644 --- a/test/javax/management/mxbean/LeakTest.java +++ b/test/javax/management/mxbean/LeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 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 @@ -25,7 +25,7 @@ * @bug 6482247 * @summary Test that creating MXBeans does not introduce memory leaks. * @author Eamonn McManus - * @run build LeakTest + * @run build LeakTest RandomMXBeanTest * @run main LeakTest */ diff --git a/test/javax/management/mxbean/MBeanOperationInfoTest.java b/test/javax/management/mxbean/MBeanOperationInfoTest.java index cff66684829096d160c8264fadc20c8411e9763a..72a571c310d472c1fcf0e469677cbb60059cdb0c 100644 --- a/test/javax/management/mxbean/MBeanOperationInfoTest.java +++ b/test/javax/management/mxbean/MBeanOperationInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 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 @@ -86,7 +86,8 @@ public class MBeanOperationInfoTest { if (error > 0) { System.out.println("\nTEST FAILED"); throw new Exception("TEST FAILED: " + error + " wrong return types"); - } else if (tested != returnTypes.length) { + } else if (tested != returnTypes.length && + !System.getProperty("java.specification.version").equals("1.5")) { System.out.println("\nTEST FAILED"); throw new Exception("TEST FAILED: " + tested + " cases tested, " + returnTypes.length + " expected"); diff --git a/test/javax/management/mxbean/MXBeanTest.java b/test/javax/management/mxbean/MXBeanTest.java index 9415b39faef9c77de7ea2b81f27bda85230fc093..9cfdbdb7230d734e3805d423637c98416bdbd530 100644 --- a/test/javax/management/mxbean/MXBeanTest.java +++ b/test/javax/management/mxbean/MXBeanTest.java @@ -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 @@ -149,7 +149,7 @@ public class MXBeanTest { if (mbai.getName().equals("Ints") && mbai.isReadable() && !mbai.isWritable() && mbai.getDescriptor().getFieldValue("openType") - .equals(new ArrayType(SimpleType.INTEGER, true)) + .equals(new ArrayType(SimpleType.INTEGER, true)) && attrs[0].getType().equals("[I")) success("MBeanAttributeInfo"); else diff --git a/test/javax/management/mxbean/SameObjectTwoNamesTest.java b/test/javax/management/mxbean/SameObjectTwoNamesTest.java index 53cc9bb3b3d9e123a6e4177bb49c3e7bd8ecd120..7aeb580e8abb01d893b987c04c699e867ecff0f6 100644 --- a/test/javax/management/mxbean/SameObjectTwoNamesTest.java +++ b/test/javax/management/mxbean/SameObjectTwoNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/javax/management/mxbean/ThreadMXBeanTest.java b/test/javax/management/mxbean/ThreadMXBeanTest.java index 2f79d8a86011cd2b3ec57302151e3b6d8426290b..ae2280e18af6839ec5520d5ecfc6d3697c708025 100644 --- a/test/javax/management/mxbean/ThreadMXBeanTest.java +++ b/test/javax/management/mxbean/ThreadMXBeanTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -46,7 +46,8 @@ public class ThreadMXBeanTest { long[] ids1 = proxy.getAllThreadIds(); // Add some random ids to the list so we'll get back null ThreadInfo - long[] ids2 = Arrays.copyOf(ids1, ids1.length + 10); + long[] ids2 = new long[ids1.length + 10]; + System.arraycopy(ids1, 0, ids2, 0, ids1.length); Random r = new Random(); for (int i = ids1.length; i < ids2.length; i++) ids2[i] = Math.abs(r.nextLong()); diff --git a/test/javax/management/mxbean/TigerMXBean.java b/test/javax/management/mxbean/TigerMXBean.java index f4f652cc79828592f93f253eaae142b569f907be..539f6ba7a6c0ad364297db43edb4dee6a7f7d0b2 100644 --- a/test/javax/management/mxbean/TigerMXBean.java +++ b/test/javax/management/mxbean/TigerMXBean.java @@ -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 @@ -83,20 +83,20 @@ public interface TigerMXBean { Tuiseal opEnum(Tuiseal x, Tuiseal y); List StringList = Arrays.asList(new String[] {"a", "b", "x"}); - ArrayType StringListType = + ArrayType StringListType = MerlinMXBean.ArrayTypeMaker.make(1, SimpleType.STRING); List getStringList(); void setStringList(List x); List opStringList(List x, List y); - Set StringSet = new HashSet(StringList); - ArrayType StringSetType = StringListType; + Set StringSet = new HashSet(StringList); + ArrayType StringSetType = StringListType; Set getStringSet(); void setStringSet(Set x); Set opStringSet(Set x, Set y); - SortedSet SortedStringSet = new TreeSet(StringList); - ArrayType SortedStringSetType = StringListType; + SortedSet SortedStringSet = new TreeSet(StringList); + ArrayType SortedStringSetType = StringListType; SortedSet getSortedStringSet(); void setSortedStringSet(SortedSet x); SortedSet opSortedStringSet(SortedSet x, @@ -119,7 +119,7 @@ public interface TigerMXBean { Map> y); SortedMap XSortedMap = - new TreeMap(Collections.singletonMap("foo", "bar")); + new TreeMap(Collections.singletonMap("foo", "bar")); String XSortedMapTypeName = "java.util.SortedMap"; CompositeType XSortedMapRowType = MerlinMXBean.CompositeTypeMaker.make( @@ -137,8 +137,8 @@ public interface TigerMXBean { // For bug 6319960, try constructing Set and Map with non-Comparable - Set PointSet = new HashSet(Collections.singleton(Point)); - ArrayType PointSetType = + Set PointSet = new HashSet(Collections.singleton(Point)); + ArrayType PointSetType = MerlinMXBean.ArrayTypeMaker.make(1, PointType); Set getPointSet(); void setPointSet(Set x); diff --git a/test/javax/management/namespace/DomainCreationTest.java b/test/javax/management/namespace/DomainCreationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..02a09868e1394d42a53bb8ae7e239102630b3d6c --- /dev/null +++ b/test/javax/management/namespace/DomainCreationTest.java @@ -0,0 +1,330 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/EventWithNamespaceControlTest.java b/test/javax/management/namespace/EventWithNamespaceControlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1e3901104c7462a2666e21e9708f064ab9a936e5 --- /dev/null +++ b/test/javax/management/namespace/EventWithNamespaceControlTest.java @@ -0,0 +1,93 @@ +/* + * 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 + * @bug 5072476 5108776 + * @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 --git a/test/javax/management/namespace/EventWithNamespaceTest.java b/test/javax/management/namespace/EventWithNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..748fdbeff148742e934c7ff6155a1e8e2bb07cbe --- /dev/null +++ b/test/javax/management/namespace/EventWithNamespaceTest.java @@ -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 5072476 5108776 + * @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 --git a/test/javax/management/namespace/ExportNamespaceTest.java b/test/javax/management/namespace/ExportNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ec49a4c0c0c00c55f5758463aef19ca6e07d2515 --- /dev/null +++ b/test/javax/management/namespace/ExportNamespaceTest.java @@ -0,0 +1,100 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/JMXDomainTest.java b/test/javax/management/namespace/JMXDomainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..258cead1ab079dc321ac9c7856c5842981aa4dcf --- /dev/null +++ b/test/javax/management/namespace/JMXDomainTest.java @@ -0,0 +1,513 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/JMXNamespaceSecurityTest.java b/test/javax/management/namespace/JMXNamespaceSecurityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..213ffbfb63e734be4bb10ce6cd8ed85586e1e320 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceSecurityTest.java @@ -0,0 +1,273 @@ +/* + * 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 + * @bug 5072476 6299231 + * @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 --git a/test/javax/management/namespace/JMXNamespaceTest.java b/test/javax/management/namespace/JMXNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a35377112aa5e08a82d4a841ae5aa3a2ffa1c1f1 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceTest.java @@ -0,0 +1,511 @@ +/* + * 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. + * @bug 5072476 + * @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.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.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +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; + } + } + } + + public 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); + } + } + + public static void verySimpleTest(String[] args) { + System.err.println("verySimpleTest: starting"); + try { + final MBeanServer srv = MBeanServerFactory.createMBeanServer(); + srv.registerMBean(new JMXNamespace( + JMXNamespaces.narrowToNamespace(srv, "foo")), + JMXNamespaces.getNamespaceObjectName("foo")); + throw new Exception("Excpected IllegalArgumentException not raised."); + } catch (IllegalArgumentException x) { + System.err.println("verySimpleTest: got expected exception: "+x); + } catch (Exception x) { + System.err.println("verySimpleTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.err.println("verySimpleTest: PASSED"); + } + + public static void verySimpleTest2(String[] args) { + System.err.println("verySimpleTest2: starting"); + try { + final MBeanServer srv = MBeanServerFactory.createMBeanServer(); + final JMXConnectorServer cs = JMXConnectorServerFactory. + newJMXConnectorServer(new JMXServiceURL("rmi",null,0), + null, srv); + cs.start(); + final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress()); + + srv.registerMBean(new JMXNamespace( + new MBeanServerConnectionWrapper( + JMXNamespaces.narrowToNamespace( + cc.getMBeanServerConnection(), + "foo"))), + JMXNamespaces.getNamespaceObjectName("foo")); + throw new Exception("Excpected IllegalArgumentException not raised."); + } catch (IllegalArgumentException x) { + System.err.println("verySimpleTest2: got expected exception: "+x); + } catch (Exception x) { + System.err.println("verySimpleTest2 FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.err.println("verySimpleTest2: PASSED"); + } + + public static void main(String[] args) { + simpleTest(args); + recursiveTest(args); + verySimpleTest(args); + verySimpleTest2(args); + } + +} diff --git a/test/javax/management/namespace/JMXNamespaceViewTest.java b/test/javax/management/namespace/JMXNamespaceViewTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e134968296b9990c95694bd41b74ca11c6637dfe --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceViewTest.java @@ -0,0 +1,550 @@ +/* + * 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. + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/JMXNamespacesTest.java b/test/javax/management/namespace/JMXNamespacesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4dc7c518a1afecf87e438ddee438791029c54bb3 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespacesTest.java @@ -0,0 +1,648 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/JMXRemoteNamespaceTest.java b/test/javax/management/namespace/JMXRemoteNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e5f795a6ba3fc2cbdcb6d7702dba26fcecc937e --- /dev/null +++ b/test/javax/management/namespace/JMXRemoteNamespaceTest.java @@ -0,0 +1,190 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/JMXRemoteTargetNamespace.java b/test/javax/management/namespace/JMXRemoteTargetNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..3d83844b1ffe1eef1c21a33dc86010711b85981a --- /dev/null +++ b/test/javax/management/namespace/JMXRemoteTargetNamespace.java @@ -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 --git a/test/javax/management/namespace/LazyDomainTest.java b/test/javax/management/namespace/LazyDomainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eda9b66696d4e89a5b6208592696204fe5a6cc6d --- /dev/null +++ b/test/javax/management/namespace/LazyDomainTest.java @@ -0,0 +1,790 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/LeadingSeparatorsTest.java b/test/javax/management/namespace/LeadingSeparatorsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5660b275317bc98a9d25a16d11802b51a88bc35d --- /dev/null +++ b/test/javax/management/namespace/LeadingSeparatorsTest.java @@ -0,0 +1,227 @@ +/* + * 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 LeadingSeparatorsTest.java + * @summary Test that the semantics of a leading // in ObjectName is respected. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean LeadingSeparatorsTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true LeadingSeparatorsTest.java + * @run build LeadingSeparatorsTest Wombat WombatMBean + * @run main LeadingSeparatorsTest + */ + +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; +import java.util.logging.Logger; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +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 LeadingSeparatorsTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class LeadingSeparatorsTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(LeadingSeparatorsTest.class.getName()); + + /** Creates a new instance of NullObjectNameTest */ + public LeadingSeparatorsTest() { + } + + public static interface MyWombatMBean extends WombatMBean { + public Set untrue(ObjectName pat) throws Exception; + } + public static class MyWombat + extends Wombat implements MyWombatMBean { + public MyWombat() throws NotCompliantMBeanException { + super(MyWombatMBean.class); + } + + public Set untrue(ObjectName pat) throws Exception { + final Set res=listMatching(pat.withDomain("*")); + final Set untrue = new HashSet(); + for (ObjectName a:res) { + untrue.add(a.withDomain(pat.getDomain()+"//"+a.getDomain())); + } + return untrue; + } + } + + 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")); + + final ObjectName n1 = new ObjectName("//direct//w:type=Wombat"); + final ObjectName n2 = new ObjectName("direct//w:type=Wombat"); + final ObjectName n3 = new ObjectName("//rmi//w:type=Wombat"); + final ObjectName n4 = new ObjectName("rmi//w:type=Wombat"); + + // register wombat using an object name with a leading // + final Object obj = new MyWombat(); + // check that returned object name doesn't have the leading // + assertEquals(n2,top.registerMBean(obj, n1).getObjectName()); + System.out.println(n1+" registered"); + + // check that the registered Wombat can be accessed with all its + // names. + System.out.println(n2+" mood is: "+top.getAttribute(n2, "Mood")); + System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood")); + System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood")); + System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood")); + + // call listMatching. The result should not contain any prefix. + final Set res = (Set) + top.invoke(n3, "listMatching", + // remove rmi// from rmi//*:* + JMXNamespaces.deepReplaceHeadNamespace( + new Object[] {ObjectName.WILDCARD.withDomain("rmi//*")}, + "rmi", ""), new String[] {ObjectName.class.getName()}); + + // add rmi// prefix to all names in res. + final Set res1 = + JMXNamespaces.deepReplaceHeadNamespace(res, "", "rmi"); + System.out.println("got: "+res1); + + // compute expected result + final Set res2 = sub.queryNames(null,null); + final Set res3 = new HashSet(); + for (ObjectName o:res2) { + res3.add(o.withDomain("rmi//"+o.getDomain())); + } + System.out.println("expected: "+res3); + assertEquals(res1, res3); + + // invoke "untrue(//niark//niark:*)" + // should return a set were all ObjectNames begin with + // //niark//niark// + // + final Set res4 = (Set) + top.invoke(n3, "untrue", + // remove niark//niark : should remove nothing since + // our ObjectName begins with a leading // + JMXNamespaces.deepReplaceHeadNamespace( + new Object[] { + ObjectName.WILDCARD.withDomain("//niark//niark")}, + "niark//niark", ""), + new String[] {ObjectName.class.getName()}); + System.out.println("got: "+res4); + + // add rmi// should add nothing since the returned names have a + // leading // + // + final Set res5 = + JMXNamespaces.deepReplaceHeadNamespace(res4, "", "rmi"); + System.out.println("got#2: "+res5); + + // compute expected result + final Set res6 = new HashSet(); + for (ObjectName o:res2) { + res6.add(o.withDomain("//niark//niark//"+o.getDomain())); + } + System.out.println("expected: "+res6); + + // both res4 and res5 should be equals to the expected result. + assertEquals(res4, res6); + assertEquals(res5, res6); + + } 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 --git a/test/javax/management/namespace/MXBeanRefTest.java b/test/javax/management/namespace/MXBeanRefTest.java new file mode 100644 index 0000000000000000000000000000000000000000..afdc0ae9789cef47a50b878af5e30cae7f3dfde4 --- /dev/null +++ b/test/javax/management/namespace/MXBeanRefTest.java @@ -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 --git a/test/javax/management/namespace/NamespaceController.java b/test/javax/management/namespace/NamespaceController.java new file mode 100644 index 0000000000000000000000000000000000000000..f5a1c42e294d8c7f39341f27b5b33c54f2efffce --- /dev/null +++ b/test/javax/management/namespace/NamespaceController.java @@ -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 --git a/test/javax/management/namespace/NamespaceControllerMBean.java b/test/javax/management/namespace/NamespaceControllerMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..b7bc3457e9fc2e6f446565f8e125af84f40d59bb --- /dev/null +++ b/test/javax/management/namespace/NamespaceControllerMBean.java @@ -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 --git a/test/javax/management/namespace/NamespaceCreationTest.java b/test/javax/management/namespace/NamespaceCreationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..871bf022052030f735724ac9bea2b3bb9e46e0c8 --- /dev/null +++ b/test/javax/management/namespace/NamespaceCreationTest.java @@ -0,0 +1,263 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/NamespaceNotificationsTest.java b/test/javax/management/namespace/NamespaceNotificationsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9c5a1a04a1ca29bd26ba583b0ecf3b8127c1ad63 --- /dev/null +++ b/test/javax/management/namespace/NamespaceNotificationsTest.java @@ -0,0 +1,389 @@ +/* + * 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. + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/NullDomainObjectNameTest.java b/test/javax/management/namespace/NullDomainObjectNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3251d388a860cf07ed79729cef353270082562a3 --- /dev/null +++ b/test/javax/management/namespace/NullDomainObjectNameTest.java @@ -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 --git a/test/javax/management/namespace/NullObjectNameTest.java b/test/javax/management/namespace/NullObjectNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..156e7661db55b816880044563b415990f47ca977 --- /dev/null +++ b/test/javax/management/namespace/NullObjectNameTest.java @@ -0,0 +1,252 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/QueryNamesTest.java b/test/javax/management/namespace/QueryNamesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1af597aceb938b10ee70e0f5201711b827bd4afe --- /dev/null +++ b/test/javax/management/namespace/QueryNamesTest.java @@ -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 QueryNamesTest.java 1.4 + * @summary Test how queryNames works with Namespaces. + * @author Daniel Fuchs + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/RemoveNotificationListenerTest.java b/test/javax/management/namespace/RemoveNotificationListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a8ea2aee376fbd780bce27b0b27bcaf60ad36017 --- /dev/null +++ b/test/javax/management/namespace/RemoveNotificationListenerTest.java @@ -0,0 +1,377 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/RoutingServerProxyTest.java b/test/javax/management/namespace/RoutingServerProxyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..698021321d14e0f76c750aa560f6d6942d5cc892 --- /dev/null +++ b/test/javax/management/namespace/RoutingServerProxyTest.java @@ -0,0 +1,400 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/SerialParamProcessorTest.java b/test/javax/management/namespace/SerialParamProcessorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..20df761d0e28debbda750ad06a9447a03b5c3971 --- /dev/null +++ b/test/javax/management/namespace/SerialParamProcessorTest.java @@ -0,0 +1,572 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/VirtualMBeanTest.java b/test/javax/management/namespace/VirtualMBeanTest.java new file mode 100644 index 0000000000000000000000000000000000000000..03fd3983e63b468324bb0c28e13740cb91712fdc --- /dev/null +++ b/test/javax/management/namespace/VirtualMBeanTest.java @@ -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 5072476 + * @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 --git a/test/javax/management/namespace/VirtualNamespaceQueryTest.java b/test/javax/management/namespace/VirtualNamespaceQueryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8af244a7bc2db73212d19e6eed4773af77aeb97a --- /dev/null +++ b/test/javax/management/namespace/VirtualNamespaceQueryTest.java @@ -0,0 +1,128 @@ +/* + * 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 + * @bug 5072476 + * @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 --git a/test/javax/management/namespace/VirtualPropsTest.java b/test/javax/management/namespace/VirtualPropsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..904cc5359d7f08fedf03364b0057959b810f8fb0 --- /dev/null +++ b/test/javax/management/namespace/VirtualPropsTest.java @@ -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 5072476 + * @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 --git a/test/javax/management/namespace/Wombat.java b/test/javax/management/namespace/Wombat.java new file mode 100644 index 0000000000000000000000000000000000000000..bef648c0fc99a2f24f5deb099010953ee68e89e3 --- /dev/null +++ b/test/javax/management/namespace/Wombat.java @@ -0,0 +1,259 @@ +/* + * 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 { + this(WombatMBean.class); + } + + public Wombat(Class clazz) + throws NotCompliantMBeanException { + super(clazz); + 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 --git a/test/javax/management/namespace/WombatMBean.java b/test/javax/management/namespace/WombatMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..73f4875317e85dc8cba42c6e4328167b50d2df70 --- /dev/null +++ b/test/javax/management/namespace/WombatMBean.java @@ -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 --git a/test/javax/management/namespace/namespace.policy b/test/javax/management/namespace/namespace.policy new file mode 100644 index 0000000000000000000000000000000000000000..e77bb79c91e87e091194e37257308c4035c3703d --- /dev/null +++ b/test/javax/management/namespace/namespace.policy @@ -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 --git a/test/javax/management/openmbean/CompositeDataStringTest.java b/test/javax/management/openmbean/CompositeDataStringTest.java new file mode 100644 index 0000000000000000000000000000000000000000..286bfd1d41bfdd932eaea446a82c16902fe15265 --- /dev/null +++ b/test/javax/management/openmbean/CompositeDataStringTest.java @@ -0,0 +1,89 @@ +/* + * 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 javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + +/* + * @test + * @bug 6610174 + * @summary Test that CompositeDataSupport.toString() represents arrays correctly + * @author Eamonn McManus + */ +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; + +public class CompositeDataStringTest { + public static void main(String[] args) throws Exception { + CompositeType basicCT = new CompositeType( + "basicCT", "basic CompositeType", + new String[] {"name", "value"}, + new String[] {"name", "value"}, + new OpenType[] {SimpleType.STRING, SimpleType.INTEGER}); + CompositeType ct = new CompositeType( + "noddy", "descr", + new String[] {"strings", "ints", "cds"}, + new String[] {"string array", "int array", "composite data array"}, + new OpenType[] { + ArrayType.getArrayType(SimpleType.STRING), + ArrayType.getPrimitiveArrayType(int[].class), + ArrayType.getArrayType(basicCT) + }); + CompositeData basicCD1 = new CompositeDataSupport( + basicCT, new String[] {"name", "value"}, new Object[] {"ceathar", 4}); + CompositeData basicCD2 = new CompositeDataSupport( + basicCT, new String[] {"name", "value"}, new Object[] {"naoi", 9}); + CompositeData cd = new CompositeDataSupport( + ct, + new String[] {"strings", "ints", "cds"}, + new Object[] { + new String[] {"fred", "jim", "sheila"}, + new int[] {2, 3, 5, 7}, + new CompositeData[] {basicCD1, basicCD2} + }); + String s = cd.toString(); + System.out.println("CompositeDataSupport.toString(): " + s); + String[] expected = { + "fred, jim, sheila", + "2, 3, 5, 7", + "ceathar", + "naoi", + }; + boolean ok = true; + for (String expect : expected) { + if (s.contains(expect)) + System.out.println("OK: string contains <" + expect + ">"); + else { + ok = false; + System.out.println("NOT OK: string does not contain <" + + expect + ">"); + } + } + if (ok) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: string did not contain expected substrings"); + } +} diff --git a/test/javax/management/openmbean/TabularDataOrderTest.java b/test/javax/management/openmbean/TabularDataOrderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..877c41b36dff34604c74f66349cccdff8157aed2 --- /dev/null +++ b/test/javax/management/openmbean/TabularDataOrderTest.java @@ -0,0 +1,190 @@ +/* + * 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 6334663 + * @summary Test that TabularDataSupport preserves the order elements were added + * @author Eamonn McManus + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +public class TabularDataOrderTest { + private static String failure; + + private static final String COMPAT_PROP_NAME = "jmx.tabular.data.hash.map"; + + private static final String[] intNames = { + "unus", "duo", "tres", "quatuor", "quinque", "sex", "septem", + "octo", "novem", "decim", + }; + private static final Map stringToValue = + new LinkedHashMap(); + static { + for (int i = 0; i < intNames.length; i++) + stringToValue.put(intNames[i], i + 1); + } + + public static interface TestMXBean { + public Map getMap(); + } + + public static class TestImpl implements TestMXBean { + public Map getMap() { + return stringToValue; + } + } + + private static final CompositeType ct; + private static final TabularType tt; + static { + try { + ct = new CompositeType( + "a.b.c", "name and int", + new String[] {"name", "int"}, + new String[] {"name of integer", "value of integer"}, + new OpenType[] {SimpleType.STRING, SimpleType.INTEGER}); + tt = new TabularType( + "d.e.f", "name and int indexed by name", ct, + new String[] {"name"}); + } catch (OpenDataException e) { + throw new AssertionError(e); + } + } + + private static TabularData makeTable() throws OpenDataException { + TabularData td = new TabularDataSupport(tt); + for (Map.Entry entry : stringToValue.entrySet()) { + CompositeData cd = new CompositeDataSupport( + ct, + new String[] {"name", "int"}, + new Object[] {entry.getKey(), entry.getValue()}); + td.put(cd); + } + return td; + } + + public static void main(String[] args) throws Exception { + System.out.println("Testing standard behaviour"); + TabularData td = makeTable(); + System.out.println(td); + + // Test that a default TabularData has the order keys were added in + int last = 0; + boolean ordered = true; + for (Object x : td.values()) { + CompositeData cd = (CompositeData) x; + String name = (String) cd.get("name"); + int value = (Integer) cd.get("int"); + System.out.println(name + " = " + value); + if (last + 1 != value) + ordered = false; + last = value; + } + if (!ordered) + fail("Order not preserved"); + + // Now test the undocumented property that causes HashMap to be used + // instead of LinkedHashMap, in case serializing to a 1.3 client. + // We serialize and deserialize in case the implementation handles + // this at serialization time. Then we look at object fields; that's + // not guaranteed to work but at worst it will fail spuriously and + // we'll have to update the test. + System.out.println("Testing compatible behaviour"); + System.setProperty(COMPAT_PROP_NAME, "true"); + td = makeTable(); + System.out.println(td); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(bout); + oout.writeObject(td); + oout.close(); + byte[] bytes = bout.toByteArray(); + ByteArrayInputStream bin = new ByteArrayInputStream(bytes); + ObjectInputStream oin = new ObjectInputStream(bin); + td = (TabularData) oin.readObject(); + boolean found = false; + for (Field f : td.getClass().getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) + continue; + f.setAccessible(true); + Object x = f.get(td); + if (x != null && x.getClass() == HashMap.class) { + found = true; + System.out.println( + x.getClass().getName() + " TabularDataSupport." + + f.getName() + " = " + x); + break; + } + } + if (!found) { + fail("TabularDataSupport does not contain HashMap though " + + COMPAT_PROP_NAME + "=true"); + } + System.clearProperty(COMPAT_PROP_NAME); + + System.out.println("Testing MXBean behaviour"); + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + ObjectName name = new ObjectName("a:b=c"); + mbs.registerMBean(new TestImpl(), name); + TestMXBean proxy = JMX.newMXBeanProxy(mbs, name, TestMXBean.class); + Map map = proxy.getMap(); + List origNames = new ArrayList(stringToValue.keySet()); + List proxyNames = new ArrayList(map.keySet()); + if (!origNames.equals(proxyNames)) + fail("Order mangled after passage through MXBean: " + proxyNames); + + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + private static void fail(String why) { + System.out.println("FAILED: " + why); + failure = why; + } +} diff --git a/test/javax/management/query/QueryNotifFilterTest.java b/test/javax/management/query/QueryNotifFilterTest.java index 2f3dcaa314c8715194874bf44f10d4ef37ac7d1d..8b685741b793b72239c1b88c36ae798caa07a4c1 100644 --- a/test/javax/management/query/QueryNotifFilterTest.java +++ b/test/javax/management/query/QueryNotifFilterTest.java @@ -98,7 +98,7 @@ public class QueryNotifFilterTest { this.queryString = queryString; } abstract boolean apply(MBeanServer mbs, ObjectName name) throws Exception; - @Override + //@Override - doesn't override in JDK5 public boolean apply(ObjectName name) { try { return apply(getMBeanServer(), name); diff --git a/test/javax/management/remote/mandatory/connection/CloseServerTest.java b/test/javax/management/remote/mandatory/connection/CloseServerTest.java index ca92bc7cfd5aabbdde4b2cf37520dd7c632b14b2..c5b1b19c3c1b5fd5bce37799a1b6d68afabe6bd3 100644 --- a/test/javax/management/remote/mandatory/connection/CloseServerTest.java +++ b/test/javax/management/remote/mandatory/connection/CloseServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,16 @@ * @run main CloseServerTest */ +import com.sun.jmx.remote.util.EnvHelp; import java.net.MalformedURLException; -import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; public class CloseServerTest { private static final String[] protocols = {"rmi", "iiop", "jmxmp"}; @@ -131,40 +136,54 @@ public class CloseServerTest { server.stop(); - // with a client listener, but close the server first - System.out.println(">>> Open, start a server, create a client, add a listener, close the server then the client."); - server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs); - server.start(); + List> envs = Arrays.asList( + Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"), + Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "true")); - addr = server.getAddress(); - client = JMXConnectorFactory.newJMXConnector(addr, null); - client.connect(null); + for (Map env : envs) { + System.out.println( + ">>>>>>>> " + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE + + " = " + env.get(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE)); - mserver = client.getMBeanServerConnection(); - mserver.addNotificationListener(delegateName, dummyListener, null, null); + // with a client listener, but close the server first + System.out.println(">>> Open, start a server, create a client, " + + "add a listener, close the server then the client."); + server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); + server.start(); - server.stop(); + addr = server.getAddress(); + client = JMXConnectorFactory.newJMXConnector(addr, null); + client.connect(null); - try { - client.close(); - } catch (Exception e) { - // ok, it is because the server has been closed. - } + mserver = client.getMBeanServerConnection(); + mserver.addNotificationListener(delegateName, dummyListener, null, null); - // with a client listener, but close the client first - System.out.println(">>> Open, start a server, create a client, add a listener, close the client then the server."); - server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs); - server.start(); + server.stop(); - addr = server.getAddress(); - client = JMXConnectorFactory.newJMXConnector(addr, null); - client.connect(null); + try { + client.close(); + } catch (Exception e) { + // ok, it is because the server has been closed. + } - mserver = client.getMBeanServerConnection(); - mserver.addNotificationListener(delegateName, dummyListener, null, null); + // with a client listener, but close the client first + System.out.println(">>> Open, start a server, create a client, " + + "add a listener, close the client then the server."); + server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); + server.start(); - client.close(); - server.stop(); + addr = server.getAddress(); + client = JMXConnectorFactory.newJMXConnector(addr, null); + client.connect(null); + + mserver = client.getMBeanServerConnection(); + mserver.addNotificationListener(delegateName, dummyListener, null, null); + + client.close(); + server.stop(); + } } catch (MalformedURLException e) { System.out.println(">>> Skipping unsupported URL " + u); return true; diff --git a/test/javax/management/remote/mandatory/connection/DeadLockTest.java b/test/javax/management/remote/mandatory/connection/DeadLockTest.java index 52f2b3ca00a048c374798d35a7542ec42dff9d88..5ea4f8d50b85b450497b701a3a891370e9d10a04 100644 --- a/test/javax/management/remote/mandatory/connection/DeadLockTest.java +++ b/test/javax/management/remote/mandatory/connection/DeadLockTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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,6 +37,7 @@ import java.util.HashMap; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; public class DeadLockTest { private static final String[] protocols = {"rmi", "iiop", "jmxmp"}; @@ -72,6 +73,9 @@ public class DeadLockTest { // disable the client ping env.put("jmx.remote.x.client.connection.check.period", "0"); + // ensure we are not internally using the Event Service on the server + env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); + try { u = new JMXServiceURL(proto, null, 0); server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); diff --git a/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java b/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java index caf0bc77088b2bf67943cd95c065934abdd6cf6c..b157bf049a375b793dff79294c3b1bc5444fa798 100644 --- a/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java +++ b/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,8 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import com.sun.jmx.remote.util.EnvHelp; +import java.util.Collections; +import javax.management.remote.rmi.RMIConnectorServer; public class IdleTimeoutTest { public static void main(String[] args) throws Exception { @@ -88,8 +90,13 @@ public class IdleTimeoutTest { private static long getIdleTimeout(MBeanServer mbs, JMXServiceURL url) throws Exception { + // If the connector server is using the Event Service, then connections + // never time out. This is by design. + Map env = + Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); JMXConnectorServer server = - JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); server.start(); try { url = server.getAddress(); @@ -164,6 +171,7 @@ public class IdleTimeoutTest { Map idleMap = new HashMap(); idleMap.put(EnvHelp.SERVER_CONNECTION_TIMEOUT, new Long(timeout)); + idleMap.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(url,idleMap,mbs); diff --git a/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java b/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0204afb1665245e83b07535f9584ba4ef790b07c --- /dev/null +++ b/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java @@ -0,0 +1,256 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +import java.io.IOException; +import java.io.Serializable; +import java.net.Socket; +import java.rmi.server.RMIClientSocketFactory; +import java.util.HashMap; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +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; +import javax.management.remote.rmi.RMIConnectorServer; + +/* + * @test + * @bug 6697180 + * @summary test on a client notification deadlock. + * @author Shanliang JIANG + * @run clean MultiThreadDeadLockTest + * @run build MultiThreadDeadLockTest + * @run main MultiThreadDeadLockTest + */ + +public class MultiThreadDeadLockTest { + + private static long serverTimeout = 500L; + + public static void main(String[] args) throws Exception { + print("Create the MBean server"); + MBeanServer mbs = MBeanServerFactory.createMBeanServer(); + + print("Initialize environment map"); + HashMap env = new HashMap(); + + print("Specify a client socket factory to control socket creation."); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, + clientFactory); + + print("Specify a server idle timeout to make a server close an idle connection."); + env.put("jmx.remote.x.server.connection.timeout", serverTimeout); + + print("Disable client heartbeat."); + env.put("jmx.remote.x.client.connection.check.period", 0); + + env.put("jmx.remote.x.notification.fetch.timeout", serverTimeout); + + print("Create an RMI server"); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); + server.start(); + + url = server.getAddress(); + + print("Create jmx client on "+url); + StateMachine.setState(CREATE_SOCKET); // allow to create client socket + client = JMXConnectorFactory.connect(url, env); + Thread.sleep(100); + + totoName = new ObjectName("default:name=toto"); + mbs.registerMBean(toto, totoName); + print("Register the mbean: " + totoName); + + print("Add listener to toto MBean"); + client.getMBeanServerConnection().addNotificationListener( + totoName, myListener, null, null); + Thread.sleep(10); + + print("send notif, listener will block the fetcher"); + toto.sendNotif(); + Thread.sleep(100); + + StateMachine.setState(NO_OP); + + print("Sleep 3 times of server idle timeout: "+serverTimeout+ + ", the sever should close the idle connection."); + Thread.sleep(serverTimeout*3); + + print("start the user thread to call mbean method, it will get IOexception" + + " and start the reconnection, the socket factory will block the" + + " socket creation."); + UserThread ut = new UserThread(); + ut.start(); + Thread.sleep(10); + + print("Free the listener, the fetcher will get IO and makes " + + "a deadlock if the bug is not fixed."); + StateMachine.setState(FREE_LISTENER); + Thread.sleep(100); + + print("Allow to create new socket for the reconnection"); + StateMachine.setState(CREATE_SOCKET); + + print("Check whether the user thread gets free to call the mbean."); + if (!ut.waitDone(5000)) { + throw new RuntimeException("Possible deadlock!"); + } + + print("Remove the listener."); + client.getMBeanServerConnection().removeNotificationListener( + totoName, myListener, null, null); + Thread.sleep(serverTimeout*3); + + print("\nWell passed, bye!"); + + client.close(); + Thread.sleep(10); + server.stop(); + } + + private static ObjectName totoName = null; + private static JMXConnector client; + + public static class UserThread extends Thread { + public UserThread() { + setDaemon(true); + } + + public void run() { + try { + client.getMBeanServerConnection().invoke( + totoName, "allowReturn", null, null); + } catch (Exception e) { + throw new Error(e); + } + + synchronized(UserThread.class) { + done = true; + UserThread.class.notify(); + } + } + + public boolean waitDone(long timeout) { + synchronized(UserThread.class) { + if(!done) { + try { + UserThread.class.wait(timeout); + } catch (Exception e) { + throw new Error(e); + } + } + } + return done; + } + + private boolean done = false; + } + + public static interface TotoMBean { + public void allowReturn(); + } + + public static class Toto extends NotificationBroadcasterSupport + implements TotoMBean { + + public void allowReturn() { + enter("allowReturn"); + + leave("allowReturn"); + } + + public void sendNotif() { + enter("sendNotif"); + + sendNotification(new Notification("Toto", totoName, 0)); + + leave("sendNotif"); + } + } + private static Toto toto = new Toto(); + + public static NotificationListener myListener = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + enter("handleNotification"); + + StateMachine.waitState(FREE_LISTENER); + + leave("handleNotification"); + } + }; + + public static class RMIClientFactory + implements RMIClientSocketFactory, Serializable { + + public Socket createSocket(String host, int port) throws IOException { + enter("createSocket"); + //print("Calling createSocket(" + host + " " + port + ")"); + + StateMachine.waitState(CREATE_SOCKET); + Socket s = new Socket(host, port); + leave("createSocket"); + + return s; + } + } + private static RMIClientFactory clientFactory = new RMIClientFactory(); + + private static int CREATE_SOCKET = 1; + private static int FREE_LISTENER = 3; + private static int NO_OP = 0; + + public static class StateMachine { + + private static int state = NO_OP; + private static int[] lock = new int[0]; + + public static void waitState(int s) { + synchronized (lock) { + while (state != s) { + try { + lock.wait(); + } catch (InterruptedException ire) { + // should not + throw new Error(ire); + } + } + } + } + + public static int getState() { + synchronized (lock) { + return state; + } + } + + public static void setState(int s) { + synchronized (lock) { + state = s; + lock.notifyAll(); + } + } + } + + private static void print(String m) { + System.out.println(m); + } + + private static void enter(String m) { + System.out.println("\n---Enter the method " + m); + } + + private static void leave(String m) { + System.out.println("===Leave the method: " + m); + } +} + diff --git a/test/javax/management/remote/mandatory/connection/RMIExitTest.java b/test/javax/management/remote/mandatory/connection/RMIExitTest.java index 08f687f432928b496779b1c089c237142991740a..8b8d6e56718db47a8ed312829d5249a88f1ab1f9 100644 --- a/test/javax/management/remote/mandatory/connection/RMIExitTest.java +++ b/test/javax/management/remote/mandatory/connection/RMIExitTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.net.MalformedURLException; import java.io.IOException; +import java.util.Collections; +import java.util.Map; import javax.management.MBeanServerFactory; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -47,12 +49,14 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.rmi.RMIConnectorServer; /** * VM shutdown hook. Test that the hook is called less than 5 secs * after expected exit. */ class TimeChecker extends Thread { + @Override public void run() { System.out.println("shutdown hook called"); long elapsedTime = @@ -81,12 +85,15 @@ public class RMIExitTest { public static void main(String[] args) { System.out.println("Start test"); Runtime.getRuntime().addShutdownHook(new TimeChecker()); - test(); + test(false); + test(true); exitStartTime = System.currentTimeMillis(); System.out.println("End test"); } - private static void test() { + private static void test(boolean eventService) { + System.out.println( + "---testing with" + (eventService ? "" : "out") + " Event Service"); try { JMXServiceURL u = new JMXServiceURL("rmi", null, 0); JMXConnectorServer server; @@ -105,8 +112,11 @@ public class RMIExitTest { } }; + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); server = JMXConnectorServerFactory.newJMXConnectorServer(u, - null, + env, mbs); server.start(); diff --git a/test/javax/management/remote/mandatory/connection/ReconnectTest.java b/test/javax/management/remote/mandatory/connection/ReconnectTest.java index 674b830e5b558f9f0a8e9ac8de112207428057d3..6be0e9e39b7f0c04dde4765177b1cba18fa5f512 100644 --- a/test/javax/management/remote/mandatory/connection/ReconnectTest.java +++ b/test/javax/management/remote/mandatory/connection/ReconnectTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,10 @@ import java.util.*; import java.net.MalformedURLException; -import java.io.IOException; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; public class ReconnectTest { private static final String[] protocols = {"rmi", "iiop", "jmxmp"}; @@ -48,6 +48,7 @@ public class ReconnectTest { String timeout = "1000"; env.put("jmx.remote.x.server.connection.timeout", timeout); env.put("jmx.remote.x.client.connection.check.period", timeout); + env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); } public static void main(String[] args) throws Exception { diff --git a/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java b/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b6c6d87926fade5670fce3242a6994b442c77d7d --- /dev/null +++ b/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java @@ -0,0 +1,274 @@ +/* + * 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.NoSuchElementException; +import java.util.Random; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.remote.IdentityMBeanServerForwarder; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; + +/* + * @test + * @bug 6218920 + * @summary Tests manipulation of MBeanServerForwarder chains. + * @author Eamonn McManus + */ +import javax.management.remote.rmi.RMIConnectorServer; + +public class ForwarderChainTest { + private static final TestMBeanServerForwarder[] forwarders = + new TestMBeanServerForwarder[10]; + static { + for (int i = 0; i < forwarders.length; i++) + forwarders[i] = new TestMBeanServerForwarder(i); + } + + private static class TestMBeanServerForwarder + extends IdentityMBeanServerForwarder { + private final int index; + volatile int defaultDomainCount; + + TestMBeanServerForwarder(int index) { + this.index = index; + } + + @Override + public String getDefaultDomain() { + defaultDomainCount++; + return super.getDefaultDomain(); + } + + @Override + public String toString() { + return "forwarders[" + index + "]"; + } + } + + private static String failure; + + public static void main(String[] args) throws Exception { + + System.out.println("===Test with newly created, unattached server==="); + + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///"); + JMXConnectorServer cs = new RMIConnectorServer(url, null); + test(cs, null); + + System.out.println("===Test with server attached to MBS==="); + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + cs = new RMIConnectorServer(url, null, mbs); + test(cs, mbs); + + System.out.println("===Remove any leftover forwarders==="); + while (cs.getSystemMBeanServer() instanceof MBeanServerForwarder) { + MBeanServerForwarder mbsf = + (MBeanServerForwarder) cs.getSystemMBeanServer(); + cs.removeMBeanServerForwarder(mbsf); + } + expectChain(cs, "U", mbs); + + System.out.println("===Ensure forwarders are called==="); + cs.setMBeanServerForwarder(forwarders[0]); + cs.setSystemMBeanServerForwarder(forwarders[1]); + expectChain(cs, "1U0", mbs); + cs.start(); + if (forwarders[0].defaultDomainCount != 0 || + forwarders[1].defaultDomainCount != 0) { + fail("defaultDomainCount not zero"); + } + JMXServiceURL addr = cs.getAddress(); + JMXConnector cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + mbsc.getDefaultDomain(); + cc.close(); + cs.stop(); + for (boolean system : new boolean[] {false, true}) { + TestMBeanServerForwarder mbsf = system ? forwarders[1] : forwarders[0]; + if (mbsf.defaultDomainCount != 1) { + fail((system ? "System" : "User") + " forwarder called " + + mbsf.defaultDomainCount + " times"); + } + } + + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + private static void test(JMXConnectorServer cs, MBeanServer end) { + // A newly-created connector server might have system forwarders, + // so get rid of those. + while (cs.getSystemMBeanServer() != cs.getMBeanServer()) + cs.removeMBeanServerForwarder((MBeanServerForwarder) cs.getSystemMBeanServer()); + + expectChain(cs, "U", end); + + System.out.println("Add a user forwarder"); + cs.setMBeanServerForwarder(forwarders[0]); + expectChain(cs, "U0", end); + + System.out.println("Add another user forwarder"); + cs.setMBeanServerForwarder(forwarders[1]); + expectChain(cs, "U10", end); + + System.out.println("Add a system forwarder"); + cs.setSystemMBeanServerForwarder(forwarders[2]); + expectChain(cs, "2U10", end); + + System.out.println("Add another user forwarder"); + cs.setMBeanServerForwarder(forwarders[3]); + expectChain(cs, "2U310", end); + + System.out.println("Add another system forwarder"); + cs.setSystemMBeanServerForwarder(forwarders[4]); + expectChain(cs, "42U310", end); + + System.out.println("Remove the first user forwarder"); + cs.removeMBeanServerForwarder(forwarders[3]); + expectChain(cs, "42U10", end); + + System.out.println("Remove the last user forwarder"); + cs.removeMBeanServerForwarder(forwarders[0]); + expectChain(cs, "42U1", end); + + System.out.println("Remove the first system forwarder"); + cs.removeMBeanServerForwarder(forwarders[4]); + expectChain(cs, "2U1", end); + + System.out.println("Remove the last system forwarder"); + cs.removeMBeanServerForwarder(forwarders[2]); + expectChain(cs, "U1", end); + + System.out.println("Remove the last forwarder"); + cs.removeMBeanServerForwarder(forwarders[1]); + expectChain(cs, "U", end); + + System.out.println("---Doing random manipulations---"); + // In this loop we pick one of the forwarders at random each time. + // If it is already in the chain, then we remove it. If it is not + // in the chain, then we do one of three things: try to remove it + // (expecting an exception); add it to the user chain; or add it + // to the system chain. + // A subtle point is that if there is no MBeanServer then + // cs.setMBeanServerForwarder(mbsf) does not change mbsf.getMBeanServer(). + // Since we're recycling a random forwarder[i], we explicitly + // call mbsf.setMBeanServer(null) in this case. + String chain = "U"; + Random r = new Random(); + for (int i = 0; i < 50; i++) { + int fwdi = r.nextInt(10); + MBeanServerForwarder mbsf = forwarders[fwdi]; + char c = (char) ('0' + fwdi); + int ci = chain.indexOf(c); + if (ci >= 0) { + System.out.println("Remove " + c); + cs.removeMBeanServerForwarder(mbsf); + chain = chain.substring(0, ci) + chain.substring(ci + 1); + } else { + switch (r.nextInt(3)) { + case 0: { // try to remove it + try { + System.out.println("Try to remove absent " + c); + cs.removeMBeanServerForwarder(mbsf); + fail("Remove succeeded but should not have"); + return; + } catch (NoSuchElementException e) { + } + break; + } + case 1: { // add it to the user chain + System.out.println("Add " + c + " to user chain"); + if (cs.getMBeanServer() == null) + mbsf.setMBeanServer(null); + cs.setMBeanServerForwarder(mbsf); + int postu = chain.indexOf('U') + 1; + chain = chain.substring(0, postu) + c + + chain.substring(postu); + break; + } + case 2: { // add it to the system chain + System.out.println("Add " + c + " to system chain"); + if (cs.getSystemMBeanServer() == null) + mbsf.setMBeanServer(null); + cs.setSystemMBeanServerForwarder(mbsf); + chain = c + chain; + break; + } + } + } + expectChain(cs, chain, end); + } + } + + /* + * Check that the forwarder chain has the expected contents. The forwarders + * are encoded as a string. For example, "12U34" means that the system + * chain contains forwarders[1] followed by forwarders[2], and the user + * chain contains forwarders[3] followed by forwarders[4]. Since the + * user chain is attached to the end of the system chain, another way to + * look at this is that the U marks the transition from one to the other. + * + * After traversing the chains, we should be pointing at "end". + */ + private static void expectChain( + JMXConnectorServer cs, String chain, MBeanServer end) { + System.out.println("...expected chain: " + chain); + MBeanServer curr = cs.getSystemMBeanServer(); + int i = 0; + while (i < chain.length()) { + char c = chain.charAt(i); + if (c == 'U') { + if (cs.getMBeanServer() != curr) { + fail("User chain should have started here: " + curr); + return; + } + } else { + int fwdi = c - '0'; + MBeanServerForwarder forwarder = forwarders[fwdi]; + if (curr != forwarder) { + fail("Expected forwarder " + c + " here: " + curr); + return; + } + curr = ((MBeanServerForwarder) curr).getMBeanServer(); + } + i++; + } + if (curr != end) { + fail("End of chain is " + curr + ", should be " + end); + return; + } + System.out.println("...OK"); + } + + private static void fail(String msg) { + System.out.println("FAILED: " + msg); + failure = msg; + } +} diff --git a/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java b/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d2d5e3771fff03e6d791dbbed93c758c6cd35c3f --- /dev/null +++ b/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java @@ -0,0 +1,177 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.management.MBeanServer; +import javax.management.event.EventClientDelegate; +import javax.management.remote.JMXConnectorServer; + +/* + * @test + * @bug 6663757 + * @summary Tests standard MBeanServerForwarders introduced by connector server + * options. + * @author Eamonn McManus + */ +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; + +public class StandardForwardersTest { + private static String failure; + + private static class Forwarder { + private final String attribute; + private final boolean defaultEnabled; + private final Class expectedClass; + + public Forwarder(String attribute, boolean defaultEnabled, + Class expectedClass) { + this.attribute = attribute; + this.defaultEnabled = defaultEnabled; + this.expectedClass = expectedClass; + } + } + + private static enum Status {DISABLED, ENABLED, DEFAULT} + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + MBeanServerForwarder ecdFwd = + EventClientDelegate.newForwarder(); + Forwarder ecd = new Forwarder( + JMXConnectorServer.EVENT_CLIENT_DELEGATE_FORWARDER, true, + ecdFwd.getClass()); + + Forwarder[] forwarders = {ecd}; + + // Now go through every combination of forwarders. Each forwarder + // may be explicitly enabled, explicitly disabled, or left to its + // default value. + int nStatus = Status.values().length; + int limit = (int) Math.pow(nStatus, forwarders.length); + for (int i = 0; i < limit; i++) { + Status[] status = new Status[forwarders.length]; + int ii = i; + for (int j = 0; j < status.length; j++) { + status[j] = Status.values()[ii % nStatus]; + ii /= nStatus; + } + Map env = new HashMap(); + String test = ""; + for (int j = 0; j < status.length; j++) { + if (!test.equals("")) + test += "; "; + test += forwarders[j].attribute; + switch (status[j]) { + case DISABLED: + test += "=false"; + env.put(forwarders[j].attribute, "false"); + break; + case ENABLED: + test += "=true"; + env.put(forwarders[j].attribute, "true"); + break; + case DEFAULT: + test += "=default(" + forwarders[j].defaultEnabled + ")"; + break; + } + } + boolean consistent = isConsistent(env); + test += "; (" + (consistent ? "" : "in") + "consistent)"; + System.out.println(test); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///"); + try { + JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); + if (!consistent) { + fail("Inconsistent attributes should have been rejected " + + "but were not"); + } + checkForwarders(cs, forwarders, status); + } catch (IllegalArgumentException e) { + if (consistent) { + fail("Consistent attributes provoked IllegalArgumentException"); + e.printStackTrace(System.out); + } + } + } + + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception(failure); + } + + // Check that the classes of the forwarders in the system chain correspond + // to what we expect given the options we have passed. This check is a bit + // superficial in the sense that a forwarder might be for example a + // SingleMBeanForwarderHandler but that doesn't prove that it is the + // right Single MBean. Nevertheless the test should expose any severe + // wrongness. + // + // The check here makes some assumptions that could become untrue in the + // future. First, it assumes that the forwarders that are added have + // exactly the classes that are in the Forwarder[] array. So for example + // the forwarder for CONTEXT_FORWARDER must be of the same class as an + // explicit call to ClientContext.newContextForwarder. The spec doesn't + // require that - it only requires that the forwarder have the same + // behaviour. The second assumption is that the connector server doesn't + // add any forwarders of its own into the system chain, and again the spec + // doesn't disallow that. + private static void checkForwarders( + JMXConnectorServer cs, Forwarder[] forwarders, Status[] status) { + List> expectedClasses = new ArrayList>(); + for (int i = 0; i < forwarders.length; i++) { + if (status[i] == Status.ENABLED || + (status[i] == Status.DEFAULT && forwarders[i].defaultEnabled)) + expectedClasses.add(forwarders[i].expectedClass); + } + MBeanServer stop = cs.getMBeanServer(); + List> foundClasses = new ArrayList>(); + for (MBeanServer mbs = cs.getSystemMBeanServer(); mbs != stop; + mbs = ((MBeanServerForwarder) mbs).getMBeanServer()) + foundClasses.add(mbs.getClass()); + if (!expectedClasses.equals(foundClasses)) { + fail("Incorrect forwarder chain: expected " + expectedClasses + + "; found " + foundClasses); + } + } + + // env is consistent if either (a) localizer is not enabled or (b) + // localizer is enabled and context is enabled. + // Neither of those is present in this codebase so env is always consistent. + private static boolean isConsistent(Map env) { + return true; + } + + private static void fail(String why) { + System.out.println("FAILED: " + why); + failure = why; + } +} diff --git a/test/javax/management/remote/mandatory/loading/MissingClassTest.java b/test/javax/management/remote/mandatory/loading/MissingClassTest.java index 7aab83079c10efbab6f3eb56d7a339ab9ac8cff3..98dbdd29025da167232532f5a0083f77e6aab414 100644 --- a/test/javax/management/remote/mandatory/loading/MissingClassTest.java +++ b/test/javax/management/remote/mandatory/loading/MissingClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,13 +44,33 @@ We also test objects that are of known class but not serializable. The test cases are similar. */ -import java.io.*; -import java.net.*; -import java.util.*; -import javax.management.*; -import javax.management.loading.*; -import javax.management.remote.*; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectOutputStream; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import javax.management.Attribute; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +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; import javax.management.remote.rmi.RMIConnectorServer; +import org.omg.CORBA.MARSHAL; public class MissingClassTest { private static final int NNOTIFS = 50; @@ -84,7 +104,6 @@ public class MissingClassTest { serverLoader.loadClass("$ClientUnknown$").newInstance(); final String[] protos = {"rmi", /*"iiop",*/ "jmxmp"}; - // iiop commented out until bug 4935098 is fixed boolean ok = true; for (int i = 0; i < protos.length; i++) { try { @@ -105,7 +124,16 @@ public class MissingClassTest { } private static boolean test(String proto) throws Exception { - System.out.println("Testing for proto " + proto); + boolean ok = true; + for (boolean eventService : new boolean[] {false, true}) + ok &= test(proto, eventService); + return ok; + } + + private static boolean test(String proto, boolean eventService) + throws Exception { + System.out.println("Testing for proto " + proto + " with" + + (eventService ? "" : "out") + " Event Service"); boolean ok = true; @@ -117,6 +145,8 @@ public class MissingClassTest { Map serverMap = new HashMap(); serverMap.put(JMXConnectorServerFactory.DEFAULT_CLASS_LOADER, serverLoader); + serverMap.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); // make sure no auto-close at server side serverMap.put("jmx.remote.x.server.connection.timeout", "888888888"); @@ -155,6 +185,8 @@ public class MissingClassTest { ok = false; } catch (IOException e) { Throwable cause = e.getCause(); + if (cause instanceof MARSHAL) // see CR 4935098 + cause = cause.getCause(); if (cause instanceof ClassNotFoundException) { System.out.println("Success: got an IOException wrapping " + "a ClassNotFoundException"); @@ -177,6 +209,8 @@ public class MissingClassTest { ok = false; } catch (IOException e) { Throwable wrapped = e.getCause(); + if (wrapped instanceof MARSHAL) // see CR 4935098 + wrapped = wrapped.getCause(); if (wrapped instanceof ClassNotFoundException) { System.out.println("Success: got an IOException wrapping " + "a ClassNotFoundException: " + @@ -228,6 +262,8 @@ public class MissingClassTest { ok = false; } catch (IOException e) { Throwable cause = e.getCause(); + if (cause instanceof MARSHAL) // see CR 4935098 + cause = cause.getCause(); if (cause instanceof ClassNotFoundException) { System.out.println("Success: got an IOException " + "wrapping a ClassNotFoundException"); @@ -461,12 +497,13 @@ public class MissingClassTest { while ((remain = deadline - System.currentTimeMillis()) >= 0) { synchronized (result) { if (result.failed - || (result.knownCount == NNOTIFS - && result.lostCount == NNOTIFS*2)) + || (result.knownCount >= NNOTIFS + && result.lostCount >= NNOTIFS*2)) break; result.wait(remain); } } + Thread.sleep(2); // allow any spurious extra notifs to arrive if (result.failed) { System.out.println("TEST FAILS: Notification strangeness"); return false; @@ -476,6 +513,11 @@ public class MissingClassTest { "got NOTIFS_LOST for unknown and " + "unserializable ones"); return true; + } else if (result.knownCount >= NNOTIFS + || result.lostCount >= NNOTIFS*2) { + System.out.println("TEST FAILS: Received too many notifs: " + + "known=" + result.knownCount + "; lost=" + result.lostCount); + return false; } else { System.out.println("TEST FAILS: Timed out without receiving " + "all notifs: known=" + result.knownCount + diff --git a/test/javax/management/remote/mandatory/notif/AddRemoveTest.java b/test/javax/management/remote/mandatory/notif/AddRemoveTest.java index 126a761ff056a7687e65b60f5b035fc4f42689f4..667badc7f67ad289e46af2d66dc5343af4a2de89 100644 --- a/test/javax/management/remote/mandatory/notif/AddRemoveTest.java +++ b/test/javax/management/remote/mandatory/notif/AddRemoveTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,12 @@ */ import java.net.MalformedURLException; -import java.io.IOException; +import java.util.Collections; +import java.util.Map; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; public class AddRemoveTest { private static final String[] protocols = {"rmi", "iiop", "jmxmp"}; @@ -69,9 +71,16 @@ public class AddRemoveTest { } } - private static boolean test(String proto) + private static boolean test(String proto) throws Exception { + boolean ok = test(proto, false); + ok &= test(proto, true); + return ok; + } + + private static boolean test(String proto, boolean eventService) throws Exception { - System.out.println(">>> Test for protocol " + proto); + System.out.println(">>> Test for protocol " + proto + " with" + + (eventService ? "" : "out") + " event service"); JMXServiceURL u = new JMXServiceURL(proto, null, 0); JMXConnectorServer server; JMXServiceURL addr; @@ -89,7 +98,10 @@ public class AddRemoveTest { try { // with a client listener, but close the server first - server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); + server = JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); server.start(); addr = server.getAddress(); diff --git a/test/javax/management/remote/mandatory/notif/DiffHBTest.java b/test/javax/management/remote/mandatory/notif/DiffHBTest.java index 8903d88dc30ab9d33385cc51f3fd32cda060b1f2..887d9443604ac545a1cd1ae01954dd080dc0c476 100644 --- a/test/javax/management/remote/mandatory/notif/DiffHBTest.java +++ b/test/javax/management/remote/mandatory/notif/DiffHBTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,12 @@ * @run main DiffHBTest */ -import java.net.MalformedURLException; -import java.io.IOException; +import java.util.Collections; +import java.util.Map; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; /** * This test registeres an unique listener with two different handbacks, @@ -48,11 +49,6 @@ public class DiffHBTest { private static ObjectName delegateName; private static ObjectName timerName; - public static int received = 0; - public static final int[] receivedLock = new int[0]; - public static Notification receivedNotif = null; - - public static Object receivedHB = null; public static final String[] hbs = new String[] {"0", "1"}; public static void main(String[] args) throws Exception { @@ -61,162 +57,174 @@ public class DiffHBTest { delegateName = new ObjectName("JMImplementation:type=MBeanServerDelegate"); timerName = new ObjectName("MBean:name=Timer"); - boolean ok = true; + String errors = ""; + for (int i = 0; i < protocols.length; i++) { - try { - if (!test(protocols[i])) { - System.out.println(">>> Test failed for " + protocols[i]); - ok = false; + final String s = test(protocols[i]); + if (s != null) { + if ("".equals(errors)) { + errors = "Failed to " + protocols[i] + ": "+s; } else { - System.out.println(">>> Test successed for " + protocols[i]); + errors = "\tFailed to " + protocols[i] + ": "+s; } - } catch (Exception e) { - System.out.println(">>> Test failed for " + protocols[i]); - e.printStackTrace(System.out); - ok = false; } } - if (ok) { - System.out.println(">>> Test passed"); + if ("".equals(errors)) { + System.out.println(">>> Passed!"); } else { - System.out.println(">>> TEST FAILED"); - System.exit(1); + System.out.println(">>> Failed!"); + + throw new RuntimeException(errors); } } - private static boolean test(String proto) throws Exception { - System.out.println(">>> Test for protocol " + proto); + private static String test(String proto) throws Exception { + String ret = null; + for (boolean eventService : new boolean[] {false, true}) { + String s = test(proto, eventService); + if (s != null) { + if (ret == null) + ret = s; + else + ret = ret + "; " + s; + } + } + return ret; + } + + private static String test(String proto, boolean eventService) + throws Exception { + System.out.println(">>> Test for protocol " + proto + " with" + + (eventService ? "" : "out") + " event service"); JMXServiceURL u = new JMXServiceURL(proto, null, 0); JMXConnectorServer server; - JMXServiceURL addr; JMXConnector client; - MBeanServerConnection mserver; - - final NotificationListener dummyListener = new NotificationListener() { - public void handleNotification(Notification n, Object o) { - synchronized(receivedLock) { - if (n == null) { - System.out.println(">>> Got a null notification."); - System.exit(1); - } - - // check number - if (received > 2) { - System.out.println(">>> Expect to receive 2 notifs, but get "+received); - System.exit(1); - } - - if (received == 0) { // first time - receivedNotif = n; - receivedHB = o; - - if (!hbs[0].equals(o) && !hbs[1].equals(o)) { - System.out.println(">>> Unkown handback: "+o); - System.exit(1); - } - } else { // second time - if (!receivedNotif.equals(n)) { - System.out.println(">>> Not get same notif twice."); - System.exit(1); - } else if (!hbs[0].equals(o) && !hbs[1].equals(o)) { // validate handback - System.out.println(">>> Unkown handback: "+o); - System.exit(1); - } else if (receivedHB.equals(o)) { - System.out.println(">>> Got same handback twice: "+o); - System.exit(1); - } - } - - ++received; - - if (received == 2) { - receivedLock.notify(); - } - } - } - }; try { - server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); + server = + JMXConnectorServerFactory.newJMXConnectorServer(u, env, mbs); server.start(); + JMXServiceURL addr = server.getAddress(); + client = JMXConnectorFactory.connect(addr, null); + } catch (Exception e) { + // not support + System.out.println(">>> not support: " + proto); + return null; + } - addr = server.getAddress(); - client = JMXConnectorFactory.newJMXConnector(addr, null); - client.connect(null); - - mserver = client.getMBeanServerConnection(); - - mserver.addNotificationListener(delegateName, dummyListener, null, hbs[0]); - mserver.addNotificationListener(delegateName, dummyListener, null, hbs[1]); + MBeanServerConnection mserver = client.getMBeanServerConnection(); - for (int i=0; i<20; i++) { - synchronized(receivedLock) { - received = 0; - } + System.out.print(">>>\t"); + for (int i=0; i<5; i++) { + System.out.print(i + "\t"); + final MyListener dummyListener = new MyListener(); + mserver.addNotificationListener( + delegateName, dummyListener, null, hbs[0]); + mserver.addNotificationListener( + delegateName, dummyListener, null, hbs[1]); - mserver.createMBean("javax.management.timer.Timer", timerName); + mserver.createMBean("javax.management.timer.Timer", timerName); - synchronized(receivedLock) { - if (received != 2) { - long remainingTime = waitingTime; - final long startTime = System.currentTimeMillis(); + long remainingTime = waitingTime; + final long startTime = System.currentTimeMillis(); - while (received != 2 && remainingTime > 0) { - receivedLock.wait(remainingTime); - remainingTime = waitingTime - + try { + synchronized(dummyListener) { + while (!dummyListener.done && remainingTime > 0) { + dummyListener.wait(remainingTime); + remainingTime = waitingTime - (System.currentTimeMillis() - startTime); - } } - if (received != 2) { - System.out.println(">>> Expected 2 notifis, but received "+received); - - return false; + if (dummyListener.errorInfo != null) { + return dummyListener.errorInfo; } } + } finally { + //System.out.println("Unregister: "+i); + mserver.unregisterMBean(timerName); + mserver.removeNotificationListener(delegateName, dummyListener); + } + } + System.out.println(""); + client.close(); + server.stop(); - synchronized(receivedLock) { - received = 0; - } + return null; + } - mserver.unregisterMBean(timerName); + private static class MyListener implements NotificationListener { + public boolean done = false; + public String errorInfo = null; + + private int received = 0; + private MBeanServerNotification receivedNotif = null; + private Object receivedHB = null; + public void handleNotification(Notification n, Object o) { + if (!(n instanceof MBeanServerNotification)) { + failed("Received an unexpected notification: "+n); + return; + } - synchronized(receivedLock) { - if (received != 2) { + if (!hbs[0].equals(o) && !hbs[1].equals(o)) { + failed("Unkown handback: "+o); + return; + } - long remainingTime = waitingTime; - final long startTime = System.currentTimeMillis(); + // what we need + final MBeanServerNotification msn = (MBeanServerNotification)n; + if (!(MBeanServerNotification.REGISTRATION_NOTIFICATION.equals( + msn.getType())) || + !msn.getMBeanName().equals(timerName)) { + return; + } - while (received != 2 && remainingTime >0) { - receivedLock.wait(remainingTime); - remainingTime = waitingTime - - (System.currentTimeMillis() - startTime); - } - } + synchronized(this) { + received++; - if (received != 2) { - System.out.println(">>> Expected 2 notifis, but received "+received); + if (received == 1) { // first time + receivedNotif = msn; + receivedHB = o; - return false; - } + return; } - } - mserver.removeNotificationListener(delegateName, dummyListener); + if (received > 2) { + failed("Expect to receive 2 notifs, but get "+received); - client.close(); + return; + } - server.stop(); + // second time + if (receivedHB.equals(o)) { + failed("Got same handback twice: "+o); + } else if(!hbs[0].equals(o) && !hbs[1].equals(o)) { + failed("Unknown handback: "+o); + } else if (receivedNotif.getSequenceNumber() != + msn.getSequenceNumber()) { + failed("expected to receive:\n" + +receivedNotif + +"\n but got\n"+msn); + } - } catch (MalformedURLException e) { - System.out.println(">>> Skipping unsupported URL " + u); - return true; + // passed + done = true; + this.notify(); + } } - return true; + private void failed(String errorInfo) { + this.errorInfo = errorInfo; + done = true; + + this.notify(); + } } - private final static long waitingTime = 10000; + private final static long waitingTime = 2000; } diff --git a/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java b/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java index 0e7a69d345cf4b5aa99df8d7837692d6dbb03ac8..2d098bf4d664fa200578eca7452d40b1f94e9c74 100644 --- a/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java +++ b/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -29,11 +29,12 @@ * @author Shanliang JIANG * @run clean EmptyDomainNotificationTest * @run build EmptyDomainNotificationTest - * @run main EmptyDomainNotificationTest + * @run main EmptyDomainNotificationTest classic + * @run main EmptyDomainNotificationTest event */ -import java.util.ArrayList; -import java.util.List; +import java.util.Collections; +import java.util.Map; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import javax.management.MBeanServerFactory; @@ -46,6 +47,7 @@ import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; public class EmptyDomainNotificationTest { @@ -80,11 +82,25 @@ public class EmptyDomainNotificationTest { public static void main(String[] args) throws Exception { + String type = args[0]; + boolean eventService; + if (type.equals("classic")) + eventService = false; + else if (type.equals("event")) + eventService = true; + else + throw new IllegalArgumentException(type); + final MBeanServer mbs = MBeanServerFactory.createMBeanServer(); final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); - JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); + + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); server.start(); JMXConnector client = JMXConnectorFactory.connect(server.getAddress(), null); diff --git a/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java b/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java index d0c519e45cadc9ec2840d7d145b48bb1bbdd2ad4..ea50947adeb8deb1e080518c19f393e6a1b087b3 100644 --- a/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java +++ b/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 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 @@ -51,18 +51,29 @@ * been compiled by the second. */ -import java.lang.management.ManagementFactory; -import javax.management.*; -import javax.management.remote.*; -import java.util.concurrent.*; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.Semaphore; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +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; +import javax.management.remote.rmi.RMIConnectorServer; public class ListenerScaleTest { private static final int WARMUP_WITH_ONE_MBEAN = 1000; private static final int NOTIFS_TO_TIME = 100; private static final int EXTRA_MBEANS = 20000; - private static final MBeanServer mbs = - ManagementFactory.getPlatformMBeanServer(); private static final ObjectName testObjectName; static { try { @@ -87,7 +98,7 @@ public class ListenerScaleTest { } }; - private static final long timeNotif() { + private static final long timeNotif(MBeanServer mbs) { try { startTime = System.nanoTime(); nnotifs = 0; @@ -117,12 +128,20 @@ public class ListenerScaleTest { }; public static void main(String[] args) throws Exception { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + test(false); + test(true); + } + + private static void test(boolean eventService) throws Exception { + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); Sender sender = new Sender(); mbs.registerMBean(sender, testObjectName); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); JMXConnectorServer cs = - JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); cs.start(); JMXServiceURL addr = cs.getAddress(); JMXConnector cc = JMXConnectorFactory.connect(addr); @@ -140,7 +159,7 @@ public class ListenerScaleTest { mbsc.addNotificationListener(testObjectName, timingListener, null, null); long singleMBeanTime = 0; for (int i = 0; i < WARMUP_WITH_ONE_MBEAN; i++) - singleMBeanTime = timeNotif(); + singleMBeanTime = timeNotif(mbs); if (singleMBeanTime == 0) singleMBeanTime = 1; System.out.println("Time with a single MBean: " + singleMBeanTime + "ns"); @@ -165,7 +184,7 @@ public class ListenerScaleTest { } System.out.println(); System.out.println("Timing a notification send now"); - long manyMBeansTime = timeNotif(); + long manyMBeansTime = timeNotif(mbs); System.out.println("Time with many MBeans: " + manyMBeansTime + "ns"); double ratio = (double) manyMBeansTime / singleMBeanTime; if (ratio > 100.0) diff --git a/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java b/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java index 254e8712bacf666831e8ad42d4885c6a52112520..4fad7d03a22a973bdc86ededb6b71b1b31e772ef 100644 --- a/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java +++ b/test/javax/management/remote/mandatory/notif/NotifBufferSizePropertyNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -31,11 +31,11 @@ * @run main NotifBufferSizePropertyNameTest */ -import java.io.IOException; import java.util.*; import javax.management.*; import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; /** * This class tests also the size of a server notification buffer. @@ -88,6 +88,9 @@ public class NotifBufferSizePropertyNameTest { private static void test(Map env) throws Exception { final MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + env = new HashMap((env == null) ? Collections.emptyMap() : env); + env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); + mbs.registerMBean(new NotificationEmitter(), oname); JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer( url, diff --git a/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java b/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java index bb053999870882381f7f56a80e0788373aebe21a..eb3cd45be9f82bc31471f94e6a9ddc3b2ec929a5 100644 --- a/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java +++ b/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -22,7 +22,7 @@ */ /* - * @test NotifReconnectDeadlockTest + * @test * @bug 6199899 * @summary Tests reconnection done by a fetching notif thread. * @author Shanliang JIANG @@ -31,11 +31,21 @@ * @run main NotifReconnectDeadlockTest */ -import java.io.IOException; -import java.util.*; - -import javax.management.*; -import javax.management.remote.*; +import java.util.HashMap; +import java.util.Map; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +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; +import javax.management.remote.rmi.RMIConnectorServer; /** * "This test checks for a bug whereby reconnection did not work if (a) it was @@ -64,6 +74,7 @@ public class NotifReconnectDeadlockTest { Map env = new HashMap(2); env.put("jmx.remote.x.server.connection.timeout", new Long(serverTimeout)); env.put("jmx.remote.x.client.connection.check.period", new Long(Long.MAX_VALUE)); + env.put(RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); final MBeanServer mbs = MBeanServerFactory.newMBeanServer(); diff --git a/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java b/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java index 42a4eb7aad419b9020871a826800176ac1059b57..081d0e5d49a26d44d5341a1f62d801435d587d67 100644 --- a/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java +++ b/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -156,7 +156,8 @@ public class NotificationAccessControllerTest { List received, List expected) { if (received.size() != size) { - echo("Error: expecting " + size + " notifications"); + echo("Error: expecting " + size + " notifications, got " + + received.size()); return 1; } else { for (Notification n : received) { diff --git a/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java b/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java index 17216476939b57a969d69d982e6b9f4cf2f2b3e4..c4988dd03f1959de1cd36c358589bcb94c1b6d5d 100644 --- a/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java +++ b/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ */ import java.net.MalformedURLException; +import java.util.Collections; +import java.util.Map; import javax.management.MBeanServerFactory; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; @@ -44,6 +46,7 @@ import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; public class NotificationBufferCreationTest { private static final MBeanServer mbs = @@ -86,6 +89,8 @@ public class NotificationBufferCreationTest { JMXServiceURL u = null; try { u = new JMXServiceURL(protocol, null, 0); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, "false"); server = JMXConnectorServerFactory.newJMXConnectorServer(u, null, diff --git a/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java b/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java index 3698da49dc99a66159735d302b16a735d0e3de2e..ff3c51661f0affc8c29ec228dbbdf27e3e18acae 100644 --- a/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java +++ b/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java @@ -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 @@ -35,7 +35,9 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.MalformedURLException; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.Vector; import javax.management.*; @@ -88,6 +90,7 @@ import javax.management.remote.*; * If the logic for adding the notification buffer's listener is incorrect * we could remove zero or two notifications from an MBean. */ +import javax.management.remote.rmi.RMIConnectorServer; public class NotificationBufferDeadlockTest { public static void main(String[] args) throws Exception { System.out.println("Check no deadlock if notif sent while initial " + @@ -109,7 +112,13 @@ public class NotificationBufferDeadlockTest { } private static void test(String proto) throws Exception { - System.out.println("Testing protocol " + proto); + test(proto, false); + test(proto, true); + } + + private static void test(String proto, boolean eventService) throws Exception { + System.out.println("Testing protocol " + proto + " with" + + (eventService ? "" : "out") + " event service"); MBeanServer mbs = MBeanServerFactory.newMBeanServer(); ObjectName testName = newName(); DeadlockTest test = new DeadlockTest(); @@ -117,8 +126,11 @@ public class NotificationBufferDeadlockTest { JMXServiceURL url = new JMXServiceURL("service:jmx:" + proto + ":///"); JMXConnectorServer cs; try { + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); cs = - JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); } catch (MalformedURLException e) { System.out.println("...protocol not supported, ignoring"); return; diff --git a/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java b/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java index 1c42043714c43a5fdc7a8758d84cb660e79b947e..0d132a4a0ad009b5bd34b3b14bb23c486535a570 100644 --- a/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java +++ b/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -29,11 +29,16 @@ * @author Luis-Miguel Alventosa * @run clean NotificationEmissionTest * @run build NotificationEmissionTest - * @run main NotificationEmissionTest 1 - * @run main NotificationEmissionTest 2 - * @run main NotificationEmissionTest 3 - * @run main NotificationEmissionTest 4 - * @run main NotificationEmissionTest 5 + * @run main NotificationEmissionTest 1 Classic + * @run main NotificationEmissionTest 2 Classic + * @run main NotificationEmissionTest 3 Classic + * @run main NotificationEmissionTest 4 Classic + * @run main NotificationEmissionTest 5 Classic + * @run main NotificationEmissionTest 1 EventService + * @run main NotificationEmissionTest 2 EventService + * @run main NotificationEmissionTest 3 EventService + * @run main NotificationEmissionTest 4 EventService + * @run main NotificationEmissionTest 5 EventService */ import java.io.File; @@ -56,9 +61,15 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXPrincipal; import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; import javax.security.auth.Subject; public class NotificationEmissionTest { + private final boolean eventService; + + public NotificationEmissionTest(boolean eventService) { + this.eventService = eventService; + } public class CustomJMXAuthenticator implements JMXAuthenticator { public Subject authenticate(Object credentials) { @@ -102,7 +113,8 @@ public class NotificationEmissionTest { List received, List expected) { if (received.size() != size) { - echo("Error: expecting " + size + " notifications"); + echo("Error: expecting " + size + " notifications, got " + + received.size()); return 1; } else { for (Notification n : received) { @@ -216,8 +228,13 @@ public class NotificationEmissionTest { // final Map env = new HashMap(); env.put("jmx.remote.authenticator", new CustomJMXAuthenticator()); - if (prop) + env.put(RMIConnectorServer.EVENT_CLIENT_DELEGATE_FORWARDER, + Boolean.toString(eventService)); + if (prop) { + echo("Setting jmx.remote.x.check.notification.emission to " + + propValue); env.put("jmx.remote.x.check.notification.emission", propValue); + } // Create the JMXServiceURL // @@ -282,9 +299,24 @@ public class NotificationEmissionTest { new Object[] {2, nb3}, new String[] {"int", "javax.management.ObjectName"}); + // If the check is effective and we're using policy.negative, + // then we should see the two notifs sent by nb2 (of which one + // has a getSource() that is nb3), but not the notif sent by nb1. + // Otherwise we should see all three notifs. If we're using the + // Event Service with a Security Manager then the logic to + // reapply the addNL permission test for every notification is + // always enabled, regardless of the value of + // jmx.remote.x.check.notification.emission. Otherwise, the + // test is only applied if that property is explicitly true. + int expectedNotifs = + ((prop || eventService) && sm && !policyPositive) ? 2 : 3; + // Wait for notifications to be emitted // - Thread.sleep(2000); + long deadline = System.currentTimeMillis() + 2000; + while (li.notifs.size() < expectedNotifs && + System.currentTimeMillis() < deadline) + Thread.sleep(1); // Remove notification listener // @@ -297,16 +329,10 @@ public class NotificationEmissionTest { sources.add(nb2); sources.add(nb3); - if (prop && sm && !policyPositive) { - // List must contain two notifs from sources nb2 and nb3 - // - result = checkNotifs(2, li.notifs, sources); - } else { - // List must contain three notifs from sources nb1, nb2 and nb3 - // - result = checkNotifs(3, li.notifs, sources); - } + result = checkNotifs(expectedNotifs, li.notifs, sources); if (result > 0) { + echo("...SecurityManager=" + sm + "; policy=" + policyPositive + + "; eventService=" + eventService); return result; } } finally { @@ -336,9 +362,18 @@ public class NotificationEmissionTest { public static void main(String[] args) throws Exception { echo("\n--- Check the emission of notifications " + - "when a Security Manager is installed ---"); - - NotificationEmissionTest net = new NotificationEmissionTest(); + "when a Security Manager is installed [" + + args[1] + "] ---"); + + boolean eventService; + if (args[1].equals("Classic")) + eventService = false; + else if (args[1].equals("EventService")) + eventService = true; + else + throw new IllegalArgumentException(args[1]); + + NotificationEmissionTest net = new NotificationEmissionTest(eventService); int error = 0; diff --git a/test/javax/management/remote/mandatory/notif/RMINotifTest.java b/test/javax/management/remote/mandatory/notif/RMINotifTest.java index 327274c7a63119aed952a8fb7aa78d490223e87f..140c6cb5be10f881f7628ebf9c1fa961fe99d66a 100644 --- a/test/javax/management/remote/mandatory/notif/RMINotifTest.java +++ b/test/javax/management/remote/mandatory/notif/RMINotifTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,36 +22,53 @@ */ /* - * @test RMINotifTest.java + * @test * @bug 7654321 - * @summary Tests to receive notifications for opened and closed connect -ions + * @summary Tests to receive notifications for opened and closed connections * @author sjiang * @run clean RMINotifTest * @run build RMINotifTest - * @run main RMINotifTest + * @run main RMINotifTest classic + * @run main RMINotifTest event */ // java imports // -import java.io.IOException; -import java.net.UnknownHostException; -import java.rmi.*; -import java.rmi.registry.*; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Collections; +import java.util.Map; import java.util.Random; - -// JMX imports -// -import javax.management.* ; - -import javax.management.remote.*; -import javax.management.remote.rmi.*; +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.NotificationFilterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +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; +import javax.management.remote.rmi.RMIConnectorServer; public class RMINotifTest { public static void main(String[] args) { + String eventService; + if (args[0].equals("classic")) + eventService = "false"; + else if (args[0].equals("event")) + eventService = "true"; + else + throw new IllegalArgumentException(args[0]); + try { // create a rmi registry Registry reg = null; @@ -88,9 +105,10 @@ public class RMINotifTest { "/jndi/rmi://:" + port + "/server" + port); System.out.println("RMIConnectorServer address " + url); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, eventService); JMXConnectorServer sServer = - JMXConnectorServerFactory.newJMXConnectorServer(url, null, - null); + JMXConnectorServerFactory.newJMXConnectorServer(url, env, null); ObjectInstance ss = server.registerMBean(sServer, new ObjectName("Default:name=RmiConnectorServer")); diff --git a/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java b/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java index 0b3aa2be7ad071a2a968602d69ada9de2af6d8dc..3166d3f3726af18213b675950953460c2f2217ba 100644 --- a/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java +++ b/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,68 +32,88 @@ * @run main UnexpectedNotifTest */ -// java imports +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +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.NotificationListener; +import javax.management.ObjectName; +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; // -import java.io.IOException; - -// JMX imports -// -import javax.management.*; -import javax.management.remote.*; +import javax.management.remote.rmi.RMIConnectorServer; public class UnexpectedNotifTest { public static void main(String[] args) throws Exception { - String[] protos = null; + List protos = new ArrayList(); + protos.add("rmi"); try { Class.forName("javax.management.remote.jmxmp.JMXMPConnectorServer"); - protos = new String[2]; - protos[0] = "rmi"; - protos[1] = "jmxmp"; + protos.add("jmxmp"); } catch (ClassNotFoundException e) { - protos = new String[1]; - protos[0] = "rmi"; + // OK: JMXMP not present so don't test it. } - for (int i = 0; i < protos.length; i++) { - System.out.println("Unexpected notifications test for protocol " + - protos[i]); - MBeanServer mbs = null; - try { - // Create a MBeanServer - // - mbs = MBeanServerFactory.createMBeanServer(); - - // Create a NotificationEmitter MBean - // - mbean = new ObjectName ("Default:name=NotificationEmitter"); - mbs.registerMBean(new NotificationEmitter(), mbean); - - // Create a connector server - // - url = new JMXServiceURL("service:jmx:" + protos[i] + "://"); - server = JMXConnectorServerFactory.newJMXConnectorServer(url, - null, - mbs); - - mbs.registerMBean( - server, - new ObjectName("Default:name=ConnectorServer")); - - server.start(); - - url = server.getAddress(); - - for (int j = 0; j < 2; j++) { - test(); - } - } finally { - // Stop server - // - server.stop(); - // Release the MBeanServer - // - MBeanServerFactory.releaseMBeanServer(mbs); + for (String proto : protos) { + test(proto, false); + test(proto, true); + } + } + + private static void test(String proto, boolean eventService) + throws Exception { + System.out.println("Unexpected notifications test for protocol " + + proto + " with" + + (eventService ? "" : "out") + " event service"); + MBeanServer mbs = null; + try { + // Create a MBeanServer + // + mbs = MBeanServerFactory.createMBeanServer(); + + // Create a NotificationEmitter MBean + // + mbean = new ObjectName ("Default:name=NotificationEmitter"); + mbs.registerMBean(new NotificationEmitter(), mbean); + + // Create a connector server + // + url = new JMXServiceURL("service:jmx:" + proto + "://"); + Map env = Collections.singletonMap( + RMIConnectorServer.DELEGATE_TO_EVENT_SERVICE, + Boolean.toString(eventService)); + + server = JMXConnectorServerFactory.newJMXConnectorServer(url, + env, + mbs); + + mbs.registerMBean( + server, + new ObjectName("Default:name=ConnectorServer")); + + server.start(); + + url = server.getAddress(); + + for (int j = 0; j < 2; j++) { + test(); } + } finally { + // Stop server + // + server.stop(); + // Release the MBeanServer + // + MBeanServerFactory.releaseMBeanServer(mbs); } } diff --git a/test/javax/script/E4XErrorTest.java b/test/javax/script/E4XErrorTest.java index 5936fd42eda59cbba866f53539b3defae31d1513..fb9cc9512b9ecf493219e78eb14161ed8a129fe1 100644 --- a/test/javax/script/E4XErrorTest.java +++ b/test/javax/script/E4XErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346734 + * @bug 6346734 6705893 * @summary We do *not* support E4X (ECMAScript for XML) in our * implementation. We want to throw error on XML literals * as early as possible rather than at "runtime" - i.e., when @@ -37,9 +37,10 @@ public class E4XErrorTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } // The test below depends on the error message content diff --git a/test/javax/script/Helper.java b/test/javax/script/Helper.java new file mode 100644 index 0000000000000000000000000000000000000000..8d259cca8a2e8cad0811d4322253c48674850640 --- /dev/null +++ b/test/javax/script/Helper.java @@ -0,0 +1,41 @@ +/* + * 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 javax.script.*; + +/** + * Helper class to consolidate testing requirements for a js engine. + * A js engine is required as part of Sun's product JDK. + */ +public class Helper { + private Helper() {}; // Don't instantiate + + public static ScriptEngine getJsEngine(ScriptEngineManager m) { + ScriptEngine e = m.getEngineByName("js"); + if (e == null && + System.getProperty("java.runtime.name").startsWith("Java(TM)")) { + // A js engine is requied for Sun's product JDK + throw new RuntimeException("no js engine found"); + } + return e; + } +} diff --git a/test/javax/script/JavaScriptScopeTest.java b/test/javax/script/JavaScriptScopeTest.java index 1bce7b6e0fd1cd68d65b825e674d7793f502b450..b6db5a81097b620edb3eaca9db9f71fb4b8a08b3 100644 --- a/test/javax/script/JavaScriptScopeTest.java +++ b/test/javax/script/JavaScriptScopeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346733 + * @bug 6346733 6705893 * @summary Verify that independent Bindings instances don't * get affected by default scope assignments. Also, verify * that script globals can be created and accessed from Java @@ -36,9 +36,10 @@ public class JavaScriptScopeTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval("var v = 'hello';"); // Create a new scope diff --git a/test/javax/script/NullUndefinedVarTest.java b/test/javax/script/NullUndefinedVarTest.java index b07d5afdf756834b7c330cdc3712a9b0f1e8688d..d0067823697e977809f9f8a744e8a0cacdac4c86 100644 --- a/test/javax/script/NullUndefinedVarTest.java +++ b/test/javax/script/NullUndefinedVarTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346732 + * @bug 6346732 6705893 * @summary should be able to assign null and undefined * value to JavaScript global variables. */ @@ -34,9 +34,10 @@ public class NullUndefinedVarTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval("var n = null; " + "if (n !== null) throw 'expecting null';" + diff --git a/test/javax/script/PluggableContextTest.java b/test/javax/script/PluggableContextTest.java index 1e6f4fa52be4cf7306501e3b848e1f44ce667e4f..64f064af8892052ff1ba25fdedc6cc9a74babba9 100644 --- a/test/javax/script/PluggableContextTest.java +++ b/test/javax/script/PluggableContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6398614 + * @bug 6398614 6705893 * @summary Create a user defined ScriptContext and check * that script can access variables from non-standard scopes */ @@ -35,7 +35,11 @@ public class PluggableContextTest { ScriptEngineManager m = new ScriptEngineManager(); ScriptContext ctx = new MyContext(); ctx.setAttribute("x", "hello", MyContext.APP_SCOPE); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } // the following reference to 'x' throws exception // if APP_SCOPE is not searched. e.eval("x", ctx); diff --git a/test/javax/script/ProviderTest.java b/test/javax/script/ProviderTest.java index 79d6f1661e1b3532f9e6bc0879c37ad4ec88995a..0ca9385959d8a788567666a6763d438edd92ef01 100644 --- a/test/javax/script/ProviderTest.java +++ b/test/javax/script/ProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -35,9 +35,10 @@ public class ProviderTest { if (se == null) { throw new RuntimeException("can't locate dummy engine"); } - se = manager.getEngineByName("js"); + se = Helper.getJsEngine(manager); if (se == null) { - throw new RuntimeException("can't locate JavaScript engine"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } } } diff --git a/test/javax/script/RhinoExceptionTest.java b/test/javax/script/RhinoExceptionTest.java index 439b947b2498a9d26eb4054f54c2710889ab3093..d3b58e1465df50e5e5cad6eaa08b7cd4d6f3a86d 100644 --- a/test/javax/script/RhinoExceptionTest.java +++ b/test/javax/script/RhinoExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 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 @@ -23,8 +23,8 @@ /* * @test - * @bug 6474943 - * @summary Test that Rhion exception messages are + * @bug 6474943 6705893 + * @summary Test that Rhino exception messages are * available from ScriptException. */ @@ -36,7 +36,11 @@ public class RhinoExceptionTest { public static void main(String[] args) throws Exception { ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } engine.put("msg", ERROR_MSG); try { engine.eval("throw new Error(msg);"); diff --git a/test/javax/script/Test1.java b/test/javax/script/Test1.java index fdfdef9bc13f27b547551f12f02e7af1c84e45a1..809fd08ed01c52908bb409eeaddd9845c332f2c1 100644 --- a/test/javax/script/Test1.java +++ b/test/javax/script/Test1.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Create JavaScript engine and execute a simple script. * Tests script engine discovery mechanism. */ @@ -35,9 +35,10 @@ public class Test1 { public static void main(String[] args) throws Exception { System.out.println("\nTest1\n"); ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test1.js"))); diff --git a/test/javax/script/Test2.java b/test/javax/script/Test2.java index 0a70eb1b1142fb2ac4d7c64c0aa5a15a45467555..d16a07b9cc6cc87b5acd6ccba89cc418502668fc 100644 --- a/test/javax/script/Test2.java +++ b/test/javax/script/Test2.java @@ -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 @@ -50,7 +50,11 @@ public class Test2 { public static void main(String[] args) throws Exception { System.out.println("\nTest2\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine eng = m.getEngineByName("js"); + ScriptEngine eng = Helper.getJsEngine(m); + if (eng == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } eng.put("Testobj", new Testobj("Hello World")); eng.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test2.js"))); diff --git a/test/javax/script/Test3.java b/test/javax/script/Test3.java index 84b610aaac5e3c8908c02c8c5979e3e41c8ac205..8aa876ba24a34840f9d91552eea61e6d72b2c1ea 100644 --- a/test/javax/script/Test3.java +++ b/test/javax/script/Test3.java @@ -1,9 +1,10 @@ /* - * 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 * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT @@ -23,7 +24,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test engine and global scopes */ @@ -37,7 +38,11 @@ public class Test3 { final Reader reader = new FileReader( new File(System.getProperty("test.src", "."), "Test3.js")); ScriptEngineManager m = new ScriptEngineManager(); - final ScriptEngine engine = m.getEngineByName("js"); + final ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Bindings en = new SimpleBindings(); engine.setBindings(en, ScriptContext.ENGINE_SCOPE); en.put("key", "engine value"); diff --git a/test/javax/script/Test4.java b/test/javax/script/Test4.java index bae255097967c69595847768f8bdcfc125f7ca03..e79d2f2f4fa7891bc02488314e9ff1da1bd01f18 100644 --- a/test/javax/script/Test4.java +++ b/test/javax/script/Test4.java @@ -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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test script functions implementing Java interface */ @@ -34,7 +34,11 @@ public class Test4 { public static void main(String[] args) throws Exception { System.out.println("\nTest4\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } e.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test4.js"))); Invocable inv = (Invocable)e; diff --git a/test/javax/script/Test5.java b/test/javax/script/Test5.java index cf32cff3e8e43366bb67fd5295f5a508f73062ce..702c81c258b012ec1f5b066684d416b247575fb1 100644 --- a/test/javax/script/Test5.java +++ b/test/javax/script/Test5.java @@ -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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Tests engine, global scopes and scope hiding. */ @@ -34,7 +34,11 @@ public class Test5 { public static void main(String[] args) throws Exception { System.out.println("\nTest5\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Bindings g = new SimpleBindings(); Bindings e = new SimpleBindings(); g.put("key", "value in global"); diff --git a/test/javax/script/Test6.java b/test/javax/script/Test6.java index 15bbda1e0b35c2b150b5154178b3ab0fc9d74495..cf44c0e6a7039fba2c0d3a8d9c2c676675ff4673 100644 --- a/test/javax/script/Test6.java +++ b/test/javax/script/Test6.java @@ -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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test basic script compilation. Value eval'ed from * compiled and interpreted scripts should be same. */ @@ -35,7 +35,11 @@ public class Test6 { public static void main(String[] args) throws Exception { System.out.println("\nTest6\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Reader reader = new FileReader( new File(System.getProperty("test.src", "."), "Test6.js")); engine.eval(reader); diff --git a/test/javax/script/Test7.java b/test/javax/script/Test7.java index 9cdd8ac3e21ff64116db92531f62bf798ee31c72..681661b316553bd2b4e79cc54df5328e7603ec7e 100644 --- a/test/javax/script/Test7.java +++ b/test/javax/script/Test7.java @@ -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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Tests importPackage and java access in script */ @@ -37,7 +37,11 @@ public class Test7 { new File(System.getProperty("test.src", "."), "Test7.js"); Reader r = new FileReader(file); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine eng = m.getEngineByName("js"); + ScriptEngine eng = Helper.getJsEngine(m); + if (eng == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } eng.put("filename", file.getAbsolutePath()); eng.eval(r); String str = (String)eng.get("firstLine"); diff --git a/test/javax/script/Test8.java b/test/javax/script/Test8.java index 80f0a6afdeaef9dbf7b2d07ceeeebd2dee11fc33..3041bc7c1fcdec0fcb8509bca8744c008afbae57 100644 --- a/test/javax/script/Test8.java +++ b/test/javax/script/Test8.java @@ -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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test invoking script function or method from Java */ @@ -34,7 +34,11 @@ public class Test8 { public static void main(String[] args) throws Exception { System.out.println("\nTest8\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } e.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test8.js"))); Invocable inv = (Invocable)e; diff --git a/test/javax/script/VersionTest.java b/test/javax/script/VersionTest.java index b4fc2fc7633d27300ad9703272eaa4dd29914cf0..c7845db189a15821c6a2dc8f9113ccd73c296981 100644 --- a/test/javax/script/VersionTest.java +++ b/test/javax/script/VersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346729 + * @bug 6346729 6705893 * @summary Create JavaScript engine and check language and engine version */ @@ -37,9 +37,10 @@ public class VersionTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } String langVersion = jsengine.getFactory().getLanguageVersion(); if (! langVersion.equals(JS_LANG_VERSION)) { diff --git a/test/sun/nio/cs/CheckICNE.java b/test/sun/nio/cs/CheckICNE.java new file mode 100644 index 0000000000000000000000000000000000000000..4b3e905f1d0c7deb59805222493e5f2e36da950e --- /dev/null +++ b/test/sun/nio/cs/CheckICNE.java @@ -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 --git a/test/sun/nio/cs/TestUTF8.java b/test/sun/nio/cs/TestUTF8.java new file mode 100644 index 0000000000000000000000000000000000000000..967054573a0fe31e175111434d214de139eb7743 --- /dev/null +++ b/test/sun/nio/cs/TestUTF8.java @@ -0,0 +1,393 @@ +/* + * 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 4486841 + * @summary Test UTF-8 charset + */ + +import java.nio.charset.*; +import java.nio.*; +import java.util.*; + +public class TestUTF8 { + static char[] decode(byte[] bb, String csn, boolean testDirect) + throws Exception { + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + ByteBuffer bbf; + CharBuffer cbf; + if (testDirect) { + bbf = ByteBuffer.allocateDirect(bb.length); + cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); + bbf.put(bb).flip(); + } else { + bbf = ByteBuffer.wrap(bb); + cbf = CharBuffer.allocate(bb.length); + } + CoderResult cr = dec.decode(bbf, cbf, true); + if (cr != CoderResult.UNDERFLOW) + throw new RuntimeException("Decoding err: " + csn); + char[] cc = new char[cbf.position()]; + cbf.flip(); cbf.get(cc); + return cc; + + } + + static CoderResult decodeCR(byte[] bb, String csn, boolean testDirect) + throws Exception { + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + ByteBuffer bbf; + CharBuffer cbf; + if (testDirect) { + bbf = ByteBuffer.allocateDirect(bb.length); + cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); + bbf.put(bb).flip(); + } else { + bbf = ByteBuffer.wrap(bb); + cbf = CharBuffer.allocate(bb.length); + } + return dec.decode(bbf, cbf, true); + } + + static byte[] encode(char[] cc, String csn, boolean testDirect) + throws Exception { + ByteBuffer bbf; + CharBuffer cbf; + CharsetEncoder enc = Charset.forName(csn).newEncoder(); + if (testDirect) { + bbf = ByteBuffer.allocateDirect(cc.length * 4); + cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); + cbf.put(cc).flip(); + } else { + bbf = ByteBuffer.allocate(cc.length * 4); + cbf = CharBuffer.wrap(cc); + } + + CoderResult cr = enc.encode(cbf, bbf, true); + if (cr != CoderResult.UNDERFLOW) + throw new RuntimeException("Encoding err: " + csn); + byte[] bb = new byte[bbf.position()]; + bbf.flip(); bbf.get(bb); + return bb; + } + + static CoderResult encodeCR(char[] cc, String csn, boolean testDirect) + throws Exception { + ByteBuffer bbf; + CharBuffer cbf; + CharsetEncoder enc = Charset.forName(csn).newEncoder(); + if (testDirect) { + bbf = ByteBuffer.allocateDirect(cc.length * 4); + cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); + cbf.put(cc).flip(); + } else { + bbf = ByteBuffer.allocate(cc.length * 4); + cbf = CharBuffer.wrap(cc); + } + return enc.encode(cbf, bbf, true); + } + + static char[] getUTFChars() { + char[] cc = new char[0x10000 - 0xe000 + 0xd800 + //bmp + (0x110000 - 0x10000) * 2]; //supp + int pos = 0; + int i = 0; + for (i = 0; i < 0xd800; i++) + cc[pos++] = (char)i; + for (i = 0xe000; i < 0x10000; i++) + cc[pos++] = (char)i; + for (i = 0x10000; i < 0x110000; i++) { + pos += Character.toChars(i, cc, pos); + } + return cc; + } + + static int to3ByteUTF8(char c, byte[] bb, int pos) { + bb[pos++] = (byte)(0xe0 | ((c >> 12))); + bb[pos++] = (byte)(0x80 | ((c >> 06) & 0x3f)); + bb[pos++] = (byte)(0x80 | ((c >> 00) & 0x3f)); + return 3; + } + + static void checkRoundtrip(String csn) throws Exception { + System.out.printf(" Check roundtrip <%s>...", csn); + char[] cc = getUTFChars(); + byte[] bb = encode(cc, csn, false); + char[] ccO = decode(bb, csn, false); + + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" non-direct failed"); + } + bb = encode(cc, csn, true); + ccO = decode(bb, csn, true); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" (direct) failed"); + } + System.out.println(); + } + + static void check6ByteSurrs(String csn) throws Exception { + System.out.printf(" Check 6-byte Surrogates <%s>...%n", csn); + byte[] bb = new byte[(0x110000 - 0x10000) * 6]; + char[] cc = new char[(0x110000 - 0x10000) * 2]; + int bpos = 0; + int cpos = 0; + for (int i = 0x10000; i < 0x110000; i++) { + Character.toChars(i, cc, cpos); + bpos += to3ByteUTF8(cc[cpos], bb, bpos); + bpos += to3ByteUTF8(cc[cpos + 1], bb, bpos); + cpos += 2; + } + + char[] ccO = decode(bb, csn, false); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding failed%n"); + } + ccO = decode(bb, csn, true); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding(direct) failed%n"); + } + } + + static void compare(String csn1, String csn2) throws Exception { + System.out.printf(" Diff <%s> <%s>...%n", csn1, csn2); + char[] cc = getUTFChars(); + + byte[] bb1 = encode(cc, csn1, false); + byte[] bb2 = encode(cc, csn2, false); + if (!Arrays.equals(bb1, bb2)) + System.out.printf(" encoding failed%n"); + char[] cc1 = decode(bb1, csn1, false); + char[] cc2 = decode(bb1, csn2, false); + if (!Arrays.equals(cc1, cc2)) { + System.out.printf(" decoding failed%n"); + } + + bb1 = encode(cc, csn1, true); + bb2 = encode(cc, csn2, true); + if (!Arrays.equals(bb1, bb2)) + System.out.printf(" encoding (direct) failed%n"); + cc1 = decode(bb1, csn1, true); + cc2 = decode(bb1, csn2, true); + if (!Arrays.equals(cc1, cc2)) { + System.out.printf(" decoding (direct) failed%n"); + } + } + + // The first byte is the length of malformed bytes + static byte[][] malformed = { + // One-byte sequences: + {1, (byte)0xFF }, + {1, (byte)0xC0 }, + {1, (byte)0x80 }, + + {1, (byte)0xFF, (byte)0xFF}, // all ones + {1, (byte)0xA0, (byte)0x80}, // 101x first byte first nibble + + // Two-byte sequences: + {1, (byte)0xC0, (byte)0x80}, // invalid first byte + {1, (byte)0xC1, (byte)0xBF}, // invalid first byte + {1, (byte)0xC2, (byte)0x00}, // invalid second byte + {1, (byte)0xC2, (byte)0xC0}, // invalid second byte + {1, (byte)0xD0, (byte)0x00}, // invalid second byte + {1, (byte)0xD0, (byte)0xC0}, // invalid second byte + {1, (byte)0xDF, (byte)0x00}, // invalid second byte + {1, (byte)0xDF, (byte)0xC0}, // invalid second byte + + // Three-byte sequences + {1, (byte)0xE0, (byte)0x80, (byte)0x80}, // 111x first byte first nibble + {1, (byte)0xE0, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xE0, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xE0, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xE0, (byte)0xC0, (byte)0xBF }, // invalid second byte + {2, (byte)0xE0, (byte)0xA0, (byte)0x7F }, // invalid third byte + {2, (byte)0xE0, (byte)0xA0, (byte)0xC0 }, // invalid third byte + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte + {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte + + // Four-byte sequences + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid second byte + {1, (byte)0xF0, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {2, (byte)0xF0, (byte)0x90, (byte)0xC0, (byte)0x80 }, // invalid third byte + {3, (byte)0xF0, (byte)0x90, (byte)0x80, (byte)0xC0 }, // invalid third byte + + {1, (byte)0xF1, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {2, (byte)0xF1, (byte)0x80, (byte)0xC0, (byte)0x80 }, // invalid third byte + {3, (byte)0xF1, (byte)0x80, (byte)0x80, (byte)0xC0 }, // invalid forth byte + {1, (byte)0xF4, (byte)0x90, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF4, (byte)0xC0, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + + // Five-byte sequences + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80}, + {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80 }, + {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF }, + {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0 }, + + // Six-byte sequences + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, + {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80 }, + {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF, (byte)0x80 }, + {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0, (byte)0x80 }, + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, + }; + + static void checkMalformed(String csn) throws Exception { + boolean failed = false; + System.out.printf(" Check malformed <%s>...%n", csn); + for (boolean direct: new boolean[] {false, true}) { + for (byte[] bins : malformed) { + int mlen = bins[0]; + byte[] bin = Arrays.copyOfRange(bins, 1, bins.length); + CoderResult cr = decodeCR(bin, csn, direct); + String ashex = ""; + for (int i = 0; i < bin.length; i++) { + if (i > 0) ashex += " "; + ashex += Integer.toBinaryString((int)bin[i] & 0xff); + } + if (!cr.isMalformed()) { + System.out.printf(" FAIL(direct=%b): [%s] not malformed.\n", direct, ashex); + failed = true; + } else if (cr.length() != mlen) { + System.out.printf(" FAIL(direct=%b): [%s] malformed[len=%d].\n", direct, ashex, cr.length()); + failed = true; + } + } + } + if (failed) + throw new RuntimeException("Check malformed failed " + csn); + } + + static boolean check(CharsetDecoder dec, byte[] utf8s, boolean direct, int[] flow) { + int inPos = flow[0]; + int inLen = flow[1]; + int outPos = flow[2]; + int outLen = flow[3]; + int expedInPos = flow[4]; + int expedOutPos = flow[5]; + CoderResult expedCR = (flow[6]==0)?CoderResult.UNDERFLOW + :CoderResult.OVERFLOW; + ByteBuffer bbf; + CharBuffer cbf; + if (direct) { + bbf = ByteBuffer.allocateDirect(inPos + utf8s.length); + cbf = ByteBuffer.allocateDirect((outPos + outLen)*2).asCharBuffer(); + } else { + bbf = ByteBuffer.allocate(inPos + utf8s.length); + cbf = CharBuffer.allocate(outPos + outLen); + } + bbf.position(inPos); + bbf.put(utf8s).flip().position(inPos).limit(inPos + inLen); + cbf.position(outPos); + dec.reset(); + CoderResult cr = dec.decode(bbf, cbf, false); + if (cr != expedCR || + bbf.position() != expedInPos || + cbf.position() != expedOutPos) { + System.out.printf("Expected(direct=%5b): [", direct); + for (int i:flow) System.out.print(" " + i); + System.out.println("] CR=" + cr + + ", inPos=" + bbf.position() + + ", outPos=" + cbf.position()); + return false; + } + return true; + } + + static void checkUnderOverflow(String csn) throws Exception { + System.out.printf(" Check under/overflow <%s>...%n", csn); + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + boolean failed = false; + byte[] utf8s = new String("\u007f\u07ff\ue000\ud800\udc00").getBytes("UTF-8"); + int inlen = utf8s.length; + + for (int inoff = 0; inoff < 20; inoff++) { + for (int outoff = 0; outoff < 20; outoff++) { + int[][] Flows = { + //inpos, inLen, outPos, outLen, inPosEP, outposEP, under(0)/over(1) + {inoff, inlen, outoff, 1, inoff + 1, outoff + 1, 1}, + {inoff, inlen, outoff, 2, inoff + 3, outoff + 2, 1}, + {inoff, inlen, outoff, 3, inoff + 6, outoff + 3, 1}, + {inoff, inlen, outoff, 4, inoff + 6, outoff + 3, 1}, + {inoff, inlen, outoff, 5, inoff + 10,outoff + 5, 0}, + // underflow + {inoff, 1, outoff, 5, inoff + 1, outoff + 1, 0}, + {inoff, 2, outoff, 5, inoff + 1, outoff + 1, 0}, + {inoff, 3, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 4, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 5, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 6, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 7, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 8, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 9, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 10, outoff, 5, inoff + 10,outoff + 5, 0}, + // 2-byte underflow/overflow + {inoff, 2, outoff, 1, inoff + 1, outoff + 1, 0}, + {inoff, 3, outoff, 1, inoff + 1, outoff + 1, 1}, + // 3-byte underflow/overflow + {inoff, 4, outoff, 2, inoff + 3, outoff + 2, 0}, + {inoff, 5, outoff, 2, inoff + 3, outoff + 2, 0}, + {inoff, 6, outoff, 2, inoff + 3, outoff + 2, 1}, + // 4-byte underflow/overflow + {inoff, 7, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 8, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 9, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 10, outoff, 4, inoff + 6, outoff + 3, 1}, + }; + for (boolean direct: new boolean[] {false, true}) { + for (int[] flow: Flows) { + if (!check(dec, utf8s, direct, flow)) + failed = true; + } + }}} + if (failed) + throw new RuntimeException("Check under/overflow failed " + csn); + } + + public static void main(String[] args) throws Exception { + checkRoundtrip("UTF-8"); + check6ByteSurrs("UTF-8"); + //compare("UTF-8", "UTF-8-OLD"); + checkMalformed("UTF-8"); + checkUnderOverflow("UTF-8"); + } +} diff --git a/src/solaris/native/sun/awt/awt_TextField.h b/test/sun/security/util/DerValue/Indefinite.java similarity index 58% rename from src/solaris/native/sun/awt/awt_TextField.h rename to test/sun/security/util/DerValue/Indefinite.java index 1566ef79111d5f795d41e7503b43a24745f4c2df..e6ba2f067d53322fe6c45b6cb106f265c688dd24 100644 --- a/src/solaris/native/sun/awt/awt_TextField.h +++ b/test/sun/security/util/DerValue/Indefinite.java @@ -1,12 +1,10 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * 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. + * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -23,14 +21,24 @@ * have any questions. */ -#include "jni_util.h" +/* + * @test + * @bug 6731685 + * @summary CertificateFactory.generateCertificates throws IOException on PKCS7 cert chain + */ + +import java.io.*; +import sun.security.util.*; -/* fieldIDs for TextField fields that may be accessed from C */ -static struct TextFieldIDs { - jfieldID echoChar; -}; +public class Indefinite { -/* fieldIDs for MTextFieldPeer fields that may be accessed from C */ -struct MTextFieldPeerIDs { - jfieldID firstChangeSkipped; -}; + public static void main(String[] args) throws Exception { + byte[] input = { + // An OCTET-STRING in 2 parts + 4, (byte)0x80, 4, 2, 'a', 'b', 4, 2, 'c', 'd', 0, 0, + // Garbage follows, may be falsely recognized as EOC + 0, 0, 0, 0 + }; + new DerValue(new ByteArrayInputStream(input)); + } +} diff --git a/test/sun/tools/jrunscript/CheckEngine.java b/test/sun/tools/jrunscript/CheckEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..5301fc4fb75971ac370e228245e3d4be13aedf55 --- /dev/null +++ b/test/sun/tools/jrunscript/CheckEngine.java @@ -0,0 +1,45 @@ +/* + * 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 javax.script.*; + +/* + * If the JDK being tested is not a Sun product JDK and a js + * engine is not present, return an exit code of 2 to indicate that + * the jrunscript tests which assume a js engine can be vacuously + * passed. + */ +public class CheckEngine { + public static void main(String... args) { + int exitCode = 0; + ScriptEngine engine = + (new ScriptEngineManager()).getEngineByName("js"); + + if (engine == null && + !(System.getProperty("java.runtime.name").startsWith("Java(TM)"))) { + exitCode = 2; + } + + System.exit(exitCode); + } +} diff --git a/test/sun/tools/jrunscript/common.sh b/test/sun/tools/jrunscript/common.sh index cfb6b0137c7edb20f7f7a7788b0d709dc46d6f29..0472d5c99449d39569b89edbd4773e0bab941190 100644 --- a/test/sun/tools/jrunscript/common.sh +++ b/test/sun/tools/jrunscript/common.sh @@ -1,5 +1,5 @@ # -# Copyright 2005 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 @@ -52,4 +52,5 @@ setup() { JRUNSCRIPT="${TESTJAVA}/bin/jrunscript" JAVAC="${TESTJAVA}/bin/javac" + JAVA="${TESTJAVA}/bin/java" } diff --git a/test/sun/tools/jrunscript/jrunscript-DTest.sh b/test/sun/tools/jrunscript/jrunscript-DTest.sh index 448d4c616be88d1d645794cb45af6ce1ac3a235a..8e6c52f19fa6f78d2118c2c3ec829775e4977236 100644 --- a/test/sun/tools/jrunscript/jrunscript-DTest.sh +++ b/test/sun/tools/jrunscript/jrunscript-DTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-DTest.sh # @summary Test that output of 'jrunscript -D' . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi # test whether value specifieD by -D option is passed # to script as java.lang.System property. sysProps is diff --git a/test/sun/tools/jrunscript/jrunscript-argsTest.sh b/test/sun/tools/jrunscript/jrunscript-argsTest.sh index cdced76c8768066f6944e96588973c60d6eef2da..72567cde544b88c83f455082ed646e627fce0606 100644 --- a/test/sun/tools/jrunscript/jrunscript-argsTest.sh +++ b/test/sun/tools/jrunscript/jrunscript-argsTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-argsTest.sh # @summary Test passing of script arguments from command line . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi # we check whether "excess" args are passed as script arguments diff --git a/test/sun/tools/jrunscript/jrunscript-cpTest.sh b/test/sun/tools/jrunscript/jrunscript-cpTest.sh index 599234db8b20b24c9a797719e811932d893825d9..aa5a52c9230f9cfa11ab5fb4a0023ea722fbfd58 100644 --- a/test/sun/tools/jrunscript/jrunscript-cpTest.sh +++ b/test/sun/tools/jrunscript/jrunscript-cpTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-cpTest.sh # @summary Test -cp option to set classpath . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f Hello.class ${JAVAC} ${TESTSRC}/Hello.java -d . diff --git a/test/sun/tools/jrunscript/jrunscript-eTest.sh b/test/sun/tools/jrunscript/jrunscript-eTest.sh index fb67830cf6f607730d4705132fe78eff86b89f18..677f4f9663daaee00ad2174ce68f58b0e65ca8e1 100644 --- a/test/sun/tools/jrunscript/jrunscript-eTest.sh +++ b/test/sun/tools/jrunscript/jrunscript-eTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-eTest.sh # @summary Test that output of 'jrunscript -e' matches the dash-e.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscript-eTest.out 2>/dev/null ${JRUNSCRIPT} -e "println('hello')" > jrunscript-eTest.out 2>&1 diff --git a/test/sun/tools/jrunscript/jrunscript-fTest.sh b/test/sun/tools/jrunscript/jrunscript-fTest.sh index a5eb5c7d2e1d77b997dcc2fdb710160479732b69..ad263ffcd5c9c9da31d07a1c813a9353f0a2e17d 100644 --- a/test/sun/tools/jrunscript/jrunscript-fTest.sh +++ b/test/sun/tools/jrunscript/jrunscript-fTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright 2005 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-fTest.sh # @summary Test that output of 'jrunscript -f' matches the dash-f.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscript-fTest.out 2>/dev/null ${JRUNSCRIPT} -f ${TESTSRC}/hello.js > jrunscript-fTest.out 2>&1 diff --git a/test/sun/tools/jrunscript/jrunscriptTest.sh b/test/sun/tools/jrunscript/jrunscriptTest.sh index 0e17b771cf54b17fb8e9d8f9bdbed46b8e7f6397..cbc9e26f12f57cc357dd55783a52b9cf723f9b6d 100644 --- a/test/sun/tools/jrunscript/jrunscriptTest.sh +++ b/test/sun/tools/jrunscript/jrunscriptTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# 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 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscriptTest.sh # @summary Test that output of 'jrunscript' interactive matches the repl.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscriptTest.out 2>/dev/null ${JRUNSCRIPT} > jrunscriptTest.out 2>&1 <