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/Makefile b/make/com/sun/Makefile index 0328f120d31d952af6cd878ec4121fe4283ff415..188e73670ad8ce715ee9e2921c168eaa1b884b30 100644 --- a/make/com/sun/Makefile +++ b/make/com/sun/Makefile @@ -41,7 +41,7 @@ endif # Omit mirror since it's built with the apt tool. SUBDIRS = $(SCRIPT_SUBDIR) image security crypto/provider jndi jmx \ java inputmethods org xml rowset net/httpserver net/ssl demo \ - tools jarsigner tracing + tools jarsigner tracing servicetag all build clean clobber:: $(SUBDIRS-loop) 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/com/sun/servicetag/Makefile b/make/com/sun/servicetag/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e7914e8278ee2d1f764297105edfd1d691b64fb2 --- /dev/null +++ b/make/com/sun/servicetag/Makefile @@ -0,0 +1,80 @@ +# 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. + +BUILDDIR = ../../.. +PACKAGE = com.sun.servicetag +PRODUCT = sun +include $(BUILDDIR)/common/Defs.gmk + +# +# Files to compile +# +AUTO_FILES_JAVA_DIRS = com/sun/servicetag + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +SERVICETAG_LIBDIR = $(LIBDIR)/servicetag +SERVICETAG_RESOURCES_DIR = $(CLASSDESTDIR)/com/sun/servicetag/resources +FILES_copy = $(SERVICETAG_RESOURCES_DIR)/product_registration.xsd \ + $(SERVICETAG_RESOURCES_DIR)/register.html \ + $(SERVICETAG_RESOURCES_DIR)/register_ja.html \ + $(SERVICETAG_RESOURCES_DIR)/register_zh_CN.html \ + $(SERVICETAG_LIBDIR)/jdk_header.png + +# Add all properties files to the FILES_copy list +SWORDFISH_properties := $(shell \ + $(CD) $(SHARE_SRC)/classes/com/sun/servicetag/resources; \ + $(FIND) . -name 'javase_*_swordfish.properties' -print ; \ + ) +FILES_copy += $(shell \ + for f in $(SWORDFISH_properties) ; do \ + echo $(SERVICETAG_RESOURCES_DIR)/$$f ; \ + done \ +) + + +# +#OTHER_JAVACFLAGS += -Xlint:unchecked + +build: install-servicetag-lib copy-files + +copy-files: $(FILES_copy) + +$(CLASSBINDIR)/%: $(SHARE_SRC)/classes/% + $(install-file) + +$(SERVICETAG_LIBDIR)/jdk_header.png: $(SHARE_SRC)/classes/com/sun/servicetag/resources/jdk_header.png + $(install-file) + $(CHMOD) 444 $@ + +install-servicetag-lib: + @$(RM) -rf $(SERVICETAG_LIBDIR) + $(MKDIR) $(SERVICETAG_LIBDIR) + +clean clobber:: + @$(RM) $(FILES_copy) + +.PHONY: copy-files 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 b4a07fc352f3ec59bef6222693f542b5d7942110..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 @@ -209,6 +209,7 @@ JAVA_JAVA_java = \ sun/util/TimeZoneNameUtility.java \ sun/util/calendar/ZoneInfo.java \ sun/util/calendar/ZoneInfoFile.java \ + sun/util/calendar/TzIDOldMapping.java \ java/util/TooManyListenersException.java \ java/util/Comparator.java \ java/util/Collections.java \ @@ -449,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/Makefile b/make/javax/swing/Makefile index c2056a45ce2f87bf172cebe377cb982f6c4419e7..e112e609cd9ac46c277efdc0901033cfd0263c4b 100644 --- a/make/javax/swing/Makefile +++ b/make/javax/swing/Makefile @@ -33,7 +33,7 @@ include $(BUILDDIR)/common/Defs.gmk # Files # include FILES.gmk -AUTO_FILES_JAVA_DIRS = javax/swing sun/swing +AUTO_FILES_JAVA_DIRS = javax/swing sun/swing com/sun/java/swing AUTO_JAVA_PRUNE = plaf SUBDIRS = html32dtd plaf 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/make/mksample/nio/multicast/Makefile b/make/mksample/nio/multicast/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..179d3d4a97c5895c7b05b0f2147aaf2f80b8ac49 --- /dev/null +++ b/make/mksample/nio/multicast/Makefile @@ -0,0 +1,52 @@ +# +# 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. +# + +# +# Makefile for the nio/multicast sample code +# + +BUILDDIR = ../../.. + +PRODUCT = java + +include $(BUILDDIR)/common/Defs.gmk + +SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/multicast +SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/multicast + +SAMPLE_FILES = \ + $(SAMPLE_DST_DIR)/Reader.java \ + $(SAMPLE_DST_DIR)/Sender.java \ + $(SAMPLE_DST_DIR)/MulticastAddress.java + +all build: $(SAMPLE_FILES) + +$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/% + $(install-file) + +clean clobber: + $(RM) -r $(SAMPLE_DST_DIR) + +.PHONY: all build clean clobber diff --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/Makefile b/make/sun/awt/Makefile index 2754dd75ec38a3300b179283b9ae422a7eb44a38..a3dfce97a5792de6ff4feae63910c59eef397d88 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/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/javazic/tzdata/VERSION b/make/sun/javazic/tzdata/VERSION index 95ed6ee539e02b38c892de5e0f69075373695cd1..2f4f9df808f9ecf42657178a698fc0607789dd38 100644 --- a/make/sun/javazic/tzdata/VERSION +++ b/make/sun/javazic/tzdata/VERSION @@ -21,4 +21,4 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # -tzdata2007h +tzdata2008e diff --git a/make/sun/javazic/tzdata/africa b/make/sun/javazic/tzdata/africa index f1f4b5f1b7afc839efc1e319c681cf204c607b9c..8141f080997cfa5bbd68f08ddf70bcb751683834 100644 --- a/make/sun/javazic/tzdata/africa +++ b/make/sun/javazic/tzdata/africa @@ -409,9 +409,63 @@ Zone Africa/Nouakchott -1:03:48 - LMT 1912 0:00 - GMT # Mauritius + +# From Steffen Thorsen (2008-06-25): +# Mauritius plans to observe DST from 2008-11-01 to 2009-03-31 on a trial +# basis.... +# It seems that Mauritius observed daylight saving time from 1982-10-10 to +# 1983-03-20 as well, but that was not successful.... +# http://www.timeanddate.com/news/time/mauritius-daylight-saving-time.html + +# From Alex Krivenyshev (2008-06-25): +# http://economicdevelopment.gov.mu/portal/site/Mainhomepage/menuitem.a42b24128104d9845dabddd154508a0c/?content_id=0a7cee8b5d69a110VgnVCM1000000a04a8c0RCRD + +# From Arthur David Olson (2008-06-30): +# The www.timeanddate.com article cited by Steffen Thorsen notes that "A +# final decision has yet to be made on the times that daylight saving +# would begin and end on these dates." As a place holder, use midnight. + +# From Paul Eggert (2008-06-30): +# Follow Thorsen on DST in 1982/1983, instead of Shanks & Pottenger. + +# From Steffen Thorsen (2008-07-10): +# According to +# +# http://www.lexpress.mu/display_article.php?news_id=111216 +# +# (in French), Mauritius will start and end their DST a few days earlier +# than previously announced (2008-11-01 to 2009-03-31). The new start +# date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time +# given, but it is probably at either 2 or 3 wall clock time). +# +# A little strange though, since the article says that they moved the date +# to align itself with Europe and USA which also change time on that date, +# but that means they have not paid attention to what happened in +# USA/Canada last year (DST ends first Sunday in November). I also wonder +# why that they end on a Friday, instead of aligning with Europe which +# changes two days later. + +# From Alex Krivenyshev (2008-07-11): +# Seems that English language article "The revival of daylight saving +# time: Energy conservation?"-# No. 16578 (07/11/2008) was originally +# published on Monday, June 30, 2008... +# +# I guess that article in French "Le gouvernement avance l'introduction +# de l'heure d'ete" stating that DST in Mauritius starting on October 26 +# and ending on March 27, 2009 is the most recent one. +# ... +# +# http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html +# + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule Mauritius 1982 only - Oct 10 0:00 1:00 S +Rule Mauritius 1983 only - Mar 21 0:00 0 - +Rule Mauritius 2008 only - Oct 26 2:00s 1:00 S +Rule Mauritius 2009 only - Mar 27 2:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis - 4:00 - MUT # Mauritius Time + 4:00 Mauritius MU%sT # Mauritius Time # Agalega Is, Rodriguez # no information; probably like Indian/Mauritius @@ -422,6 +476,77 @@ Zone Indian/Mayotte 3:00:56 - LMT 1911 Jul # Mamoutzou # Morocco # See the `europe' file for Spanish Morocco (Africa/Ceuta). + +# From Alex Krivenyshev (2008-05-09): +# Here is an article that Morocco plan to introduce Daylight Saving Time between +# 1 June, 2008 and 27 September, 2008. +# +# "... Morocco is to save energy by adjusting its clock during summer so it will +# be one hour ahead of GMT between 1 June and 27 September, according to +# Communication Minister and Gov ernment Spokesman, Khalid Naciri...." +# +# +# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html +# +# OR +# +# http://en.afrik.com/news11892.html +# + +# From Alex Krivenyshev (2008-05-09): +# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse: +# +# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view +# +# +# Morocco shifts to daylight time on June 1st through September 27, Govt. +# spokesman. + +# From Patrice Scattolin (2008-05-09): +# According to this article: +# +# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html +# +# (and republished here: +# +# http://www.actu.ma/heure-dete-comment_i127896_0.html +# +# ) +# the changes occurs at midnight: +# +# saturday night may 31st at midnight (which in french is to be +# intrepreted as the night between saturday and sunday) +# sunday night the 28th at midnight +# +# Seeing that the 28th is monday, I am guessing that she intends to say +# the midnight of the 28th which is the midnight between sunday and +# monday, which jives with other sources that say that it's inclusive +# june1st to sept 27th. +# +# The decision was taken by decree *2-08-224 *but I can't find the decree +# published on the web. +# +# It's also confirmed here: +# +# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm +# +# on a government portal as being between june 1st and sept 27th (not yet +# posted in english). +# +# The following google query will generate many relevant hits: +# +# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search +# + +# From Alex Krivenyshev (2008-05-09): +# Is Western Sahara (part which administrated by Morocco) going to follow +# Morocco DST changes? Any information? What about other part of +# Western Sahara - under administration of POLISARIO Front (also named +# SADR Saharawi Arab Democratic Republic)? + +# From Arthur David Olson (2008-05-09): +# XXX--guess that it is only Morocco for now; guess only 2008 for now. + # RULE NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Morocco 1939 only - Sep 12 0:00 1:00 S Rule Morocco 1939 only - Nov 19 0:00 0 - @@ -438,11 +563,13 @@ Rule Morocco 1976 only - Aug 1 0:00 0 - Rule Morocco 1977 only - Sep 28 0:00 0 - Rule Morocco 1978 only - Jun 1 0:00 1:00 S Rule Morocco 1978 only - Aug 4 0:00 0 - +Rule Morocco 2008 only - Jun 1 0:00 1:00 S +Rule Morocco 2008 only - Sep 28 0:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26 0:00 Morocco WE%sT 1984 Mar 16 1:00 - CET 1986 - 0:00 - WET + 0:00 Morocco WE%sT # Western Sahara Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan -1:00 - WAT 1976 Apr 14 diff --git a/make/sun/javazic/tzdata/asia b/make/sun/javazic/tzdata/asia index bec343b7796f80fcef3897de3184136327960c1b..be5819700017a26ffc9ac4048fab989b4b634489 100644 --- a/make/sun/javazic/tzdata/asia +++ b/make/sun/javazic/tzdata/asia @@ -251,6 +251,28 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # (could be true), for the moment I am assuming that those two # counties are mistakes in the astro.com data. +# From Paul Eggert (2008-02-11): +# I just now checked Google News for western news sources that talk +# about China's single time zone, and couldn't find anything before 1986 +# talking about China being in one time zone. (That article was: Jim +# Mann, "A clumsy embrace for another western custom: China on daylight +# time--sort of", Los Angeles Times, 1986-05-05. By the way, this +# article confirms the tz database's data claiming that China began +# observing daylight saving time in 1986. +# +# From Thomas S. Mullaney (2008-02-11): +# I think you're combining two subjects that need to treated +# separately: daylight savings (which, you're correct, wasn't +# implemented until the 1980s) and the unified time zone centered near +# Beijing (which was implemented in 1949). Briefly, there was also a +# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was +# ceased, and the second eventually recognized (again, in the 1980s). +# +# From Paul Eggert (2008-06-30): +# There seems to be a good chance China switched to a single time zone in 1949 +# rather than in 1980 as Shanks & Pottenger have it, but we don't have a +# reliable documentary source saying so yet, so for now we still go with +# Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Changbai Time ("Long-white Time", Long-white = Heilongjiang area) @@ -468,13 +490,13 @@ Zone Asia/Dili 8:22:20 - LMT 1912 # India # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Asia/Calcutta 5:53:28 - LMT 1880 # Kolkata +Zone Asia/Kolkata 5:53:28 - LMT 1880 # Kolkata 5:53:20 - HMT 1941 Oct # Howrah Mean Time? 6:30 - BURT 1942 May 15 # Burma Time 5:30 - IST 1942 Sep 5:30 1:00 IST 1945 Oct 15 5:30 - IST -# The following are like Asia/Calcutta: +# The following are like Asia/Kolkata: # Andaman Is # Lakshadweep (Laccadive, Minicoy and Amindivi Is) # Nicobar Is @@ -599,6 +621,15 @@ Zone Asia/Jayapura 9:22:48 - LMT 1932 Nov # daylight saving time ... # http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916 # +# From Roozbeh Pournader (2007-11-05): +# This is quoted from Official Gazette of the Islamic Republic of +# Iran, Volume 63, Number 18242, dated Tuesday 1386/6/24 +# [2007-10-16]. I am doing the best translation I can:... +# The official time of the country will be moved forward for one hour +# on the 24 hours of the first day of the month of Farvardin and will +# be changed back to its previous state on the 24 hours of the +# thirtieth day of Shahrivar. +# # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Iran 1978 1980 - Mar 21 0:00 1:00 D Rule Iran 1978 only - Oct 21 0:00 0 S @@ -673,6 +704,21 @@ Zone Asia/Tehran 3:25:44 - LMT 1916 # # So we'll ignore the Economist's claim. +# From Steffen Thorsen (2008-03-10): +# The cabinet in Iraq abolished DST last week, according to the following +# news sources (in Arabic): +# +# http://www.aljeeran.net/wesima_articles/news-20080305-98602.html +# +# +# http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10 +# +# +# We have published a short article in English about the change: +# +# http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html +# + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Iraq 1982 only - May 1 0:00 1:00 D Rule Iraq 1982 1984 - Oct 1 0:00 0 S @@ -683,8 +729,8 @@ Rule Iraq 1986 1990 - Mar lastSun 1:00s 1:00 D # IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo. # Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this. # -Rule Iraq 1991 max - Apr 1 3:00s 1:00 D -Rule Iraq 1991 max - Oct 1 3:00s 0 S +Rule Iraq 1991 2007 - Apr 1 3:00s 1:00 D +Rule Iraq 1991 2007 - Oct 1 3:00s 0 S # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Baghdad 2:57:40 - LMT 1890 2:57:36 - BMT 1918 # Baghdad Mean Time? @@ -1374,6 +1420,42 @@ Zone Indian/Maldives 4:54:00 - LMT 1880 # Male # They decided not to adopt daylight-saving time.... # http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742 +# From Deborah Goldsmith (2008-03-30): +# We received a bug report claiming that the tz database UTC offset for +# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT +# +08:00 instead. Different sources appear to disagree with the tz +# database on this, e.g.: +# +# +# http://www.timeanddate.com/worldclock/city.html?n=1026 +# +# +# http://www.worldtimeserver.com/current_time_in_MN.aspx +# +# +# both say GMT+08:00. + +# From Steffen Thorsen (2008-03-31): +# eznis airways, which operates several domestic flights, has a flight +# schedule here: +# +# http://www.eznis.com/Container.jsp?id=112 +# +# (click the English flag for English) +# +# There it appears that flights between Choibalsan and Ulaanbatar arrive +# about 1:35 - 1:50 hours later in local clock time, no matter the +# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern +# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are +# in different time zones (like we know about), while Choibalsan and +# Ulaanbatar are in the same time zone (correction needed). + +# From Arthur David Olson (2008-05-19): +# Assume that Choibalsan is indeed offset by 8:00. +# XXX--in the absence of better information, assume that transition +# was at the start of 2008-03-31 (the day of Steffen Thorsen's report); +# this is almost surely wrong. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Mongol 1983 1984 - Apr 1 0:00 1:00 S Rule Mongol 1983 only - Oct 1 0:00 0 - @@ -1409,7 +1491,8 @@ Zone Asia/Ulaanbaatar 7:07:32 - LMT 1905 Aug Zone Asia/Choibalsan 7:38:00 - LMT 1905 Aug 7:00 - ULAT 1978 8:00 - ULAT 1983 Apr - 9:00 Mongol CHO%sT # Choibalsan Time + 9:00 Mongol CHO%sT 2008 Mar 31 # Choibalsan Time + 8:00 Mongol CHO%sT # Nepal # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -1459,10 +1542,32 @@ Zone Asia/Muscat 3:54:20 - LMT 1920 # The minister told a news conference that the experiment had rather # shown 8 per cent higher consumption of electricity. +# From Alex Krivenyshev (2008-05-15): +# +# Here is an article that Pakistan plan to introduce Daylight Saving Time +# on June 1, 2008 for 3 months. +# +# "... The federal cabinet on Wednesday announced a new conservation plan to help +# reduce load shedding by approving the closure of commercial centres at 9pm and +# moving clocks forward by one hour for the next three months. +# ...." +# +# +# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html +# +# OR +# +# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4 +# + +# From Arthur David Olson (2008-05-19): +# XXX--midnight transitions is a guess; 2008 only is a guess. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Pakistan 2002 only - Apr Sun>=2 0:01 1:00 S Rule Pakistan 2002 only - Oct Sun>=2 0:01 0 - +Rule Pakistan 2008 only - Jun 1 0:00 1:00 S +Rule Pakistan 2008 only - Sep 1 0:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Karachi 4:28:12 - LMT 1907 5:30 - IST 1942 Sep @@ -1700,7 +1805,7 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # kept their clocks set five and a half hours ahead of Greenwich Mean # Time (GMT), in line with neighbor India. # From Paul Eggert (2006-04-18): -# People who live in regions under Tamil control can use TZ='Asia/Calcutta', +# People who live in regions under Tamil control can use [TZ='Asia/Kolkata'], # as that zone has agreed with the Tamil areas since our cutoff date of 1970. # From K Sethu (2006-04-25): @@ -1790,10 +1895,62 @@ Rule Syria 2006 only - Sep 22 0:00 0 - # From Paul Eggert (2007-03-29): # Today the AP reported "Syria will switch to summertime at midnight Thursday." # http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php -# For lack of better info, assume the rule changed to "last Friday in March" -# this year. -Rule Syria 2007 max - Mar lastFri 0:00 1:00 S -Rule Syria 2007 max - Oct 1 0:00 0 - +Rule Syria 2007 only - Mar lastFri 0:00 1:00 S +# From Jesper Norgard (2007-10-27): +# The sister center ICARDA of my work CIMMYT is confirming that Syria DST will +# not take place 1.st November at 0:00 o'clock but 1.st November at 24:00 or +# rather Midnight between Thursday and Friday. This does make more sence than +# having it between Wednesday and Thursday (two workdays in Syria) since the +# weekend in Syria is not Saturday and Sunday, but Friday and Saturday. So now +# it is implemented at midnight of the last workday before weekend... +# +# From Steffen Thorsen (2007-10-27): +# Jesper Norgaard Welen wrote: +# +# > "Winter local time in Syria will be observed at midnight of Thursday 1 +# > November 2007, and the clock will be put back 1 hour." +# +# I found confirmation on this in this gov.sy-article (Arabic): +# http://wehda.alwehda.gov.sy/_print_veiw.asp?FileName=12521710520070926111247 +# +# which using Google's translate tools says: +# Council of Ministers also approved the commencement of work on +# identifying the winter time as of Friday, 2/11/2007 where the 60th +# minute delay at midnight Thursday 1/11/2007. +Rule Syria 2007 only - Nov Fri>=1 0:00 0 - + +# From Stephen Colebourne (2008-03-17): +# For everyone's info, I saw an IATA time zone change for [Syria] for +# this month (March 2008) in the last day or so...This is the data IATA +# are now using: +# Country Time Standard --- DST Start --- --- DST End --- DST +# Name Zone Variation Time Date Time Date +# Variation +# Syrian Arab +# Republic SY +0200 2200 03APR08 2100 30SEP08 +0300 +# 2200 02APR09 2100 30SEP09 +0300 +# 2200 01APR10 2100 30SEP10 +0300 + +# From Arthur David Olson (2008-03-17): +# Here's a link to English-language coverage by the Syrian Arab News +# Agency (SANA)... +# +# http://www.sana.sy/eng/21/2008/03/11/165173.htm +# ...which reads (in part) "The Cabinet approved the suggestion of the +# Ministry of Electricity to begin daylight savings time on Friday April +# 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd." +# Since Syria is two hours east of UTC, the 2200 and 2100 transition times +# shown above match up with midnight in Syria. + +# From Arthur David Olson (2008-03-18): +# My buest guess at a Syrian rule is "the Friday nearest April 1"; +# coding that involves either using a "Mar Fri>=29" construct that old time zone +# compilers can't handle or having multiple Rules (a la Israel). +# For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end. + +Rule Syria 2008 max - Apr Fri>=1 0:00 1:00 S +Rule Syria 2008 max - Oct 1 0:00 0 - + # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq 2:00 Syria EE%sT @@ -1847,13 +2004,13 @@ Zone Asia/Tashkent 4:37:12 - LMT 1924 May 2 # Vietnam -# From Paul Eggert (1993-11-18): -# Saigon's official name is Thanh-Pho Ho Chi Minh, but it's too long. -# We'll stick with the traditional name for now. +# From Arthur David Olson (2008-03-18): +# The English-language name of Vietnam's most populous city is "Ho Chi Min City"; +# we use Ho_Chi_Minh below to avoid a name of more than 14 characters. # From Shanks & Pottenger: # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Asia/Saigon 7:06:40 - LMT 1906 Jun 9 +Zone Asia/Ho_Chi_Minh 7:06:40 - LMT 1906 Jun 9 7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT? 7:00 - ICT 1912 May 8:00 - ICT 1931 May diff --git a/make/sun/javazic/tzdata/australasia b/make/sun/javazic/tzdata/australasia index eee5c0b5478aaaa8be093e204a118c89581bcb6f..823550415e0a765bb202def9001b532cccb395a1 100644 --- a/make/sun/javazic/tzdata/australasia +++ b/make/sun/javazic/tzdata/australasia @@ -1368,7 +1368,7 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # * Tonga will introduce DST in November # # I was given this link by John Letts: -# +# # http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm # # @@ -1378,7 +1378,7 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # (12 + 1 hour DST). # From Arthur David Olson (1999-09-20): -# According to # http://www.tongaonline.com/news/sept1799.html # : # "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000 diff --git a/make/sun/javazic/tzdata/backward b/make/sun/javazic/tzdata/backward index 0e64882a46552e3b692749ec79c968d1ed1c077f..85522740f41489fd3572d14ddb7eee41685a1a5c 100644 --- a/make/sun/javazic/tzdata/backward +++ b/make/sun/javazic/tzdata/backward @@ -46,12 +46,15 @@ Link America/St_Thomas America/Virgin Link Asia/Ashgabat Asia/Ashkhabad Link Asia/Chongqing Asia/Chungking Link Asia/Dhaka Asia/Dacca +Link Asia/Kolkata Asia/Calcutta Link Asia/Macau Asia/Macao Link Asia/Jerusalem Asia/Tel_Aviv +Link Asia/Ho_Chi_Minh Asia/Saigon Link Asia/Thimphu Asia/Thimbu Link Asia/Makassar Asia/Ujung_Pandang Link Asia/Ulaanbaatar Asia/Ulan_Bator Link Atlantic/Faroe Atlantic/Faeroe +Link Europe/Oslo Atlantic/Jan_Mayen Link Australia/Sydney Australia/ACT Link Australia/Sydney Australia/Canberra Link Australia/Lord_Howe Australia/LHI diff --git a/make/sun/javazic/tzdata/europe b/make/sun/javazic/tzdata/europe index 16fedf8036dab33a127ac5f0bfe59f2f24af5316..30724328383c8ecbbe6a35b329ea004167ead869 100644 --- a/make/sun/javazic/tzdata/europe +++ b/make/sun/javazic/tzdata/europe @@ -479,7 +479,7 @@ Rule EU 1979 1995 - Sep lastSun 1:00u 0 - Rule EU 1981 max - Mar lastSun 1:00u 1:00 S Rule EU 1996 max - Oct lastSun 1:00u 0 - # The most recent directive covers the years starting in 2002. See: -# # Directive 2000/84/EC of the European Parliament and of the Council # of 19 January 2001 on summer-time arrangements. # @@ -502,9 +502,48 @@ Rule C-Eur 1940 only - Apr 1 2:00s 1:00 S Rule C-Eur 1942 only - Nov 2 2:00s 0 - Rule C-Eur 1943 only - Mar 29 2:00s 1:00 S Rule C-Eur 1943 only - Oct 4 2:00s 0 - -Rule C-Eur 1944 only - Apr 3 2:00s 1:00 S +Rule C-Eur 1944 1945 - Apr Mon>=1 2:00s 1:00 S # Whitman gives 1944 Oct 7; go with Shanks & Pottenger. Rule C-Eur 1944 only - Oct 2 2:00s 0 - +# From Jesper Norgaard Welen (2008-07-13): +# +# I found what is probably a typo of 2:00 which should perhaps be 2:00s +# in the C-Eur rule from tz database version 2008d (this part was +# corrected in version 2008d). The circumstancial evidence is simply the +# tz database itself, as seen below: +# +# Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01 +# 0:00 France WE%sT 1945 Sep 16 3:00 +# +# Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15 +# 0:00 France WE%sT 1945 Sep 16 3:00 +# +# Zone Europe/Belgrade 1:22:00 - LMT 1884 +# 1:00 1:00 CEST 1945 Sep 16 2:00s +# +# Rule France 1945 only - Sep 16 3:00 0 - +# Rule Belgium 1945 only - Sep 16 2:00s 0 - +# Rule Neth 1945 only - Sep 16 2:00s 0 - +# +# The rule line to be changed is: +# +# Rule C-Eur 1945 only - Sep 16 2:00 0 - +# +# It seems that Paris, Monaco, Rule France, Rule Belgium all agree on +# 2:00 standard time, e.g. 3:00 local time. However there are no +# countries that use C-Eur rules in September 1945, so the only items +# affected are apparently these ficticious zones that translates acronyms +# CET and MET: +# +# Zone CET 1:00 C-Eur CE%sT +# Zone MET 1:00 C-Eur ME%sT +# +# It this is right then the corrected version would look like: +# +# Rule C-Eur 1945 only - Sep 16 2:00s 0 - +# +# A small step for mankind though 8-) +Rule C-Eur 1945 only - Sep 16 2:00s 0 - Rule C-Eur 1977 1980 - Apr Sun>=1 2:00s 1:00 S Rule C-Eur 1977 only - Sep lastSun 2:00s 0 - Rule C-Eur 1978 only - Oct 1 2:00s 0 - @@ -747,7 +786,8 @@ Rule Bulg 1981 only - Sep 27 2:00 0 - Zone Europe/Sofia 1:33:16 - LMT 1880 1:56:56 - IMT 1894 Nov 30 # Istanbul MT? 2:00 - EET 1942 Nov 2 3:00 - 1:00 C-Eur CE%sT 1945 Apr 2 3:00 + 1:00 C-Eur CE%sT 1945 + 1:00 - CET 1945 Apr 2 3:00 2:00 - EET 1979 Mar 31 23:00 2:00 Bulg EE%sT 1982 Sep 26 2:00 2:00 C-Eur EE%sT 1991 @@ -1115,33 +1155,40 @@ Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01 # [See tz-link.htm for the URL.] # From Joerg Schilling (2002-10-23): -# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by +# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by +# # General [Nikolai] Bersarin. # From Paul Eggert (2003-03-08): # +# http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf +# # says that Bersarin issued an order to use Moscow time on May 20. # However, Moscow did not observe daylight saving in 1945, so # this was equivalent to CEMT (GMT+3), not GMT+4. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -Rule Germany 1945 only - Apr 2 2:00s 1:00 S -Rule Germany 1945 only - May 24 2:00 2:00 M # Midsummer -Rule Germany 1945 only - Sep 24 3:00 1:00 S -Rule Germany 1945 only - Nov 18 2:00s 0 - Rule Germany 1946 only - Apr 14 2:00s 1:00 S Rule Germany 1946 only - Oct 7 2:00s 0 - Rule Germany 1947 1949 - Oct Sun>=1 2:00s 0 - -Rule Germany 1947 only - Apr 6 2:00s 1:00 S +# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition +# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger. +# Go with the PTB. +Rule Germany 1947 only - Apr 6 3:00s 1:00 S Rule Germany 1947 only - May 11 2:00s 2:00 M Rule Germany 1947 only - Jun 29 3:00 1:00 S Rule Germany 1948 only - Apr 18 2:00s 1:00 S Rule Germany 1949 only - Apr 10 2:00s 1:00 S + +Rule SovietZone 1945 only - May 24 2:00 2:00 M # Midsummer +Rule SovietZone 1945 only - Sep 24 3:00 1:00 S +Rule SovietZone 1945 only - Nov 18 2:00s 0 - + # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Berlin 0:53:28 - LMT 1893 Apr - 1:00 C-Eur CE%sT 1945 Apr 2 2:00 + 1:00 C-Eur CE%sT 1945 May 24 2:00 + 1:00 SovietZone CE%sT 1946 1:00 Germany CE%sT 1980 1:00 EU CE%sT @@ -1218,7 +1265,7 @@ Rule Hungary 1980 only - Apr 6 1:00 1:00 S Zone Europe/Budapest 1:16:20 - LMT 1890 Oct 1:00 C-Eur CE%sT 1918 1:00 Hungary CE%sT 1941 Apr 6 2:00 - 1:00 C-Eur CE%sT 1945 May 1 23:00 + 1:00 C-Eur CE%sT 1945 1:00 Hungary CE%sT 1980 Sep 28 2:00s 1:00 EU CE%sT @@ -1736,7 +1783,6 @@ Zone Europe/Oslo 0:43:00 - LMT 1895 Jan 1 # come up with more definitive info about the timekeeping during the # war years it's probably best just do do the following for now: Link Europe/Oslo Arctic/Longyearbyen -Link Europe/Oslo Atlantic/Jan_Mayen # Poland # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S @@ -2136,7 +2182,8 @@ Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Belgrade 1:22:00 - LMT 1884 1:00 - CET 1941 Apr 18 23:00 - 1:00 C-Eur CE%sT 1945 May 8 2:00s + 1:00 C-Eur CE%sT 1945 + 1:00 - CET 1945 May 8 2:00s 1:00 1:00 CEST 1945 Sep 16 2:00s # Metod Kozelj reports that the legal date of # transition to EU rules was 1982-11-27, for all of Yugoslavia at the time. diff --git a/make/sun/javazic/tzdata/iso3166.tab b/make/sun/javazic/tzdata/iso3166.tab index d976eb1a1a66de3cbdb7237d6e25afff121a906e..6931ee04a716aeb588b6aba9749ae220d904f9f1 100644 --- a/make/sun/javazic/tzdata/iso3166.tab +++ b/make/sun/javazic/tzdata/iso3166.tab @@ -28,7 +28,7 @@ # # This file contains a table with the following columns: # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 Newsletter No. V-12 (2006-09-26). See: +# ISO 3166-1 Newsletter VI-1 (2007-09-21). See: # # ISO 3166 Maintenance agency (ISO 3166/MA) # . @@ -69,6 +69,7 @@ BG Bulgaria BH Bahrain BI Burundi BJ Benin +BL St Barthelemy BM Bermuda BN Brunei BO Bolivia @@ -181,6 +182,7 @@ MA Morocco MC Monaco MD Moldova ME Montenegro +MF St Martin (French part) MG Madagascar MH Marshall Islands MK Macedonia diff --git a/make/sun/javazic/tzdata/leapseconds b/make/sun/javazic/tzdata/leapseconds index 77d28dae9ddea69f166d1f70c5d9dcf486d1c32f..4526cddf5b6db3f248d0b16363e6659969ce1f52 100644 --- a/make/sun/javazic/tzdata/leapseconds +++ b/make/sun/javazic/tzdata/leapseconds @@ -66,8 +66,10 @@ Leap 1995 Dec 31 23:59:60 + S Leap 1997 Jun 30 23:59:60 + S Leap 1998 Dec 31 23:59:60 + S Leap 2005 Dec 31 23:59:60 + S +Leap 2008 Dec 31 23:59:60 + S # INTERNATIONAL EARTH ROTATION AND REFERENCE SYSTEMS SERVICE (IERS) +# # SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE ET DES SYSTEMES DE REFERENCE # # SERVICE DE LA ROTATION TERRESTRE @@ -75,30 +77,38 @@ Leap 2005 Dec 31 23:59:60 + S # 61, Av. de l'Observatoire 75014 PARIS (France) # Tel. : 33 (0) 1 40 51 22 26 # FAX : 33 (0) 1 40 51 22 91 -# Internet : services.iers@obspm.fr +# e-mail : services.iers@obspm.fr +# http://hpiers.obspm.fr/eop-pc # -# Paris, 28 June 2007 +# Paris, 4 July 2008 # -# Bulletin C 34 +# Bulletin C 36 # # To authorities responsible # for the measurement and # distribution of time # -# INFORMATION ON UTC - TAI +# UTC TIME STEP +# on the 1st of January 2009 +# +# A positive leap second will be introduced at the end of December 2008. +# The sequence of dates of the UTC second markers will be: +# +# 2008 December 31, 23h 59m 59s +# 2008 December 31, 23h 59m 60s +# 2009 January 1, 0h 0m 0s # -# NO positive leap second will be introduced at the end of December 2007. -# The difference between Coordinated Universal Time UTC and the -# International Atomic Time TAI is : +# The difference between UTC and the International Atomic Time TAI is: # -# from 2006 January 1, 0h UTC, until further notice : UTC-TAI = -33 s +# from 2006 January 1, 0h UTC, to 2009 January 1 0h UTC : UTC-TAI = - 33s +# from 2009 January 1, 0h UTC, until further notice : UTC-TAI = - 34s # # Leap seconds can be introduced in UTC at the end of the months of December -# or June, depending on the evolution of UT1-TAI. Bulletin C is mailed every -# six months, either to announce a time step in UTC, or to confirm that there +# or June, depending on the evolution of UT1-TAI. Bulletin C is mailed every +# six months, either to announce a time step in UTC or to confirm that there # will be no time step at the next possible date. # # Daniel GAMBIS -# Director +# Head # Earth Orientation Center of IERS # Observatoire de Paris, France diff --git a/make/sun/javazic/tzdata/northamerica b/make/sun/javazic/tzdata/northamerica index ab5bb5b21537b6f1bf88b14f5f39ebcb36269fee..6e0317277b789e4e3a4dcec32f1759b205d83749 100644 --- a/make/sun/javazic/tzdata/northamerica +++ b/make/sun/javazic/tzdata/northamerica @@ -2098,8 +2098,8 @@ Zone America/Antigua -4:07:12 - LMT 1912 Mar 2 # http://www.jonesbahamas.com/?c=45&a=10412 # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -Rule Bahamas 1964 2006 - Oct lastSun 2:00 0 S -Rule Bahamas 1964 1986 - Apr lastSun 2:00 1:00 D +Rule Bahamas 1964 1975 - Oct lastSun 2:00 0 S +Rule Bahamas 1964 1975 - Apr lastSun 2:00 1:00 D # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone America/Nassau -5:09:24 - LMT 1912 Mar 2 -5:00 Bahamas E%sT 1976 @@ -2209,6 +2209,69 @@ Zone America/Costa_Rica -5:36:20 - LMT 1890 # San Jose # says Cuban clocks will advance at midnight on March 10. # For lack of better information, assume Cuba will use US rules, # except that it switches at midnight standard time as usual. +# +# From Steffen Thorsen (2007-10-25): +# Carlos Alberto Fonseca Arauz informed me that Cuba will end DST one week +# earlier - on the last Sunday of October, just like in 2006. +# +# He supplied these references: +# +# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES +# http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm +# +# From Alex Kryvenishev (2007-10-25): +# Here is also article from Granma (Cuba): +# +# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre +# http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html +# +# http://www.worldtimezone.com/dst_news/dst_news_cuba03.html + +# From Arthur David Olson (2008-03-09): +# I'm in Maryland which is now observing United States Eastern Daylight +# Time. At 9:44 local time I used RealPlayer to listen to +# +# http://media.enet.cu/radioreloj +# , a Cuban information station, and heard +# the time announced as "ocho cuarenta y cuatro" ("eight forty-four"), +# indicating that Cuba is still on standard time. + +# From Steffen Thorsen (2008-03-12): +# It seems that Cuba will start DST on Sunday, 2007-03-16... +# It was announced yesterday, according to this source (in Spanish): +# +# http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm +# +# +# Some more background information is posted here: +# +# http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html +# +# +# The article also says that Cuba has been observing DST since 1963, +# while Shanks (and tzdata) has 1965 as the first date (except in the +# 1940's). Many other web pages in Cuba also claim that it has been +# observed since 1963, but with the exception of 1970 - an exception +# which is not present in tzdata/Shanks. So there is a chance we need to +# change some historic records as well. +# +# One example: +# +# http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm +# + +# From Jesper Norgaard Welen (2008-03-13): +# The Cuban time change has just been confirmed on the most authoritative +# web site, the Granma. Please check out +# +# http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html +# +# +# Basically as expected after Steffen Thorsens information, the change +# will take place midnight between Saturday and Sunday. + +# From Arthur David Olson (2008-03-12): +# Assume Sun>=15 (third Sunday) going forward. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Cuba 1928 only - Jun 10 0:00 1:00 D @@ -2240,9 +2303,9 @@ Rule Cuba 1997 only - Oct 12 0:00s 0 S Rule Cuba 1998 1999 - Mar lastSun 0:00s 1:00 D Rule Cuba 1998 2003 - Oct lastSun 0:00s 0 S Rule Cuba 2000 2006 - Apr Sun>=1 0:00s 1:00 D -Rule Cuba 2006 only - Oct lastSun 0:00s 0 S -Rule Cuba 2007 max - Mar Sun>=8 0:00s 1:00 D -Rule Cuba 2007 max - Nov Sun>=1 0:00s 0 S +Rule Cuba 2006 max - Oct lastSun 0:00s 0 S +Rule Cuba 2007 only - Mar Sun>=8 0:00s 1:00 D +Rule Cuba 2008 max - Mar Sun>=15 0:00s 1:00 D # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone America/Havana -5:29:28 - LMT 1890 @@ -2309,6 +2372,10 @@ Zone America/Grenada -4:07:00 - LMT 1911 Jul # St George's # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone America/Guadeloupe -4:06:08 - LMT 1911 Jun 8 # Pointe a Pitre -4:00 - AST +# St Barthelemy +Link America/Guadeloupe America/St_Barthelemy +# St Martin (French part) +Link America/Guadeloupe America/Marigot # Guatemala # diff --git a/make/sun/javazic/tzdata/southamerica b/make/sun/javazic/tzdata/southamerica index a147a1b0870633c710b468bf7dc13d4961fdf65d..06a8d130e3973c94e95d1a674967f7dae95797c2 100644 --- a/make/sun/javazic/tzdata/southamerica +++ b/make/sun/javazic/tzdata/southamerica @@ -127,7 +127,11 @@ Rule Arg 1989 1992 - Oct Sun>=15 0:00 1:00 S # which did not result in the switch of a time zone, as they stayed 9 hours # from the International Date Line. Rule Arg 1999 only - Oct Sun>=1 0:00 1:00 S -Rule Arg 2000 only - Mar Sun>=1 0:00 0 - +# From Paul Eggert (2007-12-28): +# DST was set to expire on March 5, not March 3, but since it was converted +# to standard time on March 3 it's more convenient for us to pretend that +# it ended on March 3. +Rule Arg 2000 only - Mar 3 0:00 0 - # # From Peter Gradelski via Steffen Thorsen (2000-03-01): # We just checked with our Sao Paulo office and they say the government of @@ -162,6 +166,30 @@ Rule Arg 2000 only - Mar Sun>=1 0:00 0 - # This kind of things had always been done this way in Argentina. # We are still -03:00 all year round in all of the country. # +# From Steffen Thorsen (2007-12-21): +# A user (Leonardo Chaim) reported that Argentina will adopt DST.... +# all of the country (all Zone-entries) are affected. News reports like +# http://www.lanacion.com.ar/opinion/nota.asp?nota_id=973037 indicate +# that Argentina will use DST next year as well, from October to +# March, although exact rules are not given. +# +# From Jesper Norgaard Welen (2007-12-26) +# The last hurdle of Argentina DST is over, the proposal was approved in +# the lower chamber too (Deputados) with a vote 192 for and 2 against. +# By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to +# the original scanned proposal, where the dates and the zero hours are +# clear and unambiguous...This is the article about final approval: +# +# http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996 +# +# +# From Paul Eggert (2007-12-22): +# For dates after mid-2008, the following rules are my guesses and +# are quite possibly wrong, but are more likely than no DST at all. +Rule Arg 2007 only - Dec 30 0:00 1:00 S +Rule Arg 2008 max - Mar Sun>=15 0:00 0 - +Rule Arg 2008 max - Oct Sun>=1 0:00 1:00 S + # From Mariano Absatz (2004-05-21): # Today it was officially published that the Province of Mendoza is changing # its timezone this winter... starting tomorrow night.... @@ -222,10 +250,80 @@ Rule Arg 2000 only - Mar Sun>=1 0:00 0 - # http://www.sanjuan.gov.ar/prensa/archivo/000426.html # http://www.sanjuan.gov.ar/prensa/archivo/000441.html +# From Alex Krivenyshev (2008-01-17): +# Here are articles that Argentina Province San Luis is planning to end DST +# as earlier as upcoming Monday January 21, 2008 or February 2008: +# +# Provincia argentina retrasa reloj y marca diferencia con resto del pais +# (Argentine Province delayed clock and mark difference with the rest of the +# country) +# +# http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel +# +# +# Es inminente que en San Luis atrasen una hora los relojes +# (It is imminent in San Luis clocks one hour delay) +# +# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414 +# +# +# +# http://www.worldtimezone.net/dst_news/dst_news_argentina02.html +# + +# From Jesper Norgaard Welen (2008-01-18): +# The page of the San Luis provincial government +# +# http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812 +# +# confirms what Alex Krivenyshev has earlier sent to the tz +# emailing list about that San Luis plans to return to standard +# time much earlier than the rest of the country. It also +# confirms that upon request the provinces San Juan and Mendoza +# refused to follow San Luis in this change. +# +# The change is supposed to take place Monday the 21.st at 0:00 +# hours. As far as I understand it if this goes ahead, we need +# a new timezone for San Luis (although there are also documented +# independent changes in the southamerica file of San Luis in +# 1990 and 1991 which has not been confirmed). + +# From Jesper Norgaard Welen (2008-01-25): +# Unfortunately the below page has become defunct, about the San Luis +# time change. Perhaps because it now is part of a group of pages "Most +# important pages of 2008." +# +# You can use +# +# http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834 +# +# instead it seems. Or use "Buscador" from the main page of the San Luis +# government, and fill in "huso" and click OK, and you will get 3 pages +# from which the first one is identical to the above. + +# From Mariano Absatz (2008-01-28): +# I can confirm that the Province of San Luis (and so far only that +# province) decided to go back to UTC-3 effective midnight Jan 20th 2008 +# (that is, Monday 21st at 0:00 is the time the clocks were delayed back +# 1 hour), and they intend to keep UTC-3 as their timezone all year round +# (that is, unless they change their mind any minute now). +# +# So we'll have to add yet another city to 'southamerica' (I think San +# Luis city is the mos populated city in the Province, so it'd be +# America/Argentina/San_Luis... of course I can't remember if San Luis's +# history of particular changes goes along with Mendoza or San Juan :-( +# (I only remember not being able to collect hard facts about San Luis +# back in 2004, when these provinces changed to UTC-4 for a few days, I +# mailed them personally and never got an answer). + +# From Paul Eggert (2008-06-30): # Unless otherwise specified, data are from Shanks & Pottenger through 1992, # from the IATA otherwise. As noted below, Shanks & Pottenger say that -# America/Cordoba split into 6 subregions during 1991/1992, but we -# haven't verified this yet so for now we'll keep it a single region. +# America/Cordoba split into 6 subregions during 1991/1992, one of which +# was America/San_Luis, but we haven't verified this yet so for now we'll +# keep America/Cordoba a single region rather than splitting it into the +# other 5 subregions. + # # Zone NAME GMTOFF RULES FORMAT [UNTIL] # @@ -236,18 +334,16 @@ Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31 -4:00 Arg AR%sT 1969 Oct 5 -3:00 Arg AR%sT 1999 Oct 3 -4:00 Arg AR%sT 2000 Mar 3 - -3:00 - ART + -3:00 Arg AR%sT # # Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN), Chaco (CC), # Formosa (FM), Salta (SA), Santiago del Estero (SE), Cordoba (CB), -# San Luis (SL), La Pampa (LP), Neuquen (NQ), Rio Negro (RN) +# La Pampa (LP), Neuquen (NQ), Rio Negro (RN) # # Shanks & Pottenger also make the following claims, which we haven't verified: # - Formosa switched to -3:00 on 1991-01-07. # - Misiones switched to -3:00 on 1990-12-29. # - Chaco switched to -3:00 on 1991-01-04. -# - San Luis switched to -4:00 on 1990-03-14, then to -3:00 on 1990-10-15, -# then to -4:00 on 1991-03-01, then to -3:00 on 1991-06-01. # - Santiago del Estero switched to -4:00 on 1991-04-01, # then to -3:00 on 1991-04-26. # @@ -259,7 +355,7 @@ Zone America/Argentina/Cordoba -4:16:48 - LMT 1894 Oct 31 -4:00 - WART 1991 Oct 20 -3:00 Arg AR%sT 1999 Oct 3 -4:00 Arg AR%sT 2000 Mar 3 - -3:00 - ART + -3:00 Arg AR%sT # # Tucuman (TM) Zone America/Argentina/Tucuman -4:20:52 - LMT 1894 Oct 31 @@ -272,7 +368,7 @@ Zone America/Argentina/Tucuman -4:20:52 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 Jun 1 -4:00 - WART 2004 Jun 13 - -3:00 - ART + -3:00 Arg AR%sT # # La Rioja (LR) Zone America/Argentina/La_Rioja -4:27:24 - LMT 1894 Oct 31 @@ -285,7 +381,7 @@ Zone America/Argentina/La_Rioja -4:27:24 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 Jun 1 -4:00 - WART 2004 Jun 20 - -3:00 - ART + -3:00 Arg AR%sT # # San Juan (SJ) Zone America/Argentina/San_Juan -4:34:04 - LMT 1894 Oct 31 @@ -298,7 +394,7 @@ Zone America/Argentina/San_Juan -4:34:04 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 May 31 -4:00 - WART 2004 Jul 25 - -3:00 - ART + -3:00 Arg AR%sT # # Jujuy (JY) Zone America/Argentina/Jujuy -4:21:12 - LMT 1894 Oct 31 @@ -312,7 +408,7 @@ Zone America/Argentina/Jujuy -4:21:12 - LMT 1894 Oct 31 -3:00 1:00 ARST 1992 -3:00 Arg AR%sT 1999 Oct 3 -4:00 Arg AR%sT 2000 Mar 3 - -3:00 - ART + -3:00 Arg AR%sT # # Catamarca (CT), Chubut (CH) Zone America/Argentina/Catamarca -4:23:08 - LMT 1894 Oct 31 @@ -325,7 +421,7 @@ Zone America/Argentina/Catamarca -4:23:08 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 Jun 1 -4:00 - WART 2004 Jun 20 - -3:00 - ART + -3:00 Arg AR%sT # # Mendoza (MZ) Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31 @@ -342,6 +438,23 @@ Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 May 23 -4:00 - WART 2004 Sep 26 + -3:00 Arg AR%sT +# +# San Luis (SL) +Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31 + -4:16:48 - CMT 1920 May + -4:00 - ART 1930 Dec + -4:00 Arg AR%sT 1969 Oct 5 + -3:00 Arg AR%sT 1990 + -3:00 1:00 ARST 1990 Mar 14 + -4:00 - WART 1990 Oct 15 + -4:00 1:00 WARST 1991 Mar 1 + -4:00 - WART 1991 Jun 1 + -3:00 - ART 1999 Oct 3 + -4:00 1:00 WARST 2000 Mar 3 + -3:00 - ART 2004 May 31 + -4:00 - WART 2004 Jul 25 + -3:00 Arg AR%sT 2008 Jan 21 -3:00 - ART # # Santa Cruz (SC) @@ -353,7 +466,7 @@ Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 Jun 1 -4:00 - WART 2004 Jun 20 - -3:00 - ART + -3:00 Arg AR%sT # # Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF) Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 @@ -364,7 +477,7 @@ Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 -4:00 Arg AR%sT 2000 Mar 3 -3:00 - ART 2004 May 30 -4:00 - WART 2004 Jun 20 - -3:00 - ART + -3:00 Arg AR%sT # Aruba # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -450,6 +563,50 @@ Zone America/La_Paz -4:32:36 - LMT 1890 # Brazil will start DST on 2007-10-14 00:00 and end on 2008-02-17 00:00: # http://www.mme.gov.br/site/news/detail.do;jsessionid=BBA06811AFCAAC28F0285210913513DA?newsId=13975 +# From Paul Schulze (2008-06-24): +# ...by law number 11.662 of April 24, 2008 (published in the "Diario +# Oficial da Uniao"...) in Brazil there are changes in the timezones, +# effective today (00:00am at June 24, 2008) as follows: +# +# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the +# part of the Amazonas state that had this timezone now being put to the +# timezone UTC+4 +# b) The whole Para state now is put at timezone UTC+3, instead of just +# part of it, as was before. +# +# This change follows a proposal of senator Tiao Viana of Acre state, that +# proposed it due to concerns about open television channels displaying +# programs inappropriate to youths in the states that had the timezone +# UTC+5 too early in the night. In the occasion, some more corrections +# were proposed, trying to unify the timezones of any given state. This +# change modifies timezone rules defined in decree 2.784 of 18 June, +# 1913. + +# From Rodrigo Severo (2008-06-24): +# Just correcting the URL: +# +# https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=3Ddo&secao=3D1&pagina=3D1&data=3D25/04/2008 +# +# +# As a result of the above Decree I believe the America/Rio_Branco +# timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall +# be created to represent the the west side of the Para State. I +# suggest this new timezone be called Santarem as the most +# important/populated city in the affected area. +# +# This new timezone would be the same as the Rio_Branco timezone up to +# the 2008/06/24 change which would be to UTC-3 instead of UTC-4. + +# From Alex Krivenyshev (2008-06-24): +# This is a quick reference page for New and Old Brazil Time Zones map. +# +# http://www.worldtimezone.com/brazil-time-new-old.php +# +# +# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05 +# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western +# part of Par state is moving to one timezone UTC- 03 (from UTC -04). + # From Paul Eggert (2002-10-10): # The official decrees referenced below are mostly taken from # @@ -572,13 +729,13 @@ Rule Brazil 2000 only - Feb 27 0:00 0 - Rule Brazil 2000 2001 - Oct Sun>=8 0:00 1:00 S Rule Brazil 2001 2006 - Feb Sun>=15 0:00 0 - # Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE. -# +# 4,399 Rule Brazil 2002 only - Nov 3 0:00 1:00 S # Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO. -# +# 4,844 Rule Brazil 2003 only - Oct 19 0:00 1:00 S # Decree 5,223 (2004-10-01) reestablishes DST in MT. -# +# 5,223 Rule Brazil 2004 only - Nov 2 0:00 1:00 S # Decree 5,539 (2005-09-19), # adopted by the same states as before. @@ -587,9 +744,8 @@ Rule Brazil 2005 only - Oct 16 0:00 1:00 S # adopted by the same states as before. Rule Brazil 2006 only - Nov 5 0:00 1:00 S Rule Brazil 2007 only - Feb 25 0:00 0 - -# (Decree number not yet known) -# http://www.brasil.gov.br/noticias/ultimas_noticias/horario_verao070920/ -# (2007-09-20) after a heads-up from Steffen Thorsen: +# Decree 6,212 (2007-09-26), +# adopted by the same states as before. Rule Brazil 2007 max - Oct Sun>=8 0:00 1:00 S Rule Brazil 2008 max - Feb Sun>=15 0:00 0 - # The latest ruleset listed above says that the following states observe DST: @@ -597,7 +753,6 @@ Rule Brazil 2008 max - Feb Sun>=15 0:00 0 - # For dates after mid-2008, the above rules with TO="max" are guesses # and are quite possibly wrong, but are more likely than no DST at all. - # Zone NAME GMTOFF RULES FORMAT [UNTIL] # # Fernando de Noronha (administratively part of PE) @@ -623,6 +778,13 @@ Zone America/Belem -3:13:56 - LMT 1914 -3:00 Brazil BR%sT 1988 Sep 12 -3:00 - BRT # +# west Para (PA) +# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem. +Zone America/Santarem -3:38:48 - LMT 1914 + -4:00 Brazil AM%sT 1988 Sep 12 + -4:00 - AMT 2008 Jun 24 00:00 + -3:00 - BRT +# # Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN), # Paraiba (PB) Zone America/Fortaleza -2:34:00 - LMT 1914 @@ -685,8 +847,7 @@ Zone America/Cuiaba -3:44:20 - LMT 1914 -4:00 - AMT 2004 Oct 1 -4:00 Brazil AM%sT # -# west Para (PA), Rondonia (RO) -# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem. +# Rondonia (RO) Zone America/Porto_Velho -4:15:36 - LMT 1914 -4:00 Brazil AM%sT 1988 Sep 12 -4:00 - AMT @@ -713,13 +874,14 @@ Zone America/Eirunepe -4:39:28 - LMT 1914 -5:00 Brazil AC%sT 1988 Sep 12 -5:00 - ACT 1993 Sep 28 -5:00 Brazil AC%sT 1994 Sep 22 - -5:00 - ACT + -5:00 - ACT 2008 Jun 24 00:00 + -4:00 - AMT # # Acre (AC) Zone America/Rio_Branco -4:31:12 - LMT 1914 -5:00 Brazil AC%sT 1988 Sep 12 - -5:00 - ACT - + -5:00 - ACT 2008 Jun 24 00:00 + -4:00 - AMT # Chile @@ -753,6 +915,26 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 # America/Santiago. The pre-1980 Pacific/Easter data are dubious, # but we have no other source. +# From German Poo-Caaman~o (2008-03-03): +# Due to drought, Chile extends Daylight Time in three weeks. This +# is one-time change (Saturday 3/29 at 24:00 for America/Santiago +# and Saturday 3/29 at 22:00 for Pacific/Easter) +# The Supreme Decree is located at +# +# http://www.shoa.cl/servicios/supremo316.pdf +# +# and the instructions for 2008 are located in: +# +# http://www.horaoficial.cl/cambio.htm +# . + +# From Jose Miguel Garrido (2008-03-05): +# ... +# You could see the announces of the change on +# +# http://www.shoa.cl/noticias/2008/04hora/hora.htm +# . + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Chile 1927 1932 - Sep 1 0:00 1:00 S Rule Chile 1928 1932 - Apr 1 0:00 0 - @@ -783,7 +965,11 @@ Rule Chile 1998 only - Mar Sun>=9 3:00u 0 - Rule Chile 1998 only - Sep 27 4:00u 1:00 S Rule Chile 1999 only - Apr 4 3:00u 0 - Rule Chile 1999 max - Oct Sun>=9 4:00u 1:00 S -Rule Chile 2000 max - Mar Sun>=9 3:00u 0 - +Rule Chile 2000 2007 - Mar Sun>=9 3:00u 0 - +# N.B.: the end of March 29 in Chile is March 30 in Universal time, +# which is used below in specifying the transition. +Rule Chile 2008 only - Mar 30 3:00u 0 - +Rule Chile 2009 max - Mar Sun>=9 3:00u 0 - # IATA SSIM anomalies: (1992-02) says 1992-03-14; # (1996-09) says 1998-03-08. Ignore these. # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -1129,19 +1315,17 @@ Zone America/Montevideo -3:44:44 - LMT 1898 Jun 28 # Venezuela # -# From Kiraz Janicke (2007-09-25), in -# http://www.venezuelanalysis.com/analysis/2645: -# The proposal ... involves turning the clock back half an hour from -# +4.00 Greenwich Mean Time (GMT), to +4.30GMT, the time zone -# Venezuela had until December 31, 1964, when the current time zone -# was adopted. The change was due to take place on September 17 and -# then on September 24, but has since been postponed until December -# 31, to allow for compliance with international organizations, such -# as the International Office of Weights and Measures. +# From John Stainforth (2007-11-28): +# ... the change for Venezuela originally expected for 2007-12-31 has +# been brought forward to 2007-12-09. The official announcement was +# published today in the "Gaceta Oficial de la Republica Bolivariana +# de Venezuela, numero 38.819" (official document for all laws or +# resolution publication) +# http://www.globovision.com/news.php?nid=72208 # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone America/Caracas -4:27:44 - LMT 1890 -4:27:40 - CMT 1912 Feb 12 # Caracas Mean Time? -4:30 - VET 1965 # Venezuela Time - -4:00 - VET 2008 + -4:00 - VET 2007 Dec 9 03:00 -4:30 - VET diff --git a/make/sun/javazic/tzdata/zone.tab b/make/sun/javazic/tzdata/zone.tab index b252abd4fd076b739200ece854e2ad506fa77eb2..a9c686227ec891c55f5eee7b4724bed0134c6483 100644 --- a/make/sun/javazic/tzdata/zone.tab +++ b/make/sun/javazic/tzdata/zone.tab @@ -64,7 +64,8 @@ AQ -7824+10654 Antarctica/Vostok Vostok Station, S Magnetic Pole AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) -AR -3124-06411 America/Argentina/Cordoba most locations (CB, CC, CN, ER, FM, LP, MN, NQ, RN, SA, SE, SF, SL) +AR -3124-06411 America/Argentina/Cordoba most locations (CB, CC, CN, ER, FM, LP, MN, NQ, RN, SA, SE, SF) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) @@ -99,6 +100,7 @@ BG +4241+02319 Europe/Sofia BH +2623+05035 Asia/Bahrain BI -0323+02922 Africa/Bujumbura BJ +0629+00237 Africa/Porto-Novo +BL +1753-06251 America/St_Barthelemy BM +3217-06446 Atlantic/Bermuda BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz @@ -112,7 +114,8 @@ BR -1259-03831 America/Bahia Bahia BR -2332-04637 America/Sao_Paulo S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS) BR -2027-05437 America/Campo_Grande Mato Grosso do Sul BR -1535-05605 America/Cuiaba Mato Grosso -BR -0846-06354 America/Porto_Velho W Para, Rondonia +BR -0226-05452 America/Santarem W Para +BR -0846-06354 America/Porto_Velho Rondonia BR +0249-06040 America/Boa_Vista Roraima BR -0308-06001 America/Manaus E Amazonas BR -0640-06952 America/Eirunepe W Amazonas @@ -230,7 +233,7 @@ ID -0232+14042 Asia/Jayapura Irian Jaya & the Moluccas IE +5320-00615 Europe/Dublin IL +3146+03514 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man -IN +2232+08822 Asia/Calcutta +IN +2232+08822 Asia/Kolkata IO -0720+07225 Indian/Chagos IQ +3321+04425 Asia/Baghdad IR +3540+05126 Asia/Tehran @@ -272,6 +275,7 @@ MA +3339-00735 Africa/Casablanca MC +4342+00723 Europe/Monaco MD +4700+02850 Europe/Chisinau ME +4226+01916 Europe/Podgorica +MF +1804-06305 America/Marigot MG -1855+04731 Indian/Antananarivo MH +0709+17112 Pacific/Majuro most locations MH +0905+16720 Pacific/Kwajalein Kwajalein @@ -361,8 +365,7 @@ SE +5920+01803 Europe/Stockholm SG +0117+10351 Asia/Singapore SH -1555-00542 Atlantic/St_Helena SI +4603+01431 Europe/Ljubljana -SJ +7800+01600 Arctic/Longyearbyen Svalbard -SJ +7059-00805 Atlantic/Jan_Mayen Jan Mayen +SJ +7800+01600 Arctic/Longyearbyen SK +4809+01707 Europe/Bratislava SL +0830-01315 Africa/Freetown SM +4355+01228 Europe/San_Marino @@ -432,7 +435,7 @@ VC +1309-06114 America/St_Vincent VE +1030-06656 America/Caracas VG +1827-06437 America/Tortola VI +1821-06456 America/St_Thomas -VN +1045+10640 Asia/Saigon +VN +1045+10640 Asia/Ho_Chi_Minh VU -1740+16825 Pacific/Efate WF -1318-17610 Pacific/Wallis WS -1350-17144 Pacific/Apia 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/Makefile b/make/sun/net/spi/Makefile index 20583bc4eb73ef7018a4800c7f4e4f85acabc2cf..f969b87992acf8228384a1386ad924abb94b3b81 100644 --- a/make/sun/net/spi/Makefile +++ b/make/sun/net/spi/Makefile @@ -23,10 +23,6 @@ # have any questions. # -# -# Makefile for building com/sun -# - BUILDDIR = ../../.. include $(BUILDDIR)/common/Defs.gmk diff --git a/make/sun/net/spi/nameservice/Makefile b/make/sun/net/spi/nameservice/Makefile index b6593c71d559b5160360493991d1708244ba387b..b0ff374de3d09be753c34964cf9d298fd9ffb8f2 100644 --- a/make/sun/net/spi/nameservice/Makefile +++ b/make/sun/net/spi/nameservice/Makefile @@ -23,10 +23,6 @@ # have any questions. # -# -# Makefile for building com/sun -# - BUILDDIR = ../../../.. include $(BUILDDIR)/common/Defs.gmk diff --git a/make/sun/net/spi/nameservice/dns/Makefile b/make/sun/net/spi/nameservice/dns/Makefile index 0a7683f5dac144e7d2b058ada024980e9c99f24b..d86a3c69f00d6287e667b552e109d2770ec3e4be 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 @@ -24,7 +24,7 @@ # # -# Makefile for building JNDI service provider toolkit +# Makefile for building JNDI DNS name service provider # BUILDDIR = ../../../../.. @@ -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/make/tools/Makefile b/make/tools/Makefile index 68dfe8ef33309a46556775fa43be54d862601719..3803fbc6edabb494e7b7318384985815ac39ec7d 100644 --- a/make/tools/Makefile +++ b/make/tools/Makefile @@ -32,7 +32,6 @@ include $(BUILDDIR)/common/Defs.gmk SUBDIRS = \ addjsum \ - auto_multi \ buildmetaindex \ commentchecker \ compile_font_config \ diff --git a/make/tools/src/build/tools/automulti/AutoMulti.java b/make/tools/src/build/tools/automulti/AutoMulti.java deleted file mode 100644 index a59edc856caa111790feb5cb9108fcaff161b6cc..0000000000000000000000000000000000000000 --- a/make/tools/src/build/tools/automulti/AutoMulti.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 1998-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 build.tools.automulti; - -import java.lang.reflect.*; -import java.util.*; -import java.io.*; - -/** - * Automatically generates the Multiplexing UI classes - * for Swing. - *

- * To use, type 'java AutoMulti ' where - * is the directory containing the source for Swing's UI classes and - * is the package prefix to use before ".swing.plaf.multi". - * For example: - * - *

- * cd TEST
- * ../../../../build/solaris-sparc/bin/java AutoMulti ../../../../src/share/classes/javax/swing/plaf javax
- * 
- * - * AutoMulti will scour the plaf directory for *UI.java files and - * generate Multi*UI.java files that do the multiplexing thing. - *

- * NOTE: This tool depends upon the existence of and on the - * compiled classes from being somewhere in the class path. - * - * @author Willie Walker - */ -public class AutoMulti { - static String importLines; - - /** - * A silly list of parameter names to use. Skips "i" because we use - * it as a 'for' loop counter. If you want to get fancy, please feel - * to change how parameter names are obtained. This will break if - * someone decides to create a UI method that takes more than 8 - * parameters. Which one is a bug (this breaking or having a method - * with more than eight parameters) is a subjective thing. - */ - public static String[] paramNames = {"a","b","c","d","e","f","g","h"}; - - /** - * Removes the package names (e.g., javax.swing) from the name. - */ - public static String unqualifyName(String name) { - StringTokenizer parser = new StringTokenizer(name,"."); - String unqualifiedName = null; - while (parser.hasMoreTokens()) { - unqualifiedName = parser.nextToken(); - } - return removeDollars(unqualifiedName); - } - - /** - * Strips the extension from the filename. - */ - public static String stripExtension(String name) { - StringTokenizer parser = new StringTokenizer(name,"."); - return parser.nextToken(); - } - - /** - * Adds some spaces. - */ - public static void indent(StringBuffer s, int i) { - while (i > 0) { - s.append(" "); - i--; - } - } - - /** - * Spits out all the beginning stuff. - */ - public static StringBuffer createPreamble(String prefixName) { - StringBuffer s = new StringBuffer(); - s.append("/*\n"); - s.append(" *\n"); - s.append(" * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.\n"); - s.append(" * \n"); - s.append(" * This software is the proprietary information of Sun Microsystems, Inc. \n"); - s.append(" * Use is subject to license terms.\n"); - s.append(" * \n"); - s.append(" */\n"); - s.append("package " + prefixName + ".swing.plaf.multi;\n"); - s.append("\n"); - return s; - } - - /** - * Replaces 'Xxx$Yyy' with "Xxx'. Used by addImport because you - * can't import nested classes directly. - */ - public static String removeNestedClassName(String s) { - int dollarPosition = s.indexOf('$'); - - if (dollarPosition >= 0) { // s contains '$' - StringBuffer sb = new StringBuffer(s); - sb.setLength(dollarPosition); - return sb.toString(); - } else { // no '$' - return s; - } - } - - /** - * Replaces '$' with ".'. Needed for printing inner class names - * for argument and return types. - */ - public static String removeDollars(String s) { - int dollarPosition = s.indexOf('$'); - - if (dollarPosition >= 0) { // s contains '$' - StringBuffer sb = new StringBuffer(s); - while (dollarPosition >= 0) { - //XXX: will there ever be more than one '$'? - sb.replace(dollarPosition, dollarPosition+1, "."); - dollarPosition = sb.indexOf("$", dollarPosition); - } - return sb.toString(); - } else { // no $ - return s; - } - } - - /** - * Adds an import line to the String. - */ - public static void addImport(String s, Class theClass) { - if (!theClass.isPrimitive() && (theClass != Object.class)) { - String className = removeNestedClassName(theClass.getName()); - String importLine = new String("import " + className + ";\n"); - if (importLines.indexOf(importLine) == -1) { - importLines += importLine; - } - } - } - - /** - * Spits out the class header information. - */ - public static void addHeader(StringBuffer s, String className) { - s.append("/**\n"); - s.append(" * A multiplexing UI used to combine " + className + "s.\n"); - s.append(" * \n"); - s.append(" *

This file was automatically generated by AutoMulti.\n"); - s.append(" *\n"); - s.append(" * @author Otto Multey\n"); // Get it? I crack myself up. - s.append(" */\n"); - s.append("public class Multi" + className + " extends " + className + " {\n"); - s.append("\n"); - s.append(" /**\n"); - s.append(" * The vector containing the real UIs. This is populated \n"); - s.append(" * in the call to createUI, and can be obtained by calling\n"); - s.append(" * the getUIs method. The first element is guaranteed to be the real UI \n"); - s.append(" * obtained from the default look and feel.\n"); - s.append(" */\n"); - s.append(" protected Vector uis = new Vector();\n"); - s.append("\n"); - s.append("////////////////////\n"); - s.append("// Common UI methods\n"); - s.append("////////////////////\n"); - s.append("\n"); - s.append(" /**\n"); - s.append(" * Returns the list of UIs associated with this multiplexing UI. This \n"); - s.append(" * allows processing of the UIs by an application aware of multiplexing \n"); - s.append(" * UIs on components.\n"); - s.append(" */\n"); - s.append(" public ComponentUI[] getUIs() {\n"); - s.append(" return MultiLookAndFeel.uisToArray(uis);\n"); - s.append(" }\n"); - } - - /** - * Prints out the code for a method. This is pretty specific to the - * Multiplexing UI code, so don't get any fancy ideas. - */ - public static void addMethod(StringBuffer s, Method m, String origName, String className) { - - // Get the method name and the return type. Be a little careful about arrays. - // - String methodName = unqualifyName(m.getName()); - String returnType; - if (!m.getReturnType().isArray()) { - returnType = unqualifyName(m.getReturnType().toString()); - addImport(importLines,m.getReturnType()); - } else { - returnType = unqualifyName(m.getReturnType().getComponentType().toString()) - + "[]"; - addImport(importLines,m.getReturnType().getComponentType()); - } - - // Print the javadoc - // - s.append("\n"); - if (methodName.equals("createUI")) { - s.append(" /**\n"); - s.append(" * Returns a multiplexing UI instance if any of the auxiliary\n"); - s.append(" * LookAndFeels supports this UI. Otherwise, just returns the \n"); - s.append(" * UI object obtained from the default LookAndFeel.\n"); - s.append(" */\n"); - } else if (!returnType.equals("void")) { - s.append(" /**\n"); - s.append(" * Invokes the " + methodName + " method on each UI handled by this object.\n"); - s.append(" * \n"); - s.append(" * @return the value obtained from the first UI, which is\n"); - s.append(" * the UI obtained from the default LookAndFeel\n"); - s.append(" */\n"); - } else { - s.append(" /**\n"); - s.append(" * Invokes the " + methodName - + " method on each UI handled by this object.\n"); - s.append(" */\n"); - } - - // Print the method signature - // - s.append(" public"); - if (Modifier.isStatic(m.getModifiers())) { - s.append(" static"); - } - s.append(" " + returnType); - s.append(" " + methodName); - s.append("("); - - Class[] params = m.getParameterTypes(); - Class temp; - String braces; - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(", "); - } - temp = params[i]; - braces = new String(""); - while (temp.isArray()) { - braces += "[]"; - temp = temp.getComponentType(); - } - s.append(unqualifyName(temp.getName()) + braces + " " + paramNames[i]); - addImport(importLines,temp); - } - s.append(")"); - - // Don't forget about exceptions - // - Class exceptions[] = m.getExceptionTypes(); - String throwsString = new String(""); - - if (exceptions.length > 0) { - s.append("\n"); - indent(s,12); - s.append("throws "); - for (int i = 0; i < exceptions.length; i++) { - if (i > 0) { - s.append(", "); - } - s.append(unqualifyName(exceptions[i].getName())); - addImport(importLines,exceptions[i]); - } - } - s.append(throwsString + " {\n"); - - // Now print out the contents of the method. We do a special thing - // for the createUI method, another thing if the method returns 'void' - // and a third thing if we don't do either of the first two. If - // you want to squash this down, feel free. - // - if (methodName.equals("createUI")) { - indent(s,8); - s.append("ComponentUI mui = new Multi" + origName + "();\n"); - indent(s,8); - s.append("return MultiLookAndFeel.createUIs(mui,\n"); - indent(s,42); - s.append("((Multi" + origName +") mui).uis,\n"); - indent(s,42); - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(","); - } - s.append(paramNames[i]); - } - s.append(");\n"); - } else if (!returnType.equals("void")) { - indent(s,8); - s.append(returnType + " returnValue = \n"); - indent(s,12); - s.append("((" + className + ") (uis.elementAt(0)))." - + methodName + "("); - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(","); - } - s.append(paramNames[i]); - } - s.append(");\n"); - indent(s,8); - s.append("for (int i = 1; i < uis.size(); i++) {\n"); - indent(s,12); - s.append("((" + className + ") (uis.elementAt(i)))." - + methodName + "("); - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(","); - } - s.append(paramNames[i]); - } - s.append(");\n"); - indent(s,8); - s.append("}\n"); - indent(s,8); - s.append("return returnValue;\n"); - } else { - indent(s,8); - s.append("for (int i = 0; i < uis.size(); i++) {\n"); - indent(s,12); - s.append("((" + className + ") (uis.elementAt(i)))." - + methodName + "("); - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(","); - } - s.append(paramNames[i]); - } - s.append(");\n"); - indent(s,8); - s.append("}\n"); - } - indent(s,4); - s.append("}\n"); - } - - /** - * Takes a plaf class name (e.g., "MenuUI") and generates the corresponding - * Multiplexing UI Java source code (e.g., "MultiMenuUI.java"). - */ - public static void generateFile(String prefixName, String className) { - try { - FileOutputStream fos; - PrintWriter outFile; - - importLines = new String(); - importLines += new String("import java.util.Vector;\n"); - - StringBuffer body = new StringBuffer(); - Class wee = Class.forName(prefixName + ".swing.plaf." + className); - String weeName = unqualifyName(wee.getName()); - addImport(importLines,wee); - while (!weeName.equals("Object")) { - body.append("\n"); - body.append("////////////////////\n"); - body.append("// " + weeName + " methods\n"); - body.append("////////////////////\n"); - Method[] methods = wee.getDeclaredMethods(); - for (int i=0; i < methods.length; i++) { - if (Modifier.isPublic(methods[i].getModifiers())) { - addMethod(body,methods[i],className,weeName); - } - } - wee = wee.getSuperclass(); - weeName = unqualifyName(wee.getName()); - addImport(importLines,wee); - } - - fos = new FileOutputStream("Multi" + className + ".java"); - outFile = new PrintWriter(fos); - StringBuffer outText = createPreamble(prefixName); - outText.append(importLines.toString() + "\n"); - addHeader(outText,className); - outText.append(body.toString()); - outText.append("}\n"); - outFile.write(outText.toString()); - outFile.flush(); - outFile.close(); - } catch (Exception e) { - System.err.println(e); - } - } - - /** - * D'Oh! Something bad happened. - */ - public static void usage(String s) throws IOException { - System.err.println("Usage: AutoMulti [com.sun]"); - throw new IllegalArgumentException(s); - } - - /** - * Takes the plaf directory name and generates the multiplexing UI - * source code. - */ - public static void main(String[] args) throws IOException { - - if (args.length < 1) { - usage(""); - } - - String dirName = args[0]; - File dir = new File(dirName); - if (!dir.isDirectory()) { - System.err.println("No such directory: " + dirName); - usage(""); - } - - String prefixName; - if (args.length > 1) { - prefixName = args[1]; - } else { - prefixName = "com.sun.java"; - } - - String plafUIs[] = dir.list(new UIJavaFilter()); - for (int i = 0; i < plafUIs.length; i++) { - generateFile(prefixName,stripExtension(plafUIs[i])); - } - } -} - -/** - * Only accepts file names of the form *UI.java. The one exception - * is not accepting ComponentUI.java because we don't need to generate - * a multiplexing class for it. - */ -class UIJavaFilter implements FilenameFilter { - public boolean accept(File dir, String name) { - if (name.equals("ComponentUI.java")) { - return false; - } else if (name.endsWith("UI.java")) { - return true; - } else { - return false; - } - } -} diff --git a/make/tools/src/build/tools/automulti/README.txt b/make/tools/src/build/tools/automulti/README.txt deleted file mode 100644 index b5de5afe910229e14664a5b3e456a1611d2307b1..0000000000000000000000000000000000000000 --- a/make/tools/src/build/tools/automulti/README.txt +++ /dev/null @@ -1,36 +0,0 @@ -AutoMulti is the tool that automatically generates the -Multi*UI classes for the Multiplexing look and feel. -Instructions for using it are in AutoMulti.java. - -TestALFGenerator is a tool (a variation of AutoMulti) -that automatically generates an auxiliary look and -feel that you can use to test the Multiplexing look -and feel. The TestALF look and feel implements every -method by printing the message "In the xxx method of -the TextALFYyyUI class." and, except in the case of -createUI, returning something meaningless (since, -except in the case of createUI, the return value is -ignored). - -TestALFLookAndFeel.java is the only non-auto-generated -file for the TestALF L&F. If you specify a package -argument to TestALFGenerator, you'll have to change -the code in TestALFLookAndFeel.java to reflect the -package name. - -To test any application with the TestALF, make sure the -compiled TestALF classes are in the class path. Then add -this to the /lib/swing.properties file (which -you'll probably have to create): - -swing.auxiliarylaf=TestALFLookAndFeel - -E.g., if you're running SwingSet2 against your solaris -build, then you'd create/edit the swing.properties file -in /build/solaris-sparc/lib. - -Then run any app. You'll see lots of thrilling "In the -Xxxx method of the Yyy class" messages. If you get anything -else (especially an exception), then you've found a bug. -Probably in the default look and feel. - diff --git a/make/tools/src/build/tools/automulti/TestALFGenerator.java b/make/tools/src/build/tools/automulti/TestALFGenerator.java deleted file mode 100644 index 9b07dbc40485bb06ecce52cdf5ee7b2a12837efc..0000000000000000000000000000000000000000 --- a/make/tools/src/build/tools/automulti/TestALFGenerator.java +++ /dev/null @@ -1,401 +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 build.tools.automulti; - -import java.lang.reflect.*; -import java.util.*; -import java.io.*; - -/** - * Automatically generates an auxiliary look and feel to be - * used for testing the Multiplexing look and feel. - *

- * To use, type 'java TestALFGenerator []' where - * is the directory containing the source for Swing's UI classes. - * is an optional argument that specifies the package - * of the TestALF classes. If it's omitted, the classes are in - * the default package. - * For example: - * - *

- * ../../../../build/solaris-sparc/bin/java TestALFGenerator ../../../../src/share/classes/javax/swing/plaf com.myco.myalaf
- * 
- * - * TestALFGenerator will scour the plaf directory for *UI.java files and - * generate TestALF*UI.java files. - *

- * NOTE: This tool depends upon the existence of and on the - * compiled classes from being somewhere in the class path. - * - * @author Willie Walker - */ -public class TestALFGenerator { - static String importLines; - static String packageName; - static String classPrefix = "TestALF"; - - /** - * A silly list of parameter names to use. Skips "i" because we use - * it as a 'for' loop counter. If you want to get fancy, please feel - * to change how parameter names are obtained. This will break if - * someone decides to create a UI method that takes more than 8 - * parameters. Which one is a bug (this breaking or having a method - * with more than eight parameters) is a subjective thing. - */ - public static String[] paramNames = {"a","b","c","d","e","f","g","h"}; - - /** - * Removes the package names (e.g., javax.swing) from the name. - */ - public static String unqualifyName(String name) { - StringTokenizer parser = new StringTokenizer(name,"."); - String unqualifiedName = null; - while (parser.hasMoreTokens()) { - unqualifiedName = parser.nextToken(); - } - return removeDollars(unqualifiedName); - } - - /** - * Strips the extension from the filename. - */ - public static String stripExtension(String name) { - StringTokenizer parser = new StringTokenizer(name,"."); - return parser.nextToken(); - } - - /** - * Adds some spaces. - */ - public static void indent(StringBuffer s, int i) { - while (i > 0) { - s.append(" "); - i--; - } - } - - /** - * Spits out all the beginning stuff. - */ - public static StringBuffer createPreamble(String prefixName) { - StringBuffer s = new StringBuffer(); - s.append("/*\n"); - s.append(" *\n"); - s.append(" * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.\n"); - s.append(" * \n"); - s.append(" * This software is the proprietary information of Sun Microsystems, Inc. \n"); - s.append(" * Use is subject to license terms.\n"); - s.append(" * \n"); - s.append(" */\n"); - if (packageName != null) { - s.append("package " + packageName + ";\n"); - s.append("\n"); - } - return s; - } - - /** - * Replaces 'Xxx$Yyy' with "Xxx'. Used by addImport because you - * can't import nested classes directly. - */ - public static String removeNestedClassName(String s) { - int dollarPosition = s.indexOf('$'); - - if (dollarPosition >= 0) { // s contains '$' - StringBuffer sb = new StringBuffer(s); - sb.setLength(dollarPosition); - return sb.toString(); - } else { // no '$' - return s; - } - } - - /** - * Replaces '$' with ".'. Needed for printing inner class names - * for argument and return types. - */ - public static String removeDollars(String s) { - int dollarPosition = s.indexOf('$'); - - if (dollarPosition >= 0) { // s contains '$' - StringBuffer sb = new StringBuffer(s); - while (dollarPosition >= 0) { - //XXX: will there ever be more than one '$'? - sb.replace(dollarPosition, dollarPosition+1, "."); - dollarPosition = sb.indexOf("$", dollarPosition); - } - return sb.toString(); - } else { // no $ - return s; - } - } - - /** - * Adds an import line to the String. - */ - public static void addImport(String s, Class theClass) { - if (!theClass.isPrimitive() && (theClass != Object.class)) { - String className = removeNestedClassName(theClass.getName()); - String importLine = new String("import " + className + ";\n"); - if (importLines.indexOf(importLine) == -1) { - importLines += importLine; - } - } - } - - /** - * Spits out the class header information. - */ - public static void addHeader(StringBuffer s, String className) { - s.append("/**\n"); - s.append(" * An auxiliary UI for " + className + "s.\n"); - s.append(" * \n"); - s.append(" *

This file was automatically generated by TestALFGenerator.\n"); - s.append(" *\n"); - s.append(" * @author Otto Multey\n"); // Get it? I crack myself up. - s.append(" */\n"); - s.append("public class " + classPrefix + className + " extends " + className + " {\n"); - s.append("\n"); - } - - /** - * Prints out the code for a method. - */ - public static void addMethod(StringBuffer s, Method m, String origName, String className) { - - // Get the method name and the return type. Be a little careful about arrays. - // - String methodName = unqualifyName(m.getName()); - String returnType; - - if (!m.getReturnType().isArray()) { - returnType = unqualifyName(m.getReturnType().toString()); - addImport(importLines,m.getReturnType()); - } else { - returnType = unqualifyName(m.getReturnType().getComponentType().toString()) - + "[]"; - addImport(importLines,m.getReturnType().getComponentType()); - } - - // Print the javadoc - // - s.append("\n"); - - if (methodName.equals("createUI")) { - s.append(" /**\n"); - s.append(" * Returns a UI object for this component.\n"); - s.append(" */\n"); - } else { - s.append(" /**\n"); - s.append(" * Prints a message saying this method has been invoked.\n"); - s.append(" */\n"); - } - - // Print the method signature - // - s.append(" public"); - if (Modifier.isStatic(m.getModifiers())) { - s.append(" static"); - } - s.append(" " + returnType); - s.append(" " + methodName); - s.append("("); - - Class[] params = m.getParameterTypes(); - Class temp; - String braces; - for (int i = 0; i < params.length; i++) { - if (i > 0) { - s.append(", "); - } - temp = params[i]; - braces = new String(""); - while (temp.isArray()) { - braces += "[]"; - temp = temp.getComponentType(); - } - s.append(unqualifyName(temp.getName()) + braces + " " + paramNames[i]); - addImport(importLines,temp); - } - s.append(")"); - - // Don't forget about exceptions - // - Class exceptions[] = m.getExceptionTypes(); - String throwsString = new String(""); - - if (exceptions.length > 0) { - s.append("\n"); - indent(s,12); - s.append("throws "); - for (int i = 0; i < exceptions.length; i++) { - if (i > 0) { - s.append(", "); - } - s.append(unqualifyName(exceptions[i].getName())); - addImport(importLines,exceptions[i]); - } - } - s.append(throwsString + " {\n"); - - // Now print out the contents of the method. - indent(s,8); - s.append("System.out.println(\"In the " + methodName - + " method of the " - + classPrefix + origName + " class.\");\n"); - if (methodName.equals("createUI")) { - indent(s,8); - s.append("return ui;\n"); - } else { - // If we have to return something, do so. - if (!returnType.equals("void")) { - Class rType = m.getReturnType(); - indent(s,8); - if (!rType.isPrimitive()) { - s.append("return null;\n"); - } else if (rType == Boolean.TYPE) { - s.append("return false;\n"); - } else if (rType == Character.TYPE) { - s.append("return '0';\n"); - } else { // byte, short, int, long, float, or double - s.append("return 0;\n"); - } - } - } - - indent(s,4); - s.append("}\n"); - } - - /** - * Takes a plaf class name (e.g., "MenuUI") and generates the corresponding - * TestALF UI Java source code (e.g., "TestALFMenuUI.java"). - */ - public static void generateFile(String prefixName, String className) { - try { - FileOutputStream fos; - PrintWriter outFile; - - importLines = new String(); - importLines += new String("import java.util.Vector;\n"); - - StringBuffer body = new StringBuffer(); - Class wee = Class.forName(prefixName + ".swing.plaf." + className); - String weeName = unqualifyName(wee.getName()); - String thisClassName = classPrefix + className; - addImport(importLines,wee); - - // Declare and initialize the shared UI object. - body.append("\n"); - body.append("////////////////////\n"); - body.append("// Shared UI object\n"); - body.append("////////////////////\n"); - body.append("private final static " + thisClassName - + " ui = new " + thisClassName + "();\n"); - - while (!weeName.equals("Object")) { - body.append("\n"); - body.append("////////////////////\n"); - body.append("// " + weeName + " methods\n"); - body.append("////////////////////\n"); - Method[] methods = wee.getDeclaredMethods(); - for (int i=0; i < methods.length; i++) { - if (Modifier.isPublic(methods[i].getModifiers())) { - addMethod(body,methods[i],className,weeName); - } - } - wee = wee.getSuperclass(); - weeName = unqualifyName(wee.getName()); - addImport(importLines,wee); - } - - fos = new FileOutputStream(classPrefix + className + ".java"); - outFile = new PrintWriter(fos); - StringBuffer outText = createPreamble(prefixName); - outText.append(importLines.toString() + "\n"); - addHeader(outText,className); - outText.append(body.toString()); - outText.append("}\n"); - outFile.write(outText.toString()); - outFile.flush(); - outFile.close(); - } catch (Exception e) { - System.err.println(e); - } - } - - /** - * D'Oh! Something bad happened. - */ - public static void usage(String s) throws IOException { - System.err.println("Usage: java TestALFGenerator []"); - throw new IllegalArgumentException(s); - } - - /** - * Takes the plaf directory name and generates the TestALF UI - * source code. - */ - public static void main(String[] args) throws IOException { - - if (args.length < 1) { - usage(""); - } - - String dirName = args[0]; - File dir = new File(dirName); - if (!dir.isDirectory()) { - System.err.println("No such directory: " + dirName); - usage(""); - } - - if (args.length > 1) { - packageName = args[1]; - } - - String plafUIs[] = dir.list(new UIJavaFilter()); - for (int i = 0; i < plafUIs.length; i++) { - generateFile("javax",stripExtension(plafUIs[i])); - } - } -} - -/** - * Only accepts file names of the form *UI.java. The one exception - * is not accepting ComponentUI.java because we don't need to generate - * a TestALF class for it. - */ -class UIJavaFilter implements FilenameFilter { - public boolean accept(File dir, String name) { - if (name.equals("ComponentUI.java")) { - return false; - } else if (name.endsWith("UI.java")) { - return true; - } else { - return false; - } - } -} diff --git a/make/tools/src/build/tools/automulti/TestALFLookAndFeel.java b/make/tools/src/build/tools/automulti/TestALFLookAndFeel.java deleted file mode 100644 index aadab48cac17f96903805f0d909fb8b01a2a5cfe..0000000000000000000000000000000000000000 --- a/make/tools/src/build/tools/automulti/TestALFLookAndFeel.java +++ /dev/null @@ -1,182 +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 com.myco.myalaf; //search for myalaf for other refs to package name - - -package build.tools.automulti; - -import java.util.Vector; -import java.lang.reflect.Method; -import javax.swing.*; -import javax.swing.plaf.*; - -/** - *

An auxiliary look and feel used for testing the Multiplexing - * look and feel. - *

- * - * @see UIManager#addAuxiliaryLookAndFeel - * @see javax.swing.plaf.multi - * - * @author Kathy Walrath - * @author Will Walker - */ -public class TestALFLookAndFeel extends LookAndFeel { - -////////////////////////////// -// LookAndFeel methods -////////////////////////////// - - /** - * Returns a string, suitable for use in menus, - * that identifies this look and feel. - * - * @return a string such as "Test Auxiliary Look and Feel" - */ - public String getName() { - return "Test Auxiliary Look and Feel"; - } - - /** - * Returns a string, suitable for use by applications/services, - * that identifies this look and feel. - * - * @return "TestALF" - */ - public String getID() { - return "TestALF"; - } - - /** - * Returns a one-line description of this look and feel. - * - * @return a descriptive string such as "Allows multiple UI instances per component instance" - */ - public String getDescription() { - return "Allows multiple UI instances per component instance"; - } - - /** - * Returns false; - * this look and feel is not native to any platform. - * - * @return false - */ - public boolean isNativeLookAndFeel() { - return false; - } - - /** - * Returns true; - * every platform permits this look and feel. - * - * @return true - */ - public boolean isSupportedLookAndFeel() { - return true; - } - - /** - * Creates, initializes, and returns - * the look and feel specific defaults. - * For this look and feel, - * the defaults consist solely of - * mappings of UI class IDs - * (such as "ButtonUI") - * to ComponentUI class names - * (such as "com.myco.myalaf.MultiButtonUI"). - * - * @return an initialized UIDefaults object - * @see javax.swing.JComponent#getUIClassID - */ - public UIDefaults getDefaults() { - System.out.println("In the TestALFLookAndFeel getDefaults method."); - UIDefaults table = new TestALFUIDefaults(); - //String prefix = "com.myco.myalaf.TestALF"; - String prefix = "TestALF"; - Object[] uiDefaults = { - "ButtonUI", prefix + "ButtonUI", - "CheckBoxMenuItemUI", prefix + "MenuItemUI", - "CheckBoxUI", prefix + "ButtonUI", - "ColorChooserUI", prefix + "ColorChooserUI", - "ComboBoxUI", prefix + "ComboBoxUI", - "DesktopIconUI", prefix + "DesktopIconUI", - "DesktopPaneUI", prefix + "DesktopPaneUI", - "EditorPaneUI", prefix + "TextUI", - "FileChooserUI", prefix + "FileChooserUI", - "FormattedTextFieldUI", prefix + "TextUI", - "InternalFrameUI", prefix + "InternalFrameUI", - "LabelUI", prefix + "LabelUI", - "ListUI", prefix + "ListUI", - "MenuBarUI", prefix + "MenuBarUI", - "MenuItemUI", prefix + "MenuItemUI", - "MenuUI", prefix + "MenuItemUI", - "OptionPaneUI", prefix + "OptionPaneUI", - "PanelUI", prefix + "PanelUI", - "PasswordFieldUI", prefix + "TextUI", - "PopupMenuSeparatorUI", prefix + "SeparatorUI", - "PopupMenuUI", prefix + "PopupMenuUI", - "ProgressBarUI", prefix + "ProgressBarUI", - "RadioButtonMenuItemUI", prefix + "MenuItemUI", - "RadioButtonUI", prefix + "ButtonUI", - "RootPaneUI", prefix + "RootPaneUI", - "ScrollBarUI", prefix + "ScrollBarUI", - "ScrollPaneUI", prefix + "ScrollPaneUI", - "SeparatorUI", prefix + "SeparatorUI", - "SliderUI", prefix + "SliderUI", - "SpinnerUI", prefix + "SpinnerUI", - "SplitPaneUI", prefix + "SplitPaneUI", - "TabbedPaneUI", prefix + "TabbedPaneUI", - "TableHeaderUI", prefix + "TableHeaderUI", - "TableUI", prefix + "TableUI", - "TextAreaUI", prefix + "TextUI", - "TextFieldUI", prefix + "TextUI", - "TextPaneUI", prefix + "TextUI", - "ToggleButtonUI", prefix + "ButtonUI", - "ToolBarSeparatorUI", prefix + "SeparatorUI", - "ToolBarUI", prefix + "ToolBarUI", - "ToolTipUI", prefix + "ToolTipUI", - "TreeUI", prefix + "TreeUI", - "ViewportUI", prefix + "ViewportUI", - }; - - table.putDefaults(uiDefaults); - return table; - } - -} - -/** - * We want the Test auxiliary look and feel to be quiet and fallback - * gracefully if it cannot find a UI. This class overrides the - * getUIError method of UIDefaults, which is the method that - * emits error messages when it cannot find a UI class in the - * LAF. - */ -class TestALFUIDefaults extends UIDefaults { - protected void getUIError(String msg) { - System.err.println("Test auxiliary L&F: " + msg); - } -} 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..311a8fa61ce3bb5aa3f07d2c2592c1cf50f7de4a 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 @@ -50,11 +50,6 @@ #define JAR_ERROR2 "Error: Unable to access jarfile %s" #define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s" -#define CLS_ERROR1 "Error: Could not find the main class %s.\n" JNI_ERROR -#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s" -#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR -#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR - #define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used" #define CFG_WARN2 "Warning: No leading - on line %d of `%s'" #define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'" diff --git a/src/share/bin/java.c b/src/share/bin/java.c index f7cbcdc95bce46ab467dd1af347b882dd9ac5c95..0feafc1ed41334485e7cb15c92f730acc44dbcc4 100644 --- a/src/share/bin/java.c +++ b/src/share/bin/java.c @@ -102,8 +102,7 @@ static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn); static jstring NewPlatformString(JNIEnv *env, char *s); static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); -static jclass LoadClass(JNIEnv *env, char *name); -static jstring GetMainClassName(JNIEnv *env, char *jarname); +static jclass LoadMainClass(JNIEnv *env, jboolean isJar, char *name); static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); static jboolean AddApplicationOptions(int cpathc, const char **cpathv); @@ -148,7 +147,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; \ @@ -301,6 +300,22 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ } +#define CHECK_EXCEPTION_NULL_LEAVE(e) \ + if ((*env)->ExceptionOccurred(env)) { \ + JLI_ReportExceptionDescription(env); \ + goto leave; \ + } \ + if ((e) == NULL) { \ + JLI_ReportErrorMessage(JNI_ERROR); \ + goto leave; \ + } + +#define CHECK_EXCEPTION_LEAVE(rv) \ + if ((*env)->ExceptionOccurred(env)) { \ + JLI_ReportExceptionDescription(env); \ + ret = (rv); \ + goto leave; \ + } int JNICALL JavaMain(void * _args) @@ -321,22 +336,16 @@ JavaMain(void * _args) int ret = 0; jlong start, end; - /* Initialize the virtual machine */ - 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); - goto leave; - } + CHECK_EXCEPTION_LEAVE(0); if (printVersion) { ret = 0; goto leave; @@ -346,11 +355,7 @@ JavaMain(void * _args) /* If the user specified neither a class name nor a JAR file */ if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { PrintUsage(env, printXUsage); - if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - ret=1; - } + CHECK_EXCEPTION_LEAVE(1); goto leave; } @@ -395,99 +400,25 @@ JavaMain(void * _args) * the environment (and remove these comments). */ if (jarfile != 0) { - mainClassName = GetMainClassName(env, jarfile); - if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } - if (mainClassName == NULL) { - ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); - goto leave; - } - classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); - if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } - mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); - goto leave; - } - (*env)->ReleaseStringUTFChars(env, mainClassName, classname); + mainClass = LoadMainClass(env, JNI_TRUE, jarfile); } else { - mainClassName = NewPlatformString(env, classname); - if (mainClassName == NULL) { - ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); - goto leave; - } - classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); - if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } - mainClass = LoadClass(env, classname); - if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); - goto leave; - } - (*env)->ReleaseStringUTFChars(env, mainClassName, classname); + mainClass = LoadMainClass(env, JNI_FALSE, classname); } + CHECK_EXCEPTION_NULL_LEAVE(mainClass); - /* Get the application's main method */ + /* + * The LoadMainClass not only loads the main class, it will also ensure + * that the main method's signature is correct, therefore further checking + * is not required. The main method is invoked here so that extraneous java + * stacks are not in the application stack trace. + */ mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); - if (mainID == NULL) { - if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - } else { - ReportErrorMessage(CLS_ERROR3); - } - goto leave; - } - - { /* Make sure the main method is public */ - jint mods; - jmethodID mid; - jobject obj = (*env)->ToReflectedMethod(env, mainClass, - mainID, JNI_TRUE); - - if( obj == NULL) { /* exception occurred */ - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } - - mid = - (*env)->GetMethodID(env, - (*env)->GetObjectClass(env, obj), - "getModifiers", "()I"); - if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } - - mods = (*env)->CallIntMethod(env, obj, mid); - if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ - ReportErrorMessage(CLS_ERROR4); - goto leave; - } - } + CHECK_EXCEPTION_NULL_LEAVE(mainID); /* Build argument array */ mainArgs = NewPlatformStringArray(env, argv, argc); - if (mainArgs == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); - goto leave; - } + CHECK_EXCEPTION_NULL_LEAVE(mainArgs); /* Invoke main method. */ (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); @@ -498,20 +429,18 @@ JavaMain(void * _args) */ ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; +leave: /* - * Detach the main thread so that it appears to have ended when + * Always detach the main thread so that it appears to have ended when * the application's main method exits. This will invoke the * uncaught exception handler machinery if main threw an * exception. An uncaught exception handler cannot change the * 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; } - - leave: /* * Wait for all non-daemon threads to end, then destroy the VM. * This will actually create a trivial new Java waiter thread @@ -525,7 +454,6 @@ JavaMain(void * _args) return ret; } - /* * Checks the command line options to find which JVM type was * specified. If no command line option was given for the JVM type, @@ -635,7 +563,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 +573,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 +588,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 +598,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 +807,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 +876,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 +898,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 +968,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 +1008,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 +1071,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; \ } @@ -1159,7 +1087,7 @@ static jstring getPlatformEncoding(JNIEnv *env) { if (propname) { jclass cls; jmethodID mid; - NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System")); + NULL_CHECK0 (cls = FindBootStrapClass(env, "java/lang/System")); NULL_CHECK0 (mid = (*env)->GetStaticMethodID( env, cls, "getProperty", @@ -1174,7 +1102,7 @@ static jstring getPlatformEncoding(JNIEnv *env) { static jboolean isEncodingSupported(JNIEnv *env, jstring enc) { jclass cls; jmethodID mid; - NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset")); + NULL_CHECK0 (cls = FindBootStrapClass(env, "java/nio/charset/Charset")); NULL_CHECK0 (mid = (*env)->GetStaticMethodID( env, cls, "isSupported", @@ -1203,8 +1131,8 @@ NewPlatformString(JNIEnv *env, char *s) jstring str = 0; (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); if (!(*env)->ExceptionOccurred(env)) { + NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String")); if (isEncodingSupported(env, enc) == JNI_TRUE) { - NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "", "([BLjava/lang/String;)V")); str = (*env)->NewObject(env, cls, mid, ary, enc); @@ -1215,7 +1143,6 @@ NewPlatformString(JNIEnv *env, char *s) the encoding name, in which the StringCoding class will pickup the iso-8859-1 as the fallback converter for us. */ - NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "", "([B)V")); str = (*env)->NewObject(env, cls, mid, ary); @@ -1238,7 +1165,7 @@ NewPlatformStringArray(JNIEnv *env, char **strv, int strc) jarray ary; int i; - NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); + NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String")); NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0)); for (i = 0; i < strc; i++) { jstring str = NewPlatformString(env, *strv++); @@ -1250,25 +1177,26 @@ NewPlatformStringArray(JNIEnv *env, char **strv, int strc) } /* - * Loads a class, convert the '.' to '/'. + * Loads a class and verifies that the main class is present and it is ok to + * call it for more details refer to the java implementation. */ static jclass -LoadClass(JNIEnv *env, char *name) +LoadMainClass(JNIEnv *env, jboolean isJar, char *name) { - char *buf = JLI_MemAlloc(JLI_StrLen(name) + 1); - char *s = buf, *t = name, c; jclass cls; + jmethodID mid; + jstring str; + jobject result; jlong start, end; - if (JLI_IsTraceLauncher()) + if (JLI_IsTraceLauncher()) { start = CounterGet(); - - do { - c = *t++; - *s++ = (c == '.') ? '/' : c; - } while (c != '\0'); - cls = (*env)->FindClass(env, buf); - JLI_MemFree(buf); + } + NULL_CHECK0(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper")); + NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain", + "(ZZLjava/lang/String;)Ljava/lang/Object;")); + str = (*env)->NewStringUTF(env, name); + result = (*env)->CallStaticObjectMethod(env, cls, mid, JNI_TRUE, isJar, str); if (JLI_IsTraceLauncher()) { end = CounterGet(); @@ -1277,49 +1205,9 @@ LoadClass(JNIEnv *env, char *name) printf("----_JAVA_LAUNCHER_DEBUG----\n"); } - return cls; -} - - -/* - * Returns the main class name for the specified jar file. - */ -static jstring -GetMainClassName(JNIEnv *env, char *jarname) -{ -#define MAIN_CLASS "Main-Class" - jclass cls; - jmethodID mid; - jobject jar, man, attr; - jstring str, result = 0; - - NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile")); - NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "", - "(Ljava/lang/String;)V")); - NULL_CHECK0(str = NewPlatformString(env, jarname)); - NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str)); - NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest", - "()Ljava/util/jar/Manifest;")); - man = (*env)->CallObjectMethod(env, jar, mid); - if (man != 0) { - NULL_CHECK0(mid = (*env)->GetMethodID(env, - (*env)->GetObjectClass(env, man), - "getMainAttributes", - "()Ljava/util/jar/Attributes;")); - attr = (*env)->CallObjectMethod(env, man, mid); - if (attr != 0) { - NULL_CHECK0(mid = (*env)->GetMethodID(env, - (*env)->GetObjectClass(env, attr), - "getValue", - "(Ljava/lang/String;)Ljava/lang/String;")); - NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS)); - result = (*env)->CallObjectMethod(env, attr, mid, str); - } - } - return result; + return (jclass)result; } - /* * For tools, convert command line args thus: * javac -cp foo:foo/"*" -J-ms32m ... @@ -1351,7 +1239,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 +1306,7 @@ AddApplicationOptions(int cpathc, const char **cpathv) } if (!GetApplicationHome(home, sizeof(home))) { - ReportErrorMessage(CFG_ERROR5); + JLI_ReportErrorMessage(CFG_ERROR5); return JNI_FALSE; } @@ -1522,7 +1410,7 @@ PrintJavaVersion(JNIEnv *env, jboolean extraLF) jclass ver; jmethodID print; - NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version")); + NULL_CHECK(ver = FindBootStrapClass(env, "sun/misc/Version")); NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, (extraLF == JNI_TRUE) ? "println" : "print", @@ -1534,7 +1422,7 @@ PrintJavaVersion(JNIEnv *env, jboolean extraLF) } /* - * Prints default usage or the Xusage message, see sun.launcher.LauncherHelp.java + * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java */ static void PrintUsage(JNIEnv* env, jboolean doXUsage) @@ -1544,7 +1432,7 @@ PrintUsage(JNIEnv* env, jboolean doXUsage) jstring jprogname, vm1, vm2; int i; - NULL_CHECK(cls = (*env)->FindClass(env, "sun/launcher/LauncherHelp")); + NULL_CHECK(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper")); if (doXUsage) { @@ -1691,7 +1579,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 +1591,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 +1599,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 +1615,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 +1635,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 +1644,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 +1907,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..fe039cdcc88452d2562c88e475e3478309432f79 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(); @@ -184,4 +180,16 @@ static int ContinueInNewThread(InvocationFunctions* ifn, int argc, char** argv, */ void InitLauncher(jboolean javaw); +/* + * This allows for finding classes from the VM's bootstrap class loader directly, + * FindClass uses the application class loader internally, this will cause + * unnecessary searching of the classpath for the required classes. + * + */ +typedef jclass (JNICALL FindClassFromBootLoader_t(JNIEnv *env, + const char *name, + jboolean init, + jobject loader, + jboolean throwError)); +jclass FindBootStrapClass(JNIEnv *env, const char *classname); #endif /* _JAVA_H_ */ diff --git a/src/share/classes/com/sun/beans/WeakCache.java b/src/share/classes/com/sun/beans/WeakCache.java new file mode 100644 index 0000000000000000000000000000000000000000..461c48e1fd3c7a55ae104262ee13f14c2c0b2a06 --- /dev/null +++ b/src/share/classes/com/sun/beans/WeakCache.java @@ -0,0 +1,84 @@ +/* + * 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.beans; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +import java.util.Map; +import java.util.WeakHashMap; + +/** + * A hashtable-based cache with weak keys and weak values. + * An entry in the map will be automatically removed + * when its key is no longer in the ordinary use. + * A value will be automatically removed as well + * when it is no longer in the ordinary use. + * + * @since 1.7 + * + * @author Sergey A. Malenkov + */ +public final class WeakCache { + private final Map> map = new WeakHashMap>(); + + /** + * Returns a value to which the specified {@code key} is mapped, + * or {@code null} if this map contains no mapping for the {@code key}. + * + * @param key the key whose associated value is returned + * @return a value to which the specified {@code key} is mapped + */ + public V get(K key) { + Reference reference = this.map.get(key); + if (reference == null) { + return null; + } + V value = reference.get(); + if (value == null) { + this.map.remove(key); + } + return value; + } + + /** + * Associates the specified {@code value} with the specified {@code key}. + * Removes the mapping for the specified {@code key} from this cache + * if it is present and the specified {@code value} is {@code null}. + * If the cache previously contained a mapping for the {@code key}, + * the old value is replaced by the specified {@code value}. + * + * @param key the key with which the specified value is associated + * @param value the value to be associated with the specified key + */ + public void put(K key, V value) { + if (value != null) { + this.map.put(key, new WeakReference(value)); + } + else { + this.map.remove(key); + } + } +} diff --git a/src/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/share/classes/com/sun/java/swing/SwingUtilities3.java new file mode 100644 index 0000000000000000000000000000000000000000..28d9e8af6ec91a8ed0b07d4db36d84c4823b4b48 --- /dev/null +++ b/src/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -0,0 +1,178 @@ +/* + * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.java.swing; + +import sun.awt.EventQueueDelegate; +import sun.awt.AppContext; +import java.util.Map; +import java.util.concurrent.Callable; +import java.awt.AWTEvent; +import java.awt.EventQueue; +import java.awt.Component; +import javax.swing.JComponent; +import javax.swing.RepaintManager; + +/** + * A collection of utility methods for Swing. + *

+ * WARNING: While this class is public, it should not be treated as + * public API and its API may change in incompatable ways between dot dot + * releases and even patch releases. You should not rely on this class even + * existing. + * + * This is a second part of sun.swing.SwingUtilities2. It is required + * to provide services for JavaFX applets. + * + */ +public class SwingUtilities3 { + /** + * The {@code clientProperty} key for delegate {@code RepaintManager} + */ + private static final Object DELEGATE_REPAINT_MANAGER_KEY = + new StringBuilder("DelegateRepaintManagerKey"); + + /** + * Registers delegate RepaintManager for {@code JComponent}. + */ + public static void setDelegateRepaintManager(JComponent component, + RepaintManager repaintManager) { + /* setting up flag in AppContext to speed up lookups in case + * there are no delegate RepaintManagers used. + */ + AppContext.getAppContext().put(DELEGATE_REPAINT_MANAGER_KEY, + Boolean.TRUE); + + component.putClientProperty(DELEGATE_REPAINT_MANAGER_KEY, + repaintManager); + } + + /** + * Returns delegate {@code RepaintManager} for {@code component} hierarchy. + */ + public static RepaintManager getDelegateRepaintManager(Component + component) { + RepaintManager delegate = null; + if (Boolean.TRUE == AppContext.getAppContext().get( + DELEGATE_REPAINT_MANAGER_KEY)) { + while (delegate == null && component != null) { + while (component != null + && ! (component instanceof JComponent)) { + component = component.getParent(); + } + if (component != null) { + delegate = (RepaintManager) + ((JComponent) component) + .getClientProperty(DELEGATE_REPAINT_MANAGER_KEY); + component = component.getParent(); + } + + } + } + return delegate; + } + + /* + * We use maps to avoid reflection. Hopefully it should perform better + * this way. + */ + public static void setEventQueueDelegate( + Map> map) { + EventQueueDelegate.setDelegate(new EventQueueDelegateFromMap(map)); + } + + private static class EventQueueDelegateFromMap + implements EventQueueDelegate.Delegate { + private final AWTEvent[] afterDispatchEventArgument; + private final Object[] afterDispatchHandleArgument; + private final Callable afterDispatchCallable; + + private final AWTEvent[] beforeDispatchEventArgument; + private final Callable beforeDispatchCallable; + + private final EventQueue[] getNextEventEventQueueArgument; + private final Callable getNextEventCallable; + + @SuppressWarnings("unchecked") + public EventQueueDelegateFromMap(Map> objectMap) { + Map methodMap = objectMap.get("afterDispatch"); + afterDispatchEventArgument = (AWTEvent[]) methodMap.get("event"); + afterDispatchHandleArgument = (Object[]) methodMap.get("handle"); + afterDispatchCallable = (Callable) methodMap.get("method"); + + methodMap = objectMap.get("beforeDispatch"); + beforeDispatchEventArgument = (AWTEvent[]) methodMap.get("event"); + beforeDispatchCallable = (Callable) methodMap.get("method"); + + methodMap = objectMap.get("getNextEvent"); + getNextEventEventQueueArgument = + (EventQueue[]) methodMap.get("eventQueue"); + getNextEventCallable = (Callable) methodMap.get("method"); + } + + @Override + public void afterDispatch(AWTEvent event, Object handle) throws InterruptedException { + afterDispatchEventArgument[0] = event; + afterDispatchHandleArgument[0] = handle; + try { + afterDispatchCallable.call(); + } catch (InterruptedException e) { + throw e; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Object beforeDispatch(AWTEvent event) throws InterruptedException { + beforeDispatchEventArgument[0] = event; + try { + return beforeDispatchCallable.call(); + } catch (InterruptedException e) { + throw e; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public AWTEvent getNextEvent(EventQueue eventQueue) throws InterruptedException { + getNextEventEventQueueArgument[0] = eventQueue; + try { + return getNextEventCallable.call(); + } catch (InterruptedException e) { + throw e; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java b/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java index 9ae2d940443c4ceff9ffaaf9b2ff3b1155d7e1cf..c70d889f4535da033a06f194e4d89b5e82101d20 100644 --- a/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java +++ b/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java @@ -442,7 +442,10 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements } if (updateModel) { - getColorSelectionModel().setSelectedColor(color); + ColorSelectionModel model = getColorSelectionModel(); + if (model != null) { + model.setSelectedColor(color); + } } triangle.setColor(hue, saturation, brightness); diff --git a/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java b/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java index 14d974b03142fe583100d8bc5f014624596501ab..a3eada90d84606d2c89bc72158c8861e4f52b24b 100644 --- a/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java +++ b/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java @@ -770,33 +770,56 @@ class Metacity implements SynthConstants { JComponent maximizeButton = findChild(titlePane, "InternalFrameTitlePane.maximizeButton"); JComponent closeButton = findChild(titlePane, "InternalFrameTitlePane.closeButton"); - int buttonGap = 0; - Insets button_border = (Insets)gm.get("button_border"); Dimension buttonDim = calculateButtonSize(titlePane); - int x = getInt("left_titlebar_edge"); int y = (button_border != null) ? button_border.top : 0; + if (titlePaneParent.getComponentOrientation().isLeftToRight()) { + int x = getInt("left_titlebar_edge"); - menuButton.setBounds(x, y, buttonDim.width, buttonDim.height); + menuButton.setBounds(x, y, buttonDim.width, buttonDim.height); - x = w - buttonDim.width - getInt("right_titlebar_edge"); - if (button_border != null) { - x -= button_border.right; - } + x = w - buttonDim.width - getInt("right_titlebar_edge"); + if (button_border != null) { + x -= button_border.right; + } - if (frame.isClosable()) { - closeButton.setBounds(x, y, buttonDim.width, buttonDim.height); - x -= (buttonDim.width + buttonGap); - } + if (frame.isClosable()) { + closeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + x -= buttonDim.width; + } - if (frame.isMaximizable()) { - maximizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); - x -= (buttonDim.width + buttonGap); - } + if (frame.isMaximizable()) { + maximizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + x -= buttonDim.width; + } - if (frame.isIconifiable()) { - minimizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + if (frame.isIconifiable()) { + minimizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + } + } else { + int x = w - buttonDim.width - getInt("right_titlebar_edge"); + + menuButton.setBounds(x, y, buttonDim.width, buttonDim.height); + + x = getInt("left_titlebar_edge"); + if (button_border != null) { + x += button_border.left; + } + + if (frame.isClosable()) { + closeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + x += buttonDim.width; + } + + if (frame.isMaximizable()) { + maximizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + x += buttonDim.width; + } + + if (frame.isIconifiable()) { + minimizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); + } } } } // end TitlePaneLayout @@ -973,10 +996,8 @@ class Metacity implements SynthConstants { String title = jif.getTitle(); if (title != null) { FontMetrics fm = SwingUtilities2.getFontMetrics(jif, g); - if (jif.getComponentOrientation().isLeftToRight()) { - title = SwingUtilities2.clipStringIfNecessary(jif, fm, title, - calculateTitleTextWidth(g, jif)); - } + title = SwingUtilities2.clipStringIfNecessary(jif, fm, title, + calculateTitleArea(jif).width); g.setColor(color); SwingUtilities2.drawString(jif, g, title, x, y + fm.getAscent()); } @@ -1010,9 +1031,10 @@ class Metacity implements SynthConstants { JComponent titlePane = findChild(jif, "InternalFrame.northPane"); Dimension buttonDim = calculateButtonSize(titlePane); Insets title_border = (Insets)frameGeometry.get("title_border"); - Rectangle r = new Rectangle(); + Insets button_border = (Insets)getFrameGeometry().get("button_border"); - r.x = getInt("left_titlebar_edge") + buttonDim.width; + Rectangle r = new Rectangle(); + r.x = getInt("left_titlebar_edge"); r.y = 0; r.height = titlePane.getHeight(); if (title_border != null) { @@ -1021,15 +1043,36 @@ class Metacity implements SynthConstants { r.height -= (title_border.top + title_border.bottom); } - r.width = titlePane.getWidth() - r.x - getInt("right_titlebar_edge"); - if (jif.isClosable()) { - r.width -= buttonDim.width; - } - if (jif.isMaximizable()) { - r.width -= buttonDim.width; - } - if (jif.isIconifiable()) { - r.width -= buttonDim.width; + if (titlePane.getParent().getComponentOrientation().isLeftToRight()) { + r.x += buttonDim.width; + if (button_border != null) { + r.x += button_border.left; + } + r.width = titlePane.getWidth() - r.x - getInt("right_titlebar_edge"); + if (jif.isClosable()) { + r.width -= buttonDim.width; + } + if (jif.isMaximizable()) { + r.width -= buttonDim.width; + } + if (jif.isIconifiable()) { + r.width -= buttonDim.width; + } + } else { + if (jif.isClosable()) { + r.x += buttonDim.width; + } + if (jif.isMaximizable()) { + r.x += buttonDim.width; + } + if (jif.isIconifiable()) { + r.x += buttonDim.width; + } + r.width = titlePane.getWidth() - r.x - getInt("right_titlebar_edge") + - buttonDim.width; + if (button_border != null) { + r.x -= button_border.right; + } } if (title_border != null) { r.width -= title_border.right; diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/DesktopProperty.java b/src/share/classes/com/sun/java/swing/plaf/windows/DesktopProperty.java index d7d5c0205d7f6ee2bb07ca42904af69d7bb0baea..139b0db559ba2d4b7dc218a6db985c98269c0548 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/DesktopProperty.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/DesktopProperty.java @@ -49,8 +49,7 @@ public class DesktopProperty implements UIDefaults.ActiveValue { /** * ReferenceQueue of unreferenced WeakPCLs. */ - private static ReferenceQueue queue; - + private static ReferenceQueue queue; /** * PropertyChangeListener attached to the Toolkit. @@ -76,7 +75,7 @@ public class DesktopProperty implements UIDefaults.ActiveValue { static { - queue = new ReferenceQueue(); + queue = new ReferenceQueue(); } /** @@ -117,8 +116,8 @@ public class DesktopProperty implements UIDefaults.ActiveValue { XPStyle.invalidateStyle(); } Frame appFrames[] = Frame.getFrames(); - for (int j=0; j < appFrames.length; j++) { - updateWindowUI(appFrames[j]); + for (Frame appFrame : appFrames) { + updateWindowUI(appFrame); } } @@ -128,8 +127,8 @@ public class DesktopProperty implements UIDefaults.ActiveValue { private static void updateWindowUI(Window window) { SwingUtilities.updateComponentTreeUI(window); Window ownedWins[] = window.getOwnedWindows(); - for (int i=0; i < ownedWins.length; i++) { - updateWindowUI(ownedWins[i]); + for (Window ownedWin : ownedWins) { + updateWindowUI(ownedWin); } } @@ -270,13 +269,13 @@ public class DesktopProperty implements UIDefaults.ActiveValue { * is handled via a WeakReference so as not to pin down the * DesktopProperty. */ - private static class WeakPCL extends WeakReference + private static class WeakPCL extends WeakReference implements PropertyChangeListener { private Toolkit kit; private String key; private LookAndFeel laf; - WeakPCL(Object target, Toolkit kit, String key, LookAndFeel laf) { + WeakPCL(DesktopProperty target, Toolkit kit, String key, LookAndFeel laf) { super(target, queue); this.kit = kit; this.key = key; @@ -284,7 +283,7 @@ public class DesktopProperty implements UIDefaults.ActiveValue { } public void propertyChange(PropertyChangeEvent pce) { - DesktopProperty property = (DesktopProperty)get(); + DesktopProperty property = get(); if (property == null || laf != UIManager.getLookAndFeel()) { // The property was GC'ed, we're no longer interested in diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java index e27ac218e113b6f37908e7e9c8a2f00e15c44c78..20d87d015aa1e185c96427346fce5416e5669d5d 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java @@ -96,7 +96,7 @@ public class WindowsDesktopManager extends DefaultDesktopManager } } catch (PropertyVetoException e) {} if (f != currentFrame) { - currentFrameRef = new WeakReference(f); + currentFrameRef = new WeakReference(f); } } diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java index 43d840b1d6f520e3fe48d9b9e793294c591e33ea..e0fb203e0d32783172cddbafcd64e0187e085154 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java @@ -983,7 +983,7 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { } else if (s.equals("componentOrientation")) { ComponentOrientation o = (ComponentOrientation)e.getNewValue(); JFileChooser cc = (JFileChooser)e.getSource(); - if (o != (ComponentOrientation)e.getOldValue()) { + if (o != e.getOldValue()) { cc.applyComponentOrientation(o); } } else if (s.equals("ancestor")) { @@ -1123,7 +1123,7 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { * Data model for a type-face selection combo-box. */ protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { - Vector directories = new Vector(); + Vector directories = new Vector(); int[] depths = null; File selectedDirectory = null; JFileChooser chooser = getFileChooser(); @@ -1162,7 +1162,7 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { // Get the canonical (full) path. This has the side // benefit of removing extraneous chars from the path, // for example /foo/bar/ becomes /foo/bar - File canonical = null; + File canonical; try { canonical = directory.getCanonicalFile(); } catch (IOException e) { @@ -1175,7 +1175,7 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { File sf = useShellFolder ? ShellFolder.getShellFolder(canonical) : canonical; File f = sf; - Vector path = new Vector(10); + Vector path = new Vector(10); do { path.addElement(f); } while ((f = f.getParentFile()) != null); @@ -1183,7 +1183,7 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { int pathCount = path.size(); // Insert chain at appropriate place in vector for (int i = 0; i < pathCount; i++) { - f = (File)path.get(i); + f = path.get(i); if (directories.contains(f)) { int topIndex = directories.indexOf(f); for (int j = i-1; j >= 0; j--) { @@ -1202,12 +1202,12 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { private void calculateDepths() { depths = new int[directories.size()]; for (int i = 0; i < depths.length; i++) { - File dir = (File)directories.get(i); + File dir = directories.get(i); File parent = dir.getParentFile(); depths[i] = 0; if (parent != null) { for (int j = i-1; j >= 0; j--) { - if (parent.equals((File)directories.get(j))) { + if (parent.equals(directories.get(j))) { depths[i] = depths[j] + 1; break; } @@ -1306,8 +1306,8 @@ public class WindowsFileChooserUI extends BasicFileChooserUI { FileFilter currentFilter = getFileChooser().getFileFilter(); boolean found = false; if(currentFilter != null) { - for(int i=0; i < filters.length; i++) { - if(filters[i] == currentFilter) { + for (FileFilter filter : filters) { + if (filter == currentFilter) { found = true; } } diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java index b13033bf76b424e9fde94a00ec5d8449f254156b..5222cd5dd089544277794eb5fab9338c2a076ee1 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java @@ -137,25 +137,46 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { int baseline = (getHeight() + fm.getAscent() - fm.getLeading() - fm.getDescent()) / 2; + Rectangle lastIconBounds = new Rectangle(0, 0, 0, 0); + if (frame.isIconifiable()) { + lastIconBounds = iconButton.getBounds(); + } else if (frame.isMaximizable()) { + lastIconBounds = maxButton.getBounds(); + } else if (frame.isClosable()) { + lastIconBounds = closeButton.getBounds(); + } + int titleX; - Rectangle r = new Rectangle(0, 0, 0, 0); - if (frame.isIconifiable()) r = iconButton.getBounds(); - else if (frame.isMaximizable()) r = maxButton.getBounds(); - else if (frame.isClosable()) r = closeButton.getBounds(); int titleW; - - if(WindowsGraphicsUtils.isLeftToRight(frame) ) { - if (r.x == 0) r.x = frame.getWidth()-frame.getInsets().right; - titleX = systemLabel.getX() + systemLabel.getWidth() + 2; - if (xp != null) { - titleX += 2; - } - titleW = r.x - titleX - 3; - title = getTitle(frame.getTitle(), fm, titleW); + int gap = 2; + if (WindowsGraphicsUtils.isLeftToRight(frame)) { + if (lastIconBounds.x == 0) { // There are no icons + lastIconBounds.x = frame.getWidth() - frame.getInsets().right; + } + titleX = systemLabel.getX() + systemLabel.getWidth() + gap; + if (xp != null) { + titleX += 2; + } + titleW = lastIconBounds.x - titleX - gap; } else { - titleX = systemLabel.getX() - 2 - - SwingUtilities2.stringWidth(frame,fm,title); + if (lastIconBounds.x == 0) { // There are no icons + lastIconBounds.x = frame.getInsets().left; + } + titleW = SwingUtilities2.stringWidth(frame, fm, title); + int minTitleX = lastIconBounds.x + lastIconBounds.width + gap; + if (xp != null) { + minTitleX += 2; + } + int availableWidth = systemLabel.getX() - gap - minTitleX; + if (availableWidth > titleW) { + titleX = systemLabel.getX() - gap - titleW; + } else { + titleX = minTitleX; + titleW = availableWidth; + } } + title = getTitle(frame.getTitle(), fm, titleW); + if (xp != null) { String shadowType = null; if (isSelected) { @@ -258,8 +279,8 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { g.fillRect(0, 0, w, h); } Icon icon = getIcon(); - int iconWidth = 0; - int iconHeight = 0; + int iconWidth; + int iconHeight; if (icon != null && (iconWidth = icon.getIconWidth()) > 0 && (iconHeight = icon.getIconHeight()) > 0) { @@ -304,18 +325,18 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { } protected void addSystemMenuItems(JPopupMenu menu) { - JMenuItem mi = (JMenuItem)menu.add(restoreAction); + JMenuItem mi = menu.add(restoreAction); mi.setMnemonic('R'); - mi = (JMenuItem)menu.add(moveAction); + mi = menu.add(moveAction); mi.setMnemonic('M'); - mi = (JMenuItem)menu.add(sizeAction); + mi = menu.add(sizeAction); mi.setMnemonic('S'); - mi = (JMenuItem)menu.add(iconifyAction); + mi = menu.add(iconifyAction); mi.setMnemonic('n'); - mi = (JMenuItem)menu.add(maximizeAction); + mi = menu.add(maximizeAction); mi.setMnemonic('x'); systemPopupMenu.add(new JSeparator()); - mi = (JMenuItem)menu.add(closeAction); + mi = menu.add(closeAction); mi.setMnemonic('C'); } @@ -441,7 +462,7 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { public class WindowsPropertyChangeHandler extends PropertyChangeHandler { public void propertyChange(PropertyChangeEvent evt) { - String prop = (String)evt.getPropertyName(); + String prop = evt.getPropertyName(); // Update the internal frame icon for the system menu. if (JInternalFrame.FRAME_ICON_PROPERTY.equals(prop) && diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java index b137b38c015c8b13eee6fd3a146f6304748e530c..f79f9d644dbd3968dca6bca95a86f6f70f2c75e8 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java @@ -369,21 +369,21 @@ public class WindowsScrollBarUI extends BasicScrollBarUI { */ private static class Grid { private static final int BUFFER_SIZE = 64; - private static HashMap map; + private static HashMap> map; private BufferedImage image; static { - map = new HashMap(); + map = new HashMap>(); } public static Grid getGrid(Color fg, Color bg) { String key = fg.getRGB() + " " + bg.getRGB(); - WeakReference ref = (WeakReference)map.get(key); - Grid grid = (ref == null) ? null : (Grid)ref.get(); + WeakReference ref = map.get(key); + Grid grid = (ref == null) ? null : ref.get(); if (grid == null) { grid = new Grid(fg, bg); - map.put(key, new WeakReference(grid)); + map.put(key, new WeakReference(grid)); } return grid; } diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java index 54d21e8f00d349608d68fb589deda27d28981640..b781caa3cfc63607aae33bf958faf3a6e6cdc2fa 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java @@ -53,13 +53,13 @@ public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { * Keys to use for forward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusForwardTraversalKeys; + private static Set managingFocusForwardTraversalKeys; /** * Keys to use for backward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusBackwardTraversalKeys; + private static Set managingFocusBackwardTraversalKeys; private boolean contentOpaque = true; @@ -69,13 +69,13 @@ public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { // focus forward traversal key if (managingFocusForwardTraversalKeys==null) { - managingFocusForwardTraversalKeys = new HashSet(); + managingFocusForwardTraversalKeys = new HashSet(); managingFocusForwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); } tabPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, managingFocusForwardTraversalKeys); // focus backward traversal key if (managingFocusBackwardTraversalKeys==null) { - managingFocusBackwardTraversalKeys = new HashSet(); + managingFocusBackwardTraversalKeys = new HashSet(); managingFocusBackwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK)); } tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, managingFocusBackwardTraversalKeys); diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java index e2217e0f35a31ab54391c8d5df880727a3c6f698..0f2b39d893769148ef33d520e9724663c02e532d 100644 --- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java @@ -124,7 +124,7 @@ public class WindowsTableHeaderUI extends BasicTableHeaderUI { setIcon(null); sortIcon = null; SortOrder sortOrder = - getColumnSortOrder(header.getTable(), column); + getColumnSortOrder(table, column); if (sortOrder != null) { switch (sortOrder) { case ASCENDING: 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/share/classes/com/sun/jmx/event/EventClientFactory.java b/src/share/classes/com/sun/jmx/event/EventClientFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3cab63ccdc686a5daf8003cd854e573539b88b7b --- /dev/null +++ b/src/share/classes/com/sun/jmx/event/EventClientFactory.java @@ -0,0 +1,46 @@ +/* + * 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 javax.management.event.*; + +/** + * Implemented by objects which are using an {@link EventClient} to + * subscribe for Notifications. + * + */ +public interface EventClientFactory { + /** + * 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/Introspector.java b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index 1554444f508f3f2b20c4fc5c1d359cea2d4a2a57..52783fd5a6043b2b8cda001615fc6ddd3af47d63 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -228,7 +228,15 @@ public class Introspector { // to generate the appropriate exception. } if (c != null) { - MXBeanMappingFactory factory = MXBeanMappingFactory.forInterface(c); + MXBeanMappingFactory factory; + try { + factory = MXBeanMappingFactory.forInterface(c); + } catch (IllegalArgumentException e) { + NotCompliantMBeanException ncmbe = + new NotCompliantMBeanException(e.getMessage()); + ncmbe.initCause(e); + throw ncmbe; + } return new MXBeanSupport(mbean, c, factory); } checkCompliance(mbeanClass); 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/MXBeanSupport.java b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java index 594a97334815181220f4edfe70529bcf8421c133..7a9c5d2e7a882902fc298073d4f98ef839826d1c 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java @@ -36,7 +36,6 @@ import javax.management.MBeanServer; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.openmbean.MXBeanMappingFactory; -import javax.management.openmbean.MXBeanMappingFactoryClass; /** * Base class for MXBeans. 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/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..32cca2d2dc429c001118bba8f9ede81db06e5d5f --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.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 javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input & results... + *

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

+ * + * @since 1.7 + */ +class IdentityProcessor extends RewritingProcessor { + + + /** Creates a new instance of SerialRewritingProcessor */ + public IdentityProcessor() { + } + + @Override + public T rewriteOutput(T result) { + return result; + } + + @Override + public T rewriteInput(T input) { + return input; + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return sourceName; + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return sourceMoi; + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return targetName; + } + +} diff --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 0)) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " - + Description); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " + Description); } else { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS - + ": For unknown purposes"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": For unknown purposes"); } try { ResourceResolver.register(JAVACLASS); @@ -359,13 +351,11 @@ public final class Init { "DESCRIPTION"); if ((Description != null) && (Description.length() > 0)) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " - + Description); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " + Description); } else { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS - + ": For unknown purposes"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": For unknown purposes"); } KeyResolver.register(JAVACLASS); @@ -376,8 +366,8 @@ public final class Init { if (tag.equals("PrefixMappings")){ XX_configure_reg_prefixes_start = System.currentTimeMillis(); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now I try to bind prefixes:"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now I try to bind prefixes:"); Element[] nl = XMLUtils.selectNodes(el.getFirstChild(), CONF_NS,"PrefixMapping"); @@ -386,8 +376,8 @@ public final class Init { "namespace"); String prefix = nl[i].getAttributeNS(null, "prefix"); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now I try to bind " + prefix + " to " + namespace); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now I try to bind " + prefix + " to " + namespace); com.sun.org.apache.xml.internal.security.utils.ElementProxy .setDefaultPrefix(namespace, prefix); } @@ -398,19 +388,19 @@ public final class Init { long XX_init_end = System.currentTimeMillis(); //J- - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XX_init " + ((int)(XX_init_end - XX_init_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_prng " + ((int)(XX_prng_end - XX_prng_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_parsing " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_i18n " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_c14n " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_jcemapper " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyInfo " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyResolver " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_prefixes " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_sigalgos " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_transforms " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms"); + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "XX_init " + ((int)(XX_init_end - XX_init_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_prng " + ((int)(XX_prng_end - XX_prng_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_parsing " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_i18n " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_c14n " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_jcemapper " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyInfo " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyResolver " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_prefixes " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_sigalgos " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_transforms " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms"); } } catch (Exception e) { log.log(java.util.logging.Level.SEVERE, "Bad: ", e); diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java index 2f326f0a7a44dd38d18301cde2622e46d8f90e16..62fd0fe4964cf16b2a33fbde643867e95edb03b0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java @@ -24,7 +24,7 @@ package com.sun.org.apache.xml.internal.security.algorithms; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; -import com.sun.org.apache.xml.internal.security.utils.ElementProxy; +import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -33,11 +33,7 @@ import org.w3c.dom.Element; * The Algorithm class which stores the Algorithm URI as a string. * */ -public abstract class Algorithm extends ElementProxy { - - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(Algorithm.class.getName()); +public abstract class Algorithm extends SignatureElementProxy { /** * @@ -79,7 +75,7 @@ public abstract class Algorithm extends ElementProxy { */ protected void setAlgorithmURI(String algorithmURI) { - if ((this._state == MODE_CREATE) && (algorithmURI != null)) { + if ( (algorithmURI != null)) { this._constructionElement.setAttributeNS(null, Constants._ATT_ALGORITHM, algorithmURI); } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java index 475d4591bcdd95c0b3f7c16c0e37562b7e242300..7a239135920e75b4ee92eef2dad536d653e2b009 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java @@ -35,7 +35,7 @@ import org.w3c.dom.Element; /** * This class maps algorithm identifier URIs to JAVA JCE class names. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class JCEMapper { @@ -45,9 +45,9 @@ public class JCEMapper { - private static Map uriToJCEName = new HashMap(); + private static Map uriToJCEName; - private static Map algorithmsMap = new HashMap(); + private static Map algorithmsMap; private static String providerName = null; /** @@ -63,6 +63,8 @@ public class JCEMapper { static void loadAlgorithms( Element algorithmsEl) { Element[] algorithms = XMLUtils.selectNodes(algorithmsEl.getFirstChild(),Init.CONF_NS,"Algorithm"); + uriToJCEName = new HashMap( algorithms.length * 2); + algorithmsMap = new HashMap( algorithms.length * 2); for (int i = 0 ;i < algorithms.length ;i ++) { Element el = algorithms[i]; String id = el.getAttribute("URI"); @@ -70,6 +72,7 @@ public class JCEMapper { uriToJCEName.put(id, jceName); algorithmsMap.put(id, new Algorithm(el)); } + } static Algorithm getAlgorithmMapping(String algoURI) { @@ -84,8 +87,8 @@ public class JCEMapper { * */ public static String translateURItoJCEID(String AlgorithmURI) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); String jceName = (String) uriToJCEName.get(AlgorithmURI); return jceName; @@ -100,8 +103,8 @@ public class JCEMapper { * */ public static String getAlgorithmClassFromURI(String AlgorithmURI) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); return ((Algorithm) algorithmsMap.get(AlgorithmURI)).algorithmClass; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java index 805d061a2e6dd5b6cfa37a67f2b5d517a059f1a5..fa62ef3518f750316b7bb817335a8c5d49b3d3f4 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java @@ -20,10 +20,10 @@ */ package com.sun.org.apache.xml.internal.security.algorithms; - - import java.security.MessageDigest; import java.security.NoSuchProviderException; +import java.util.HashMap; +import java.util.Map; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Constants; @@ -41,11 +41,6 @@ import org.w3c.dom.Document; */ public class MessageDigestAlgorithm extends Algorithm { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger( - MessageDigestAlgorithm.class.getName()); - /** Message Digest - NOT RECOMMENDED MD5*/ public static final String ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5 = Constants.MoreAlgorithmsSpecNS + "md5"; /** Digest - Required SHA1*/ @@ -76,6 +71,12 @@ public class MessageDigestAlgorithm extends Algorithm { this.algorithm = messageDigest; } + static ThreadLocal instances=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + /** * Factory method for constructing a message digest algorithm by name. * @@ -86,8 +87,15 @@ public class MessageDigestAlgorithm extends Algorithm { */ public static MessageDigestAlgorithm getInstance( Document doc, String algorithmURI) throws XMLSignatureException { + MessageDigest md = getDigestInstance(algorithmURI); + return new MessageDigestAlgorithm(doc, md, algorithmURI); + } - String algorithmID = JCEMapper.translateURItoJCEID(algorithmURI); +private static MessageDigest getDigestInstance(String algorithmURI) throws XMLSignatureException { + MessageDigest result=(MessageDigest) ((Map)instances.get()).get(algorithmURI); + if (result!=null) + return result; + String algorithmID = JCEMapper.translateURItoJCEID(algorithmURI); if (algorithmID == null) { Object[] exArgs = { algorithmURI }; @@ -113,8 +121,9 @@ public class MessageDigestAlgorithm extends Algorithm { throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); } - return new MessageDigestAlgorithm(doc, md, algorithmURI); - } + ((Map)instances.get()).put(algorithmURI, md); + return md; +} /** * Returns the actual {@link java.security.MessageDigest} algorithm object diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java index 3ebb782a3d22d70933d8155829a3c95486008264..567df3cbbd12c6fd17f8a944ec23e8c410e349ec 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java @@ -25,6 +25,7 @@ import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.HashMap; +import java.util.Map; import com.sun.org.apache.xml.internal.security.algorithms.implementations.IntegrityHmac; import com.sun.org.apache.xml.internal.security.exceptions.AlgorithmAlreadyRegisteredException; @@ -52,9 +53,35 @@ public class SignatureAlgorithm extends Algorithm { /** All available algorithm classes are registered here */ static HashMap _algorithmHash = null; + static ThreadLocal instancesSigning=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + + static ThreadLocal instancesVerify=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + + static ThreadLocal keysSigning=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + static ThreadLocal keysVerify=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; +// boolean isForSigning=false; + /** Field _signatureAlgorithm */ protected SignatureAlgorithmSpi _signatureAlgorithm = null; + private String algorithmURI; + /** * Constructor SignatureAlgorithm * @@ -64,18 +91,49 @@ public class SignatureAlgorithm extends Algorithm { */ public SignatureAlgorithm(Document doc, String algorithmURI) throws XMLSecurityException { - super(doc, algorithmURI); + this.algorithmURI = algorithmURI; + } - try { + + private void initializeAlgorithm(boolean isForSigning) throws XMLSignatureException { + if (_signatureAlgorithm!=null) { + return; + } + _signatureAlgorithm=isForSigning ? getInstanceForSigning(algorithmURI) : getInstanceForVerify(algorithmURI); + this._signatureAlgorithm + .engineGetContextFromElement(this._constructionElement); + } + private static SignatureAlgorithmSpi getInstanceForSigning(String algorithmURI) throws XMLSignatureException { + SignatureAlgorithmSpi result=(SignatureAlgorithmSpi) ((Map)instancesSigning.get()).get(algorithmURI); + if (result!=null) { + result.reset(); + return result; + } + result=buildSigner(algorithmURI, result); + ((Map)instancesSigning.get()).put(algorithmURI,result); + return result; + } + private static SignatureAlgorithmSpi getInstanceForVerify(String algorithmURI) throws XMLSignatureException { + SignatureAlgorithmSpi result=(SignatureAlgorithmSpi) ((Map)instancesVerify.get()).get(algorithmURI); + if (result!=null) { + result.reset(); + return result; + } + result=buildSigner(algorithmURI, result); + ((Map)instancesVerify.get()).put(algorithmURI,result); + return result; + } + + private static SignatureAlgorithmSpi buildSigner(String algorithmURI, SignatureAlgorithmSpi result) throws XMLSignatureException { + try { Class implementingClass = SignatureAlgorithm.getImplementingClass(algorithmURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" + implementingClass + "\""); - - this._signatureAlgorithm = - (SignatureAlgorithmSpi) implementingClass.newInstance(); + result=(SignatureAlgorithmSpi) implementingClass.newInstance(); + return result; } catch (IllegalAccessException ex) { Object exArgs[] = { algorithmURI, ex.getMessage() }; @@ -92,7 +150,7 @@ public class SignatureAlgorithm extends Algorithm { throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex); } - } +} /** * Constructor SignatureAlgorithm @@ -107,7 +165,8 @@ public class SignatureAlgorithm extends Algorithm { throws XMLSecurityException { this(doc, algorithmURI); - + this.algorithmURI=algorithmURI; + initializeAlgorithm(true); this._signatureAlgorithm.engineSetHMACOutputLength(HMACOutputLength); ((IntegrityHmac)this._signatureAlgorithm) .engineAddContextToElement(this._constructionElement); @@ -124,37 +183,7 @@ public class SignatureAlgorithm extends Algorithm { throws XMLSecurityException { super(element, BaseURI); - - String algorithmURI = this.getURI(); - - try { - Class implementingClass = - SignatureAlgorithm.getImplementingClass(algorithmURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" - + implementingClass + "\""); - - this._signatureAlgorithm = - (SignatureAlgorithmSpi) implementingClass.newInstance(); - - this._signatureAlgorithm - .engineGetContextFromElement(this._constructionElement); - } catch (IllegalAccessException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } catch (InstantiationException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } catch (NullPointerException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } + algorithmURI = this.getURI(); } /** @@ -175,7 +204,12 @@ public class SignatureAlgorithm extends Algorithm { * @return the result of the {@link java.security.Signature#getAlgorithm} method */ public String getJCEAlgorithmString() { - return this._signatureAlgorithm.engineGetJCEAlgorithmString(); + try { + return getInstanceForVerify(algorithmURI).engineGetJCEAlgorithmString(); + } catch (XMLSignatureException e) { + //Ignore. + return null; + } } /** @@ -184,7 +218,11 @@ public class SignatureAlgorithm extends Algorithm { * @return The Provider of this Signature Alogrithm */ public String getJCEProviderName() { - return this._signatureAlgorithm.engineGetJCEProviderName(); + try { + return getInstanceForVerify(algorithmURI).engineGetJCEProviderName(); + } catch (XMLSignatureException e) { + return null; + } } /** @@ -231,7 +269,13 @@ public class SignatureAlgorithm extends Algorithm { * @throws XMLSignatureException */ public void initSign(Key signingKey) throws XMLSignatureException { - this._signatureAlgorithm.engineInitSign(signingKey); + initializeAlgorithm(true); + Map map=(Map)keysSigning.get(); + if (map.get(this.algorithmURI)==signingKey) { + return; + } + map.put(this.algorithmURI,signingKey); + this._signatureAlgorithm.engineInitSign(signingKey); } /** @@ -244,6 +288,7 @@ public class SignatureAlgorithm extends Algorithm { */ public void initSign(Key signingKey, SecureRandom secureRandom) throws XMLSignatureException { + initializeAlgorithm(true); this._signatureAlgorithm.engineInitSign(signingKey, secureRandom); } @@ -258,6 +303,7 @@ public class SignatureAlgorithm extends Algorithm { public void initSign( Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) throws XMLSignatureException { + initializeAlgorithm(true); this._signatureAlgorithm.engineInitSign(signingKey, algorithmParameterSpec); } @@ -282,7 +328,13 @@ public class SignatureAlgorithm extends Algorithm { * @throws XMLSignatureException */ public void initVerify(Key verificationKey) throws XMLSignatureException { - this._signatureAlgorithm.engineInitVerify(verificationKey); + initializeAlgorithm(false); + Map map=(Map)keysVerify.get(); + if (map.get(this.algorithmURI)==verificationKey) { + return; + } + map.put(this.algorithmURI,verificationKey); + this._signatureAlgorithm.engineInitVerify(verificationKey); } /** @@ -320,7 +372,7 @@ public class SignatureAlgorithm extends Algorithm { .getLogger(SignatureAlgorithm.class.getName()); } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Init() called"); + log.log(java.util.logging.Level.FINE, "Init() called"); if (!SignatureAlgorithm._alreadyInitialized) { SignatureAlgorithm._algorithmHash = new HashMap(10); @@ -340,8 +392,8 @@ public class SignatureAlgorithm extends Algorithm { throws AlgorithmAlreadyRegisteredException,XMLSignatureException { { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass); // are we already registered? Class registeredClassClass = diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java index 1ae46db4bb35d5aa54d8487e7774b97a4ee0ae54..c47be7e2c0dd0a437476a65501b93746fd5245a2 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java @@ -20,27 +20,20 @@ */ package com.sun.org.apache.xml.internal.security.algorithms; - - import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; -import org.w3c.dom.Document; import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SignatureAlgorithmSpi.class.getName()); - /** * Returns the URI representation of Transformation algorithm * @@ -167,20 +160,6 @@ public abstract class SignatureAlgorithmSpi { protected abstract void engineSetParameter(AlgorithmParameterSpec params) throws XMLSignatureException; - /** Field _doc */ - Document _doc = null; - - /** - * Method engineSetDocument - * - * @param doc - */ - protected void engineSetDocument(Document doc) { - this._doc = doc; - } - - /** Field _constructionElement */ - Element _constructionElement = null; /** * Method engineGetContextFromElement @@ -188,7 +167,6 @@ public abstract class SignatureAlgorithmSpi { * @param element */ protected void engineGetContextFromElement(Element element) { - this._constructionElement = element; } /** @@ -199,4 +177,7 @@ public abstract class SignatureAlgorithmSpi { */ protected abstract void engineSetHMACOutputLength(int HMACOutputLength) throws XMLSignatureException; + + public void reset() { + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java index 0e89024bf265d7c1e302af34ef0777edc41cf88f..d3495bb567f4ed2402a7876e0ee91b4a22e12f2d 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java @@ -45,7 +45,7 @@ import org.w3c.dom.Text; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { @@ -74,8 +74,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { public IntegrityHmac() throws XMLSignatureException { String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created IntegrityHmacSHA1 using " + algorithmID); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created IntegrityHmacSHA1 using " + algorithmID); try { this._macAlgorithm = Mac.getInstance(algorithmID); @@ -99,6 +99,10 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { throw new XMLSignatureException("empty"); } + public void reset() { + _HMACOutputLength=0; + } + /** * Proxy method for {@link java.security.Signature#verify(byte[])} * which is executed on the internal {@link java.security.Signature} object. @@ -145,7 +149,20 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { try { this._macAlgorithm.init(secretKey); } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); + // reinstantiate Mac object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Mac mac = this._macAlgorithm; + try { + this._macAlgorithm = Mac.getInstance + (_macAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous Mac + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Mac:" + e); + } + this._macAlgorithm = mac; + } + throw new XMLSignatureException("empty", ex); } } @@ -323,7 +340,7 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { */ protected String engineGetJCEAlgorithmString() { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "engineGetJCEAlgorithmString()"); + log.log(java.util.logging.Level.FINE, "engineGetJCEAlgorithmString()"); return this._macAlgorithm.getAlgorithm(); } @@ -397,7 +414,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA1 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA1 extends IntegrityHmac { @@ -423,7 +441,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA256 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA256 extends IntegrityHmac { @@ -449,7 +468,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA384 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA384 extends IntegrityHmac { @@ -475,7 +495,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA512 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA512 extends IntegrityHmac { @@ -501,7 +522,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacRIPEMD160 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacRIPEMD160 extends IntegrityHmac { @@ -527,7 +549,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacMD5 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacMD5 extends IntegrityHmac { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java index fde23e8fc880ea4014abcc069c4e7304a3962005..ccc01b01c58e644461f42d9b69c2878de613f417 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java @@ -3,7 +3,7 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2007 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.algorithms.implementations; - - import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -38,329 +36,344 @@ import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi import com.sun.org.apache.xml.internal.security.signature.XMLSignature; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class SignatureBaseRSA extends SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SignatureBaseRSA.class.getName()); + java.util.logging.Logger.getLogger + (SignatureBaseRSA.class.getName()); /** @inheritDoc */ - public abstract String engineGetURI(); + public abstract String engineGetURI(); - /** Field algorithm */ - private java.security.Signature _signatureAlgorithm = null; + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; - /** - * Constructor SignatureRSA - * - * @throws XMLSignatureException - */ - public SignatureBaseRSA() throws XMLSignatureException { + /** + * Constructor SignatureRSA + * + * @throws XMLSignatureException + */ + public SignatureBaseRSA() throws XMLSignatureException { - String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); + String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); - String provider=JCEMapper.getProviderId(); - try { - if (provider==null) { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureRSA using " + algorithmID); + String provider=JCEMapper.getProviderId(); + try { + if (provider==null) { this._signatureAlgorithm = Signature.getInstance(algorithmID); - } else { + } else { this._signatureAlgorithm = Signature.getInstance(algorithmID,provider); - } - } catch (java.security.NoSuchAlgorithmException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** @inheritDoc */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected boolean engineVerify(byte[] signature) + throws XMLSignatureException { + + try { + return this._signatureAlgorithm.verify(signature); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected byte[] engineSign() throws XMLSignatureException { + try { + return this._signatureAlgorithm.sign(); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign + ((PrivateKey) privateKey, secureRandom); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** @inheritDoc */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** @inheritDoc */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException + ("algorithms.HMACOutputLengthOnlyForHMAC"); + } - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); - } catch (NoSuchProviderException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; + /** @inheritDoc */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); + } + + /** + * Class SignatureRSASHA1 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA1 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA1 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA1() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1; + } + } + + /** + * Class SignatureRSASHA256 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA256 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA256 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA256() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256; + } + } + + /** + * Class SignatureRSASHA384 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA384 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA384 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA384() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384; + } + } + + /** + * Class SignatureRSASHA512 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA512 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA512 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA512() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512; + } + } + + /** + * Class SignatureRSARIPEMD160 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSARIPEMD160 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSARIPEMD160 + * + * @throws XMLSignatureException + */ + public SignatureRSARIPEMD160() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160; + } + } + + /** + * Class SignatureRSAMD5 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSAMD5 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSAMD5 + * + * @throws XMLSignatureException + */ + public SignatureRSAMD5() throws XMLSignatureException { + super(); + } - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5; } - } - - /** @inheritDoc */ - protected void engineSetParameter(AlgorithmParameterSpec params) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.setParameter(params); - } catch (InvalidAlgorithmParameterException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected boolean engineVerify(byte[] signature) - throws XMLSignatureException { - - try { - return this._signatureAlgorithm.verify(signature); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitVerify(Key publicKey) throws XMLSignatureException { - - if (!(publicKey instanceof PublicKey)) { - String supplied = publicKey.getClass().getName(); - String needed = PublicKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initVerify((PublicKey) publicKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected byte[] engineSign() throws XMLSignatureException { - - try { - return this._signatureAlgorithm.sign(); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitSign(Key privateKey, SecureRandom secureRandom) - throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey, - secureRandom); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitSign(Key privateKey) throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte[] input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte buf[], int offset, int len) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(buf, offset, len); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected String engineGetJCEAlgorithmString() { - return this._signatureAlgorithm.getAlgorithm(); - } - - /** @inheritDoc */ - protected String engineGetJCEProviderName() { - return this._signatureAlgorithm.getProvider().getName(); - } - - /** @inheritDoc */ - protected void engineSetHMACOutputLength(int HMACOutputLength) - throws XMLSignatureException { - throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); - } - - /** @inheritDoc */ - protected void engineInitSign( - Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) - throws XMLSignatureException { - throw new XMLSignatureException( - "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); - } - - /** - * Class SignatureRSASHA1 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA1 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA1 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA1() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1; - } - } - - /** - * Class SignatureRSASHA256 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA256 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA256 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA256() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256; - } - } - - /** - * Class SignatureRSASHA384 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA384 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA384 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA384() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384; - } - } - - /** - * Class SignatureRSASHA512 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA512 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA512 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA512() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512; - } - } - - /** - * Class SignatureRSARIPEMD160 - * - * @author $Author: raul $ - */ - public static class SignatureRSARIPEMD160 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSARIPEMD160 - * - * @throws XMLSignatureException - */ - public SignatureRSARIPEMD160() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160; - } - } - - /** - * Class SignatureRSAMD5 - * - * @author $Author: raul $ - */ - public static class SignatureRSAMD5 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSAMD5 - * - * @throws XMLSignatureException - */ - public SignatureRSAMD5() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5; - } - } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java index 355579b7e5385ee4a97f324d0a8d1436436a4987..615aa436e462358b457b5d002ba8e52f8b4aa096 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.algorithms.implementations; - - import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -39,342 +37,359 @@ import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Base64; import com.sun.org.apache.xml.internal.security.utils.Constants; - /** * - * @author $Author: vishal $ + * @author $Author: mullan $ */ public class SignatureDSA extends SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(SignatureDSA.class.getName()); - /** Field _URI */ - public static final String _URI = Constants.SignatureSpecNS + "dsa-sha1"; - - /** Field algorithm */ - private java.security.Signature _signatureAlgorithm = null; - - /** - * Method engineGetURI - * - * @inheritDoc - */ - protected String engineGetURI() { - return SignatureDSA._URI; - } - - /** - * Constructor SignatureDSA - * - * @throws XMLSignatureException - */ - public SignatureDSA() throws XMLSignatureException { - - String algorithmID = JCEMapper.translateURItoJCEID(SignatureDSA._URI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); - - try { - this._signatureAlgorithm = Signature.getInstance(algorithmID); - } catch (java.security.NoSuchAlgorithmException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); - } - } - - /** - * @inheritDoc - */ - protected void engineSetParameter(AlgorithmParameterSpec params) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.setParameter(params); - } catch (InvalidAlgorithmParameterException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected boolean engineVerify(byte[] signature) + /** Field _URI */ + public static final String _URI = Constants.SignatureSpecNS + "dsa-sha1"; + + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; + + /** + * Method engineGetURI + * + * @inheritDoc + */ + protected String engineGetURI() { + return SignatureDSA._URI; + } + + /** + * Constructor SignatureDSA + * + * @throws XMLSignatureException + */ + public SignatureDSA() throws XMLSignatureException { + + String algorithmID = JCEMapper.translateURItoJCEID(SignatureDSA._URI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); + + String provider = JCEMapper.getProviderId(); + try { + if (provider == null) { + this._signatureAlgorithm = Signature.getInstance(algorithmID); + } else { + this._signatureAlgorithm = + Signature.getInstance(algorithmID, provider); + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (java.security.NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** + * @inheritDoc + */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected boolean engineVerify(byte[] signature) throws XMLSignatureException { - try { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Called DSA.verify() on " + Base64.encode(signature)); - - byte[] jcebytes = SignatureDSA.convertXMLDSIGtoASN1(signature); - - return this._signatureAlgorithm.verify(jcebytes); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } catch (IOException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitVerify(Key publicKey) throws XMLSignatureException { - - if (!(publicKey instanceof PublicKey)) { - String supplied = publicKey.getClass().getName(); - String needed = PublicKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initVerify((PublicKey) publicKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected byte[] engineSign() throws XMLSignatureException { - - try { - byte jcebytes[] = this._signatureAlgorithm.sign(); - - return SignatureDSA.convertASN1toXMLDSIG(jcebytes); - } catch (IOException ex) { - throw new XMLSignatureException("empty", ex); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + try { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Called DSA.verify() on " + Base64.encode(signature)); + + byte[] jcebytes = SignatureDSA.convertXMLDSIGtoASN1(signature); + + return this._signatureAlgorithm.verify(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected byte[] engineSign() throws XMLSignatureException { + + try { + byte jcebytes[] = this._signatureAlgorithm.sign(); + + return SignatureDSA.convertASN1toXMLDSIG(jcebytes); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) throws XMLSignatureException { - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey, + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey, secureRandom); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitSign(Key privateKey) throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte[] input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte buf[], int offset, int len) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(buf, offset, len); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * Method engineGetJCEAlgorithmString - * - * @inheritDoc - */ - protected String engineGetJCEAlgorithmString() { - return this._signatureAlgorithm.getAlgorithm(); - } - - /** - * Method engineGetJCEProviderName - * - * @inheritDoc - */ - protected String engineGetJCEProviderName() { - return this._signatureAlgorithm.getProvider().getName(); - } - - - /** - * Converts an ASN.1 DSA value to a XML Signature DSA Value. - * - * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value - * pairs; the XML Signature requires the core BigInteger values. - * - * @param asn1Bytes - * @return the decode bytes - * - * @throws IOException - * @see 6.4.1 DSA - */ - private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * Method engineGetJCEAlgorithmString + * + * @inheritDoc + */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** + * Method engineGetJCEProviderName + * + * @inheritDoc + */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** + * Converts an ASN.1 DSA value to a XML Signature DSA Value. + * + * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param asn1Bytes + * @return the decode bytes + * + * @throws IOException + * @see 6.4.1 DSA + */ + private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) throws IOException { - byte rLength = asn1Bytes[3]; - int i; + byte rLength = asn1Bytes[3]; + int i; - for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); + for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); - byte sLength = asn1Bytes[5 + rLength]; - int j; + byte sLength = asn1Bytes[5 + rLength]; + int j; - for (j = sLength; + for (j = sLength; (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--); - if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) + if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) || (asn1Bytes[2] != 2) || (i > 20) || (asn1Bytes[4 + rLength] != 2) || (j > 20)) { - throw new IOException("Invalid ASN.1 format of DSA signature"); - } - byte xmldsigBytes[] = new byte[40]; + throw new IOException("Invalid ASN.1 format of DSA signature"); + } + byte xmldsigBytes[] = new byte[40]; - System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 20 - i, + System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 20 - i, i); - System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, + System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, 40 - j, j); - return xmldsigBytes; - } - - /** - * Converts a XML Signature DSA Value to an ASN.1 DSA value. - * - * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value - * pairs; the XML Signature requires the core BigInteger values. - * - * @param xmldsigBytes - * @return the encoded ASN.1 bytes - * - * @throws IOException - * @see 6.4.1 DSA - */ - private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) + return xmldsigBytes; + } + + /** + * Converts a XML Signature DSA Value to an ASN.1 DSA value. + * + * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param xmldsigBytes + * @return the encoded ASN.1 bytes + * + * @throws IOException + * @see 6.4.1 DSA + */ + private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) throws IOException { - if (xmldsigBytes.length != 40) { - throw new IOException("Invalid XMLDSIG format of DSA signature"); - } + if (xmldsigBytes.length != 40) { + throw new IOException("Invalid XMLDSIG format of DSA signature"); + } - int i; + int i; - for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--); + for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--); - int j = i; + int j = i; - if (xmldsigBytes[20 - i] < 0) { + if (xmldsigBytes[20 - i] < 0) { j += 1; - } - - int k; - - for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--); - - int l = k; - - if (xmldsigBytes[40 - k] < 0) { - l += 1; - } - - byte asn1Bytes[] = new byte[6 + j + l]; - - asn1Bytes[0] = 48; - asn1Bytes[1] = (byte) (4 + j + l); - asn1Bytes[2] = 2; - asn1Bytes[3] = (byte) j; - - System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i); - - asn1Bytes[4 + j] = 2; - asn1Bytes[5 + j] = (byte) l; - - System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k); - - return asn1Bytes; - } - - /** - * Method engineSetHMACOutputLength - * - * @param HMACOutputLength - * @throws XMLSignatureException - */ - protected void engineSetHMACOutputLength(int HMACOutputLength) - throws XMLSignatureException { - throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); - } - - /** - * Method engineInitSign - * - * @param signingKey - * @param algorithmParameterSpec - * @throws XMLSignatureException - */ - protected void engineInitSign( - Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) - throws XMLSignatureException { - throw new XMLSignatureException( - "algorithms.CannotUseAlgorithmParameterSpecOnDSA"); - } + } + + int k; + + for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--); + + int l = k; + + if (xmldsigBytes[40 - k] < 0) { + l += 1; + } + + byte asn1Bytes[] = new byte[6 + j + l]; + + asn1Bytes[0] = 48; + asn1Bytes[1] = (byte) (4 + j + l); + asn1Bytes[2] = 2; + asn1Bytes[3] = (byte) j; + + System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i); + + asn1Bytes[4 + j] = 2; + asn1Bytes[5 + j] = (byte) l; + + System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k); + + return asn1Bytes; + } + + /** + * Method engineSetHMACOutputLength + * + * @param HMACOutputLength + * @throws XMLSignatureException + */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.HMACOutputLengthOnlyForHMAC"); + } + + /** + * Method engineInitSign + * + * @param signingKey + * @param algorithmParameterSpec + * @throws XMLSignatureException + */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnDSA"); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java new file mode 100644 index 0000000000000000000000000000000000000000..18fdffe28fb5533db2fbef538505501d98983141 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java @@ -0,0 +1,384 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * 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. + * + */ +package com.sun.org.apache.xml.internal.security.algorithms.implementations; + + + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; + +import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper; +import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi; +import com.sun.org.apache.xml.internal.security.signature.XMLSignature; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; +import com.sun.org.apache.xml.internal.security.utils.Base64; + + +/** + * + * @author $Author: mullan $ + */ +public abstract class SignatureECDSA extends SignatureAlgorithmSpi { + + /** {@link java.util.logging} logging facility */ + static java.util.logging.Logger log = + java.util.logging.Logger.getLogger(SignatureECDSA.class.getName()); + + /** @inheritDoc */ + public abstract String engineGetURI(); + + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; + + /** + * Converts an ASN.1 ECDSA value to a XML Signature ECDSA Value. + * + * The JAVA JCE ECDSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param asn1Bytes + * @return the decode bytes + * + * @throws IOException + * @see 6.4.1 DSA + * @see 3.3. ECDSA Signatures + */ + private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) + throws IOException { + + byte rLength = asn1Bytes[3]; + int i; + + for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); + + byte sLength = asn1Bytes[5 + rLength]; + int j; + + for (j = sLength; + (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--); + + if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) + || (asn1Bytes[2] != 2) || (i > 24) + || (asn1Bytes[4 + rLength] != 2) || (j > 24)) { + throw new IOException("Invalid ASN.1 format of ECDSA signature"); + } + byte xmldsigBytes[] = new byte[48]; + + System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 24 - i, + i); + System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, + 48 - j, j); + + return xmldsigBytes; + } + + /** + * Converts a XML Signature ECDSA Value to an ASN.1 DSA value. + * + * The JAVA JCE ECDSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param xmldsigBytes + * @return the encoded ASN.1 bytes + * + * @throws IOException + * @see 6.4.1 DSA + * @see 3.3. ECDSA Signatures + */ + private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) + throws IOException { + + if (xmldsigBytes.length != 48) { + throw new IOException("Invalid XMLDSIG format of ECDSA signature"); + } + + int i; + + for (i = 24; (i > 0) && (xmldsigBytes[24 - i] == 0); i--); + + int j = i; + + if (xmldsigBytes[24 - i] < 0) { + j += 1; + } + + int k; + + for (k = 24; (k > 0) && (xmldsigBytes[48 - k] == 0); k--); + + int l = k; + + if (xmldsigBytes[48 - k] < 0) { + l += 1; + } + + byte asn1Bytes[] = new byte[6 + j + l]; + + asn1Bytes[0] = 48; + asn1Bytes[1] = (byte) (4 + j + l); + asn1Bytes[2] = 2; + asn1Bytes[3] = (byte) j; + + System.arraycopy(xmldsigBytes, 24 - i, asn1Bytes, (4 + j) - i, i); + + asn1Bytes[4 + j] = 2; + asn1Bytes[5 + j] = (byte) l; + + System.arraycopy(xmldsigBytes, 48 - k, asn1Bytes, (6 + j + l) - k, k); + + return asn1Bytes; + } + + /** + * Constructor SignatureRSA + * + * @throws XMLSignatureException + */ + public SignatureECDSA() throws XMLSignatureException { + + String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); + + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureECDSA using " + algorithmID); + String provider=JCEMapper.getProviderId(); + try { + if (provider==null) { + this._signatureAlgorithm = Signature.getInstance(algorithmID); + } else { + this._signatureAlgorithm = Signature.getInstance(algorithmID,provider); + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, + ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, + ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** @inheritDoc */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected boolean engineVerify(byte[] signature) + throws XMLSignatureException { + + try { + byte[] jcebytes = SignatureECDSA.convertXMLDSIGtoASN1(signature); + + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Called ECDSA.verify() on " + Base64.encode(signature)); + + return this._signatureAlgorithm.verify(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected byte[] engineSign() throws XMLSignatureException { + + try { + byte jcebytes[] = this._signatureAlgorithm.sign(); + + return SignatureECDSA.convertASN1toXMLDSIG(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey, + secureRandom); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte input) throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** @inheritDoc */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** @inheritDoc */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); + } + + /** @inheritDoc */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); + } + + /** + * Class SignatureRSASHA1 + * + * @author $Author: mullan $ + * @version $Revision: 1.2 $ + */ + public static class SignatureECDSASHA1 extends SignatureECDSA { + + /** + * Constructor SignatureRSASHA1 + * + * @throws XMLSignatureException + */ + public SignatureECDSASHA1() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1; + } + } + +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java index 732334c36562e12bd133eb2c1ed50e972a1f8e8e..36c98cfe7900fa70a430ac01ca123e17f6962610 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java index eb7cb6cad0103150cfa2382588a2ffc6da1f556b..a4181233d6029ceaa3fb52b84574be5d5535b274 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java @@ -3,7 +3,7 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2008 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.c14n; - - import java.io.ByteArrayInputStream; import java.io.OutputStream; import java.util.HashMap; @@ -37,318 +35,326 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; - /** - * * * @author Christian Geuer-Pollmann */ public class Canonicalizer { - //J- - /** The output encoding of canonicalized data */ - public static final String ENCODING = "UTF8"; + /** The output encoding of canonicalized data */ + public static final String ENCODING = "UTF8"; + + /** + * XPath Expresion for selecting every node and continuous comments joined + * in only one node + */ + public static final String XPATH_C14N_WITH_COMMENTS_SINGLE_NODE = + "(.//. | .//@* | .//namespace::*)"; + + /** + * The URL defined in XML-SEC Rec for inclusive c14n without comments. + */ + public static final String ALGO_ID_C14N_OMIT_COMMENTS = + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + /** + * The URL defined in XML-SEC Rec for inclusive c14n with comments. + */ + public static final String ALGO_ID_C14N_WITH_COMMENTS = + ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; + /** + * The URL defined in XML-SEC Rec for exclusive c14n without comments. + */ + public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = + "http://www.w3.org/2001/10/xml-exc-c14n#"; + /** + * The URL defined in XML-SEC Rec for exclusive c14n with comments. + */ + public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = + ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; + /** + * The URI for inclusive c14n 1.1 without comments. + */ + public static final String ALGO_ID_C14N11_OMIT_COMMENTS = + "http://www.w3.org/2006/12/xml-c14n11"; + /** + * The URI for inclusive c14n 1.1 with comments. + */ + public static final String ALGO_ID_C14N11_WITH_COMMENTS = + ALGO_ID_C14N11_OMIT_COMMENTS + "#WithComments"; + + static boolean _alreadyInitialized = false; + static Map _canonicalizerHash = null; + protected CanonicalizerSpi canonicalizerSpi = null; - /** - * XPath Expresion for selecting every node and continuos comments joined in only one node + /** + * Method init + * */ - public static final String XPATH_C14N_WITH_COMMENTS_SINGLE_NODE = "(.//. | .//@* | .//namespace::*)"; + public static void init() { + if (!Canonicalizer._alreadyInitialized) { + Canonicalizer._canonicalizerHash = new HashMap(10); + Canonicalizer._alreadyInitialized = true; + } + } - /** - * The URL defined in XML-SEC Rec for inclusive c14n without comments. + /** + * Constructor Canonicalizer + * + * @param algorithmURI + * @throws InvalidCanonicalizerException */ - public static final String ALGO_ID_C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; - /** - * The URL defined in XML-SEC Rec for inclusive c14n with comments. - */ - public static final String ALGO_ID_C14N_WITH_COMMENTS = ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; - /** - * The URL defined in XML-SEC Rec for exclusive c14n without comments. - */ - public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#"; - /** - * The URL defined in XML-SEC Rec for exclusive c14n with comments. - */ - public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; - - static boolean _alreadyInitialized = false; - static Map _canonicalizerHash = null; - - protected CanonicalizerSpi canonicalizerSpi = null; - //J+ - - /** - * Method init - * - */ - public static void init() { - - if (!Canonicalizer._alreadyInitialized) { - Canonicalizer._canonicalizerHash = new HashMap(10); - Canonicalizer._alreadyInitialized = true; - } - } - - /** - * Constructor Canonicalizer - * - * @param algorithmURI - * @throws InvalidCanonicalizerException - */ - private Canonicalizer(String algorithmURI) + private Canonicalizer(String algorithmURI) throws InvalidCanonicalizerException { - try { - Class implementingClass = getImplementingClass(algorithmURI); - - this.canonicalizerSpi = - (CanonicalizerSpi) implementingClass.newInstance(); - this.canonicalizerSpi.reset=true; - } catch (Exception e) { - Object exArgs[] = { algorithmURI }; - - throw new InvalidCanonicalizerException( - "signature.Canonicalizer.UnknownCanonicalizer", exArgs); - } - } - - /** - * Method getInstance - * - * @param algorithmURI - * @return a Conicicalizer instance ready for the job - * @throws InvalidCanonicalizerException - */ - public static final Canonicalizer getInstance(String algorithmURI) + try { + Class implementingClass = getImplementingClass(algorithmURI); + + this.canonicalizerSpi = + (CanonicalizerSpi) implementingClass.newInstance(); + this.canonicalizerSpi.reset=true; + } catch (Exception e) { + Object exArgs[] = { algorithmURI }; + + throw new InvalidCanonicalizerException( + "signature.Canonicalizer.UnknownCanonicalizer", exArgs); + } + } + + /** + * Method getInstance + * + * @param algorithmURI + * @return a Conicicalizer instance ready for the job + * @throws InvalidCanonicalizerException + */ + public static final Canonicalizer getInstance(String algorithmURI) throws InvalidCanonicalizerException { - Canonicalizer c14nizer = new Canonicalizer(algorithmURI); + Canonicalizer c14nizer = new Canonicalizer(algorithmURI); - return c14nizer; - } + return c14nizer; + } - /** - * Method register - * - * @param algorithmURI - * @param implementingClass - * @throws AlgorithmAlreadyRegisteredException - */ - public static void register(String algorithmURI, String implementingClass) + /** + * Method register + * + * @param algorithmURI + * @param implementingClass + * @throws AlgorithmAlreadyRegisteredException + */ + public static void register(String algorithmURI, String implementingClass) throws AlgorithmAlreadyRegisteredException { - // check whether URI is already registered - Class registeredClass = getImplementingClass(algorithmURI); + // check whether URI is already registered + Class registeredClass = getImplementingClass(algorithmURI); - if (registeredClass != null) { - Object exArgs[] = { algorithmURI, registeredClass }; + if (registeredClass != null) { + Object exArgs[] = { algorithmURI, registeredClass }; - throw new AlgorithmAlreadyRegisteredException( - "algorithm.alreadyRegistered", exArgs); - } + throw new AlgorithmAlreadyRegisteredException( + "algorithm.alreadyRegistered", exArgs); + } - try { - _canonicalizerHash.put(algorithmURI, Class.forName(implementingClass)); + try { + _canonicalizerHash.put(algorithmURI, Class.forName(implementingClass)); } catch (ClassNotFoundException e) { - throw new RuntimeException("c14n class not found"); + throw new RuntimeException("c14n class not found"); } - } - - /** - * Method getURI - * - * @return the URI defined for this c14n instance. - */ - public final String getURI() { - return this.canonicalizerSpi.engineGetURI(); - } - - /** - * Method getIncludeComments - * - * @return true if the c14n respect the comments. - */ - public boolean getIncludeComments() { - return this.canonicalizerSpi.engineGetIncludeComments(); - } - - /** - * This method tries to canonicalize the given bytes. It's possible to even - * canonicalize non-wellformed sequences if they are well-formed after being - * wrapped with a >a<...>/a<. - * - * @param inputBytes - * @return the result of the conicalization. - * @throws CanonicalizationException - * @throws java.io.IOException - * @throws javax.xml.parsers.ParserConfigurationException - * @throws org.xml.sax.SAXException - */ - public byte[] canonicalize(byte[] inputBytes) + } + + /** + * Method getURI + * + * @return the URI defined for this c14n instance. + */ + public final String getURI() { + return this.canonicalizerSpi.engineGetURI(); + } + + /** + * Method getIncludeComments + * + * @return true if the c14n respect the comments. + */ + public boolean getIncludeComments() { + return this.canonicalizerSpi.engineGetIncludeComments(); + } + + /** + * This method tries to canonicalize the given bytes. It's possible to even + * canonicalize non-wellformed sequences if they are well-formed after being + * wrapped with a >a<...>/a<. + * + * @param inputBytes + * @return the result of the conicalization. + * @throws CanonicalizationException + * @throws java.io.IOException + * @throws javax.xml.parsers.ParserConfigurationException + * @throws org.xml.sax.SAXException + */ + public byte[] canonicalize(byte[] inputBytes) throws javax.xml.parsers.ParserConfigurationException, java.io.IOException, org.xml.sax.SAXException, CanonicalizationException { - ByteArrayInputStream bais = new ByteArrayInputStream(inputBytes); - InputSource in = new InputSource(bais); - DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); - - dfactory.setNamespaceAware(true); - - // needs to validate for ID attribute nomalization - dfactory.setValidating(true); - - DocumentBuilder db = dfactory.newDocumentBuilder(); - - /* - * for some of the test vectors from the specification, - * there has to be a validatin parser for ID attributes, default - * attribute values, NMTOKENS, etc. - * Unfortunaltely, the test vectors do use different DTDs or - * even no DTD. So Xerces 1.3.1 fires many warnings about using - * ErrorHandlers. - * - * Text from the spec: - * - * The input octet stream MUST contain a well-formed XML document, - * but the input need not be validated. However, the attribute - * value normalization and entity reference resolution MUST be - * performed in accordance with the behaviors of a validating - * XML processor. As well, nodes for default attributes (declared - * in the ATTLIST with an AttValue but not specified) are created - * in each element. Thus, the declarations in the document type - * declaration are used to help create the canonical form, even - * though the document type declaration is not retained in the - * canonical form. - * - */ - db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils - .IgnoreAllErrorHandler()); - - Document document = db.parse(in); - byte result[] = this.canonicalizeSubtree(document); - - return result; - } - - /** - * Canonicalizes the subtree rooted by node. - * - * @param node The node to canicalize - * @return the result of the c14n. - * - * @throws CanonicalizationException - */ - public byte[] canonicalizeSubtree(Node node) + ByteArrayInputStream bais = new ByteArrayInputStream(inputBytes); + InputSource in = new InputSource(bais); + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + + dfactory.setNamespaceAware(true); + + // needs to validate for ID attribute nomalization + dfactory.setValidating(true); + + DocumentBuilder db = dfactory.newDocumentBuilder(); + + /* + * for some of the test vectors from the specification, + * there has to be a validatin parser for ID attributes, default + * attribute values, NMTOKENS, etc. + * Unfortunaltely, the test vectors do use different DTDs or + * even no DTD. So Xerces 1.3.1 fires many warnings about using + * ErrorHandlers. + * + * Text from the spec: + * + * The input octet stream MUST contain a well-formed XML document, + * but the input need not be validated. However, the attribute + * value normalization and entity reference resolution MUST be + * performed in accordance with the behaviors of a validating + * XML processor. As well, nodes for default attributes (declared + * in the ATTLIST with an AttValue but not specified) are created + * in each element. Thus, the declarations in the document type + * declaration are used to help create the canonical form, even + * though the document type declaration is not retained in the + * canonical form. + * + */ + db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils + .IgnoreAllErrorHandler()); + + Document document = db.parse(in); + byte result[] = this.canonicalizeSubtree(document); + + return result; + } + + /** + * Canonicalizes the subtree rooted by node. + * + * @param node The node to canicalize + * @return the result of the c14n. + * + * @throws CanonicalizationException + */ + public byte[] canonicalizeSubtree(Node node) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeSubTree(node); - } - - /** - * Canonicalizes the subtree rooted by node. - * - * @param node - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeSubtree(Node node, String inclusiveNamespaces) + return this.canonicalizerSpi.engineCanonicalizeSubTree(node); + } + + /** + * Canonicalizes the subtree rooted by node. + * + * @param node + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeSubtree(Node node, String inclusiveNamespaces) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeSubTree(node, + return this.canonicalizerSpi.engineCanonicalizeSubTree(node, inclusiveNamespaces); - } - - /** - * Canonicalizes an XPath node set. The xpathNodeSet is treated - * as a list of XPath nodes, not as a list of subtrees. - * - * @param xpathNodeSet - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet(NodeList xpathNodeSet) + } + + /** + * Canonicalizes an XPath node set. The xpathNodeSet is treated + * as a list of XPath nodes, not as a list of subtrees. + * + * @param xpathNodeSet + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(NodeList xpathNodeSet) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); - } - - /** - * Canonicalizes an XPath node set. The xpathNodeSet is treated - * as a list of XPath nodes, not as a list of subtrees. - * - * @param xpathNodeSet - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet( + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); + } + + /** + * Canonicalizes an XPath node set. The xpathNodeSet is treated + * as a list of XPath nodes, not as a list of subtrees. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet( NodeList xpathNodeSet, String inclusiveNamespaces) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, inclusiveNamespaces); - } - - /** - * Canonicalizes an XPath node set. - * - * @param xpathNodeSet - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet) + } + + /** + * Canonicalizes an XPath node set. + * + * @param xpathNodeSet + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); - } - - /** - * Canonicalizes an XPath node set. - * - * @param xpathNodeSet - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet( - Set xpathNodeSet, String inclusiveNamespaces) - throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, - inclusiveNamespaces); - } - - /** - * Sets the writter where the cannocalization ends. ByteArrayOutputStream if - * none is setted. - * @param os - */ - public void setWriter(OutputStream os) { - this.canonicalizerSpi.setWriter(os); - } - - /** - * Returns the name of the implementing {@link CanonicalizerSpi} class - * - * @return the name of the implementing {@link CanonicalizerSpi} class - */ - public String getImplementingCanonicalizerClass() { - return this.canonicalizerSpi.getClass().getName(); - } - - /** - * Method getImplementingClass - * - * @param URI - * @return the name of the class that implements the give URI - */ - private static Class getImplementingClass(String URI) { - return (Class) _canonicalizerHash.get(URI); - } - - /** - * Set the canonicalizator behaviour to not reset. - * - */ - public void notReset() { - this.canonicalizerSpi.reset=false; - } + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); + } + + /** + * Canonicalizes an XPath node set. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet, + String inclusiveNamespaces) throws CanonicalizationException { + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, + inclusiveNamespaces); + } + + /** + * Sets the writer where the canonicalization ends. ByteArrayOutputStream + * if none is set. + * @param os + */ + public void setWriter(OutputStream os) { + this.canonicalizerSpi.setWriter(os); + } + + /** + * Returns the name of the implementing {@link CanonicalizerSpi} class + * + * @return the name of the implementing {@link CanonicalizerSpi} class + */ + public String getImplementingCanonicalizerClass() { + return this.canonicalizerSpi.getClass().getName(); + } + + /** + * Method getImplementingClass + * + * @param URI + * @return the name of the class that implements the given URI + */ + private static Class getImplementingClass(String URI) { + return (Class) _canonicalizerHash.get(URI); + } + + /** + * Set the canonicalizer behaviour to not reset. + */ + public void notReset() { + this.canonicalizerSpi.reset = false; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java index 8af3ed88050382964bdf23e08cb4b091549a9d8f..9fb1531b7e910fa002e3373c8aec289c38d4df35 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java index 46fdc660338e01752ad1fbe93dbe5b147298e0e7..802abda2862d10a033e43d2541c4f123ad623693 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,17 +20,17 @@ */ package com.sun.org.apache.xml.internal.security.c14n.helper; - - import com.sun.org.apache.xml.internal.security.utils.Constants; import org.w3c.dom.Attr; - +import java.io.Serializable; +import java.util.Comparator; /** * Compares two attributes based on the C14n specification. * *
      - *
    • Namespace nodes have a lesser document order position than attribute nodes. + *
    • Namespace nodes have a lesser document order position than attribute + * nodes. *
    • An element's namespace nodes are sorted lexicographically by * local name (the default namespace node, if one exists, has no * local name and is therefore lexicographically least). @@ -40,104 +39,89 @@ import org.w3c.dom.Attr; * key (an empty namespace URI is lexicographically least). *
    * - * $todo$ Should we implement java.util.Comparator and import java.util.Arrays to use Arrays.sort(intarray); * @author Christian Geuer-Pollmann */ -public class AttrCompare implements java.util.Comparator { - - private final int ATTR0_BEFORE_ATTR1 = -1; - private final int ATTR1_BEFORE_ATTR0 = 1; - - private final static String XMLNS=Constants.NamespaceSpecNS; - /** - * Compares two attributes based on the C14n specification. - * - *
      - *
    • Namespace nodes have a lesser document order position than attribute nodes. - *
    • An element's namespace nodes are sorted lexicographically by - * local name (the default namespace node, if one exists, has no - * local name and is therefore lexicographically least). - *
    • An element's attribute nodes are sorted lexicographically with - * namespace URI as the primary key and local name as the secondary - * key (an empty namespace URI is lexicographically least). - *
    - * - * @param obj0 casted Attr - * @param obj1 casted Attr - * @return returns a negative integer, zero, or a positive integer as obj0 is less than, equal to, or greater than obj1 - * - */ - public int compare(Object obj0, Object obj1) { - - Attr attr0 = (Attr) obj0; - Attr attr1 = (Attr) obj1; - String namespaceURI0 = attr0.getNamespaceURI(); - String namespaceURI1 = attr1.getNamespaceURI(); - - boolean isNamespaceAttr0 = - XMLNS.equals(namespaceURI0); - boolean isNamespaceAttr1 = - XMLNS.equals(namespaceURI1); - - if (isNamespaceAttr0) { - if (isNamespaceAttr1) { - - // both are namespaces - String localname0 = attr0.getLocalName(); - String localname1 = attr1.getLocalName(); - - if (localname0.equals("xmlns")) { - localname0 = ""; +public class AttrCompare implements Comparator, Serializable { + + private final static long serialVersionUID = -7113259629930576230L; + private final static int ATTR0_BEFORE_ATTR1 = -1; + private final static int ATTR1_BEFORE_ATTR0 = 1; + private final static String XMLNS=Constants.NamespaceSpecNS; + + /** + * Compares two attributes based on the C14n specification. + * + *
      + *
    • Namespace nodes have a lesser document order position than + * attribute nodes. + *
    • An element's namespace nodes are sorted lexicographically by + * local name (the default namespace node, if one exists, has no + * local name and is therefore lexicographically least). + *
    • An element's attribute nodes are sorted lexicographically with + * namespace URI as the primary key and local name as the secondary + * key (an empty namespace URI is lexicographically least). + *
    + * + * @param obj0 casted Attr + * @param obj1 casted Attr + * @return returns a negative integer, zero, or a positive integer as + * obj0 is less than, equal to, or greater than obj1 + * + */ + public int compare(Object obj0, Object obj1) { + + Attr attr0 = (Attr) obj0; + Attr attr1 = (Attr) obj1; + String namespaceURI0 = attr0.getNamespaceURI(); + String namespaceURI1 = attr1.getNamespaceURI(); + + boolean isNamespaceAttr0 = XMLNS==namespaceURI0; + boolean isNamespaceAttr1 = XMLNS==namespaceURI1; + + if (isNamespaceAttr0) { + if (isNamespaceAttr1) { + // both are namespaces + String localname0 = attr0.getLocalName(); + String localname1 = attr1.getLocalName(); + + if (localname0.equals("xmlns")) { + localname0 = ""; + } + + if (localname1.equals("xmlns")) { + localname1 = ""; + } + + return localname0.compareTo(localname1); } + // attr0 is a namespace, attr1 is not + return ATTR0_BEFORE_ATTR1; + } - if (localname1.equals("xmlns")) { - localname1 = ""; - } - - return localname0.compareTo(localname1); - } - // attr0 is a namespace, attr1 is not - return ATTR0_BEFORE_ATTR1; - - } - if (isNamespaceAttr1) { - + if (isNamespaceAttr1) { // attr1 is a namespace, attr0 is not return ATTR1_BEFORE_ATTR0; - } - - // none is a namespae - - if (namespaceURI0 == null) { - if (namespaceURI1 == null) { - /* - String localName0 = attr0.getLocalName(); - String localName1 = attr1.getLocalName(); - return localName0.compareTo(localName1); - */ + } + // none is a namespace + if (namespaceURI0 == null) { + if (namespaceURI1 == null) { String name0 = attr0.getName(); String name1 = attr1.getName(); return name0.compareTo(name1); + } + return ATTR0_BEFORE_ATTR1; } - return ATTR0_BEFORE_ATTR1; - } - if (namespaceURI1 == null) { - return ATTR1_BEFORE_ATTR0; - } - int a = namespaceURI0.compareTo(namespaceURI1); - - if (a != 0) { - return a; - } - /* - String localName0 = ; - String localName1 =;*/ - - return (attr0.getLocalName()) - .compareTo( attr1.getLocalName()); + if (namespaceURI1 == null) { + return ATTR1_BEFORE_ATTR0; + } - } + int a = namespaceURI0.compareTo(namespaceURI1); + if (a != 0) { + return a; + } + return (attr0.getLocalName()).compareTo(attr1.getLocalName()); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java new file mode 100644 index 0000000000000000000000000000000000000000..4790fd890432a907e8c04e470b6aa4106f986cf9 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java @@ -0,0 +1,684 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * 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. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +import java.util.logging.Logger; +import java.util.logging.Logger; +import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; +import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; +import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; + +/** + * Implements + * Canonical XML Version 1.1, a W3C Proposed Recommendation from 29 + * January 2008. + * + * @author Sean Mullan + * @author Raul Benito + * @version $Revision: 1.2 $ + */ +public abstract class Canonicalizer11 extends CanonicalizerBase { + boolean firstCall = true; + final SortedSet result = new TreeSet(COMPARE); + static final String XMLNS_URI = Constants.NamespaceSpecNS; + static final String XML_LANG_URI = Constants.XML_LANG_SPACE_SpecNS; + + static Logger log = Logger.getLogger(Canonicalizer11.class.getName()); + + static class XmlAttrStack { + int currentLevel = 0; + int lastlevel = 0; + XmlsStackElement cur; + static class XmlsStackElement { + int level; + boolean rendered = false; + List nodes = new ArrayList(); + }; + List levels = new ArrayList(); + void push(int level) { + currentLevel = level; + if (currentLevel == -1) + return; + cur = null; + while (lastlevel >= currentLevel) { + levels.remove(levels.size() - 1); + if (levels.size() == 0) { + lastlevel = 0; + return; + } + lastlevel=((XmlsStackElement)levels.get(levels.size()-1)).level; + } + } + void addXmlnsAttr(Attr n) { + if (cur == null) { + cur = new XmlsStackElement(); + cur.level = currentLevel; + levels.add(cur); + lastlevel = currentLevel; + } + cur.nodes.add(n); + } + void getXmlnsAttr(Collection col) { + if (cur == null) { + cur = new XmlsStackElement(); + cur.level = currentLevel; + lastlevel = currentLevel; + levels.add(cur); + } + int size = levels.size() - 2; + boolean parentRendered = false; + XmlsStackElement e = null; + if (size == -1) { + parentRendered = true; + } else { + e = (XmlsStackElement) levels.get(size); + if (e.rendered && e.level+1 == currentLevel) + parentRendered = true; + } + if (parentRendered) { + col.addAll(cur.nodes); + cur.rendered = true; + return; + } + + Map loa = new HashMap(); + List baseAttrs = new ArrayList(); + boolean successiveOmitted = true; + for (;size>=0;size--) { + e = (XmlsStackElement) levels.get(size); + if (e.rendered) { + successiveOmitted = false; + } + Iterator it = e.nodes.iterator(); + while (it.hasNext() && successiveOmitted) { + Attr n = (Attr) it.next(); + if (n.getLocalName().equals("base")) { + if (!e.rendered) { + baseAttrs.add(n); + } + } else if (!loa.containsKey(n.getName())) + loa.put(n.getName(), n); + } + } + if (!baseAttrs.isEmpty()) { + Iterator it = cur.nodes.iterator(); + String base = null; + Attr baseAttr = null; + while (it.hasNext()) { + Attr n = (Attr) it.next(); + if (n.getLocalName().equals("base")) { + base = n.getValue(); + baseAttr = n; + break; + } + } + it = baseAttrs.iterator(); + while (it.hasNext()) { + Attr n = (Attr) it.next(); + if (base == null) { + base = n.getValue(); + baseAttr = n; + } else { + try { + base = joinURI(n.getValue(), base); + } catch (URISyntaxException ue) { + ue.printStackTrace(); + } + } + } + if (base != null && base.length() != 0) { + baseAttr.setValue(base); + col.add(baseAttr); + } + } + + cur.rendered = true; + col.addAll(loa.values()); + } + }; + XmlAttrStack xmlattrStack = new XmlAttrStack(); + + /** + * Constructor Canonicalizer11 + * + * @param includeComments + */ + public Canonicalizer11(boolean includeComments) { + super(includeComments); + } + + /** + * Returns the Attr[]s to be outputted for the given element. + *
    + * The code of this method is a copy of {@link #handleAttributes(Element, + * NameSpaceSymbTable)}, + * whereas it takes into account that subtree-c14n is -- well -- + * subtree-based. + * So if the element in question isRoot of c14n, it's parent is not in the + * node set, as well as all other ancestors. + * + * @param E + * @param ns + * @return the Attr[]s to be outputted + * @throws CanonicalizationException + */ + Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns) + throws CanonicalizationException { + if (!E.hasAttributes() && !firstCall) { + return null; + } + // result will contain the attrs which have to be outputted + final SortedSet result = this.result; + result.clear(); + NamedNodeMap attrs = E.getAttributes(); + int attrsLength = attrs.getLength(); + + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + String NUri = N.getNamespaceURI(); + + if (XMLNS_URI != NUri) { + // It's not a namespace attr node. Add to the result and + // continue. + result.add(N); + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getValue(); + if (XML.equals(NName) + && XML_LANG_URI.equals(NValue)) { + // The default mapping for xml must not be output. + continue; + } + + Node n = ns.addMappingAndRender(NName, NValue, N); + + if (n != null) { + // Render the ns definition + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = {E.getTagName(), NName, N.getNodeValue()}; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } + + if (firstCall) { + // It is the first node of the subtree + // Obtain all the namespaces defined in the parents, and added + // to the output. + ns.getUnrenderedNodes(result); + // output the attributes in the xml namespace. + xmlattrStack.getXmlnsAttr(result); + firstCall = false; + } + + return result.iterator(); + } + + /** + * Returns the Attr[]s to be outputted for the given element. + *
    + * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a + * DOM which has been prepared using + * {@link com.sun.org.apache.xml.internal.security.utils.XMLUtils#circumventBug2650( + * org.w3c.dom.Document)}. + * + * @param E + * @param ns + * @return the Attr[]s to be outputted + * @throws CanonicalizationException + */ + Iterator handleAttributes(Element E, NameSpaceSymbTable ns) + throws CanonicalizationException { + // result will contain the attrs which have to be output + xmlattrStack.push(ns.getLevel()); + boolean isRealVisible = isVisibleDO(E, ns.getLevel()) == 1; + NamedNodeMap attrs = null; + int attrsLength = 0; + if (E.hasAttributes()) { + attrs = E.getAttributes(); + attrsLength = attrs.getLength(); + } + + SortedSet result = this.result; + result.clear(); + + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + String NUri = N.getNamespaceURI(); + + if (XMLNS_URI != NUri) { + // A non namespace definition node. + if (XML_LANG_URI == NUri) { + if (N.getLocalName().equals("id")) { + if (isRealVisible) { + // treat xml:id like any other attribute + // (emit it, but don't inherit it) + result.add(N); + } + } else { + xmlattrStack.addXmlnsAttr(N); + } + } else if (isRealVisible) { + // The node is visible add the attribute to the list of + // output attributes. + result.add(N); + } + // keep working + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getValue(); + if ("xml".equals(NName) + && XML_LANG_URI.equals(NValue)) { + /* except omit namespace node with local name xml, which defines + * the xml prefix, if its string value is + * http://www.w3.org/XML/1998/namespace. + */ + continue; + } + // add the prefix binding to the ns symb table. + // ns.addInclusiveMapping(NName,NValue,N,isRealVisible); + if (isVisible(N)) { + if (!isRealVisible && ns.removeMappingIfRender(NName)) { + continue; + } + // The xpath select this node output it if needed. + // Node n = ns.addMappingAndRenderXNodeSet + // (NName, NValue, N, isRealVisible); + Node n = ns.addMappingAndRender(NName, NValue, N); + if (n != null) { + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = + { E.getTagName(), NName, N.getNodeValue() }; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } else { + if (isRealVisible && NName != XMLNS) { + ns.removeMapping(NName); + } else { + ns.addMapping(NName, NValue, N); + } + } + } + if (isRealVisible) { + // The element is visible, handle the xmlns definition + Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS); + Node n = null; + if (xmlns == null) { + // No xmlns def just get the already defined. + n = ns.getMapping(XMLNS); + } else if (!isVisible(xmlns)) { + // There is a defn but the xmlns is not selected by the xpath. + // then xmlns="" + n = ns.addMappingAndRender(XMLNS, "", nullNode); + } + // output the xmlns def if needed. + if (n != null) { + result.add(n); + } + // Float all xml:* attributes of the unselected parent elements to + // this one. addXmlAttributes(E,result); + xmlattrStack.getXmlnsAttr(result); + ns.getUnrenderedNodes(result); + } + + return result.iterator(); + } + + /** + * Always throws a CanonicalizationException because this is inclusive c14n. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return none it always fails + * @throws CanonicalizationException always + */ + public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet, + String inclusiveNamespaces) throws CanonicalizationException { + throw new CanonicalizationException( + "c14n.Canonicalizer.UnsupportedOperation"); + } + + /** + * Always throws a CanonicalizationException because this is inclusive c14n. + * + * @param rootNode + * @param inclusiveNamespaces + * @return none it always fails + * @throws CanonicalizationException + */ + public byte[] engineCanonicalizeSubTree(Node rootNode, + String inclusiveNamespaces) throws CanonicalizationException { + throw new CanonicalizationException( + "c14n.Canonicalizer.UnsupportedOperation"); + } + + void circumventBugIfNeeded(XMLSignatureInput input) + throws CanonicalizationException, ParserConfigurationException, + IOException, SAXException { + if (!input.isNeedsToBeExpanded()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc = XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc = XMLUtils.getOwnerDocument(input.getNodeSet()); + } + XMLUtils.circumventBug2650(doc); + } + + void handleParent(Element e, NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + xmlattrStack.push(-1); + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS != N.getNamespaceURI()) { + // Not a namespace definition, ignore. + if (XML_LANG_URI == N.getNamespaceURI()) { + xmlattrStack.addXmlnsAttr(N); + } + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } + + private static String joinURI(String baseURI, String relativeURI) + throws URISyntaxException { + String bscheme = null; + String bauthority = null; + String bpath = ""; + String bquery = null; + String bfragment = null; // Is this correct? + + // pre-parse the baseURI + if (baseURI != null) { + if (baseURI.endsWith("..")) { + baseURI = baseURI + "/"; + } + URI base = new URI(baseURI); + bscheme = base.getScheme(); + bauthority = base.getAuthority(); + bpath = base.getPath(); + bquery = base.getQuery(); + bfragment = base.getFragment(); + } + + URI r = new URI(relativeURI); + String rscheme = r.getScheme(); + String rauthority = r.getAuthority(); + String rpath = r.getPath(); + String rquery = r.getQuery(); + String rfragment = null; + + String tscheme, tauthority, tpath, tquery, tfragment; + if (rscheme != null && rscheme.equals(bscheme)) { + rscheme = null; + } + if (rscheme != null) { + tscheme = rscheme; + tauthority = rauthority; + tpath = removeDotSegments(rpath); + tquery = rquery; + } else { + if (rauthority != null) { + tauthority = rauthority; + tpath = removeDotSegments(rpath); + tquery = rquery; + } else { + if (rpath.length() == 0) { + tpath = bpath; + if (rquery != null) { + tquery = rquery; + } else { + tquery = bquery; + } + } else { + if (rpath.startsWith("/")) { + tpath = removeDotSegments(rpath); + } else { + if (bauthority != null && bpath.length() == 0) { + tpath = "/" + rpath; + } else { + int last = bpath.lastIndexOf('/'); + if (last == -1) { + tpath = rpath; + } else { + tpath = bpath.substring(0, last+1) + rpath; + } + } + tpath = removeDotSegments(tpath); + } + tquery = rquery; + } + tauthority = bauthority; + } + tscheme = bscheme; + } + tfragment = rfragment; + return new URI(tscheme, tauthority, tpath, tquery, tfragment).toString(); + } + + private static String removeDotSegments(String path) { + + log.log(java.util.logging.Level.FINE, "STEP OUTPUT BUFFER\t\tINPUT BUFFER"); + + // 1. The input buffer is initialized with the now-appended path + // components then replace occurrences of "//" in the input buffer + // with "/" until no more occurrences of "//" are in the input buffer. + String input = path; + while (input.indexOf("//") > -1) { + input = input.replaceAll("//", "/"); + } + + // Initialize the output buffer with the empty string. + StringBuffer output = new StringBuffer(); + + // If the input buffer starts with a root slash "/" then move this + // character to the output buffer. + if (input.charAt(0) == '/') { + output.append("/"); + input = input.substring(1); + } + + printStep("1 ", output.toString(), input); + + // While the input buffer is not empty, loop as follows + while (input.length() != 0) { + // 2A. If the input buffer begins with a prefix of "./", + // then remove that prefix from the input buffer + // else if the input buffer begins with a prefix of "../", then + // if also the output does not contain the root slash "/" only, + // then move this prefix to the end of the output buffer else + // remove that prefix + if (input.startsWith("./")) { + input = input.substring(2); + printStep("2A", output.toString(), input); + } else if (input.startsWith("../")) { + input = input.substring(3); + if (!output.toString().equals("/")) { + output.append("../"); + } + printStep("2A", output.toString(), input); + // 2B. if the input buffer begins with a prefix of "/./" or "/.", + // where "." is a complete path segment, then replace that prefix + // with "/" in the input buffer; otherwise, + } else if (input.startsWith("/./")) { + input = input.substring(2); + printStep("2B", output.toString(), input); + } else if (input.equals("/.")) { + // FIXME: what is complete path segment? + input = input.replaceFirst("/.", "/"); + printStep("2B", output.toString(), input); + // 2C. if the input buffer begins with a prefix of "/../" or "/..", + // where ".." is a complete path segment, then replace that prefix + // with "/" in the input buffer and if also the output buffer is + // empty, last segment in the output buffer equals "../" or "..", + // where ".." is a complete path segment, then append ".." or "/.." + // for the latter case respectively to the output buffer else + // remove the last segment and its preceding "/" (if any) from the + // output buffer and if hereby the first character in the output + // buffer was removed and it was not the root slash then delete a + // leading slash from the input buffer; otherwise, + } else if (input.startsWith("/../")) { + input = input.substring(3); + if (output.length() == 0) { + output.append("/"); + } else if (output.toString().endsWith("../")) { + output.append(".."); + } else if (output.toString().endsWith("..")) { + output.append("/.."); + } else { + int index = output.lastIndexOf("/"); + if (index == -1) { + output = new StringBuffer(); + if (input.charAt(0) == '/') { + input = input.substring(1); + } + } else { + output = output.delete(index, output.length()); + } + } + printStep("2C", output.toString(), input); + } else if (input.equals("/..")) { + // FIXME: what is complete path segment? + input = input.replaceFirst("/..", "/"); + if (output.length() == 0) { + output.append("/"); + } else if (output.toString().endsWith("../")) { + output.append(".."); + } else if (output.toString().endsWith("..")) { + output.append("/.."); + } else { + int index = output.lastIndexOf("/"); + if (index == -1) { + output = new StringBuffer(); + if (input.charAt(0) == '/') { + input = input.substring(1); + } + } else { + output = output.delete(index, output.length()); + } + } + printStep("2C", output.toString(), input); + // 2D. if the input buffer consists only of ".", then remove + // that from the input buffer else if the input buffer consists + // only of ".." and if the output buffer does not contain only + // the root slash "/", then move the ".." to the output buffer + // else delte it.; otherwise, + } else if (input.equals(".")) { + input = ""; + printStep("2D", output.toString(), input); + } else if (input.equals("..")) { + if (!output.toString().equals("/")) + output.append(".."); + input = ""; + printStep("2D", output.toString(), input); + // 2E. move the first path segment (if any) in the input buffer + // to the end of the output buffer, including the initial "/" + // character (if any) and any subsequent characters up to, but not + // including, the next "/" character or the end of the input buffer. + } else { + int end = -1; + int begin = input.indexOf('/'); + if (begin == 0) { + end = input.indexOf('/', 1); + } else { + end = begin; + begin = 0; + } + String segment; + if (end == -1) { + segment = input.substring(begin); + input = ""; + } else { + segment = input.substring(begin, end); + input = input.substring(end); + } + output.append(segment); + printStep("2E", output.toString(), input); + } + } + + // 3. Finally, if the only or last segment of the output buffer is + // "..", where ".." is a complete path segment not followed by a slash + // then append a slash "/". The output buffer is returned as the result + // of remove_dot_segments + if (output.toString().endsWith("..")) { + output.append("/"); + printStep("3 ", output.toString(), input); + } + + return output.toString(); + } + + private static void printStep(String step, String output, String input) { + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, " " + step + ": " + output); + if (output.length() == 0) { + log.log(java.util.logging.Level.FINE, "\t\t\t\t" + input); + } else { + log.log(java.util.logging.Level.FINE, "\t\t\t" + input); + } + } + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java new file mode 100644 index 0000000000000000000000000000000000000000..31903667f606de63a33954c907ba9a7b7fc42fbe --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java @@ -0,0 +1,41 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * 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. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; + +/** + * @author Sean Mullan + */ +public class Canonicalizer11_OmitComments extends Canonicalizer11 { + + public Canonicalizer11_OmitComments() { + super(false); + } + + public final String engineGetURI() { + return Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS; + } + + public final boolean engineGetIncludeComments() { + return false; + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java new file mode 100644 index 0000000000000000000000000000000000000000..ba650c10872ca6b9dbe609e411da98bb5b5cc44c --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java @@ -0,0 +1,41 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * 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. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; + +/** + * @author Sean Mullan + */ +public class Canonicalizer11_WithComments extends Canonicalizer11 { + + public Canonicalizer11_WithComments() { + super(true); + } + + public final String engineGetURI() { + return Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS; + } + + public final boolean engineGetIncludeComments() { + return true; + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java index 5dbeb60f98519e7f083052696214278f0a8faffa..541c2d63c99574da4cd210b2d61d7d4479f3a57f 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -23,20 +22,30 @@ package com.sun.org.apache.xml.internal.security.c14n.implementations; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; + import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** @@ -44,13 +53,92 @@ import org.w3c.dom.Node; * XML Version 1.0, a W3C Recommendation from 15 March 2001. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ */ public abstract class Canonicalizer20010315 extends CanonicalizerBase { boolean firstCall=true; final SortedSet result= new TreeSet(COMPARE); static final String XMLNS_URI=Constants.NamespaceSpecNS; static final String XML_LANG_URI=Constants.XML_LANG_SPACE_SpecNS; - /** + static class XmlAttrStack { + int currentLevel=0; + int lastlevel=0; + XmlsStackElement cur; + static class XmlsStackElement { + int level; + boolean rendered=false; + List nodes=new ArrayList(); + }; + List levels=new ArrayList(); + void push(int level) { + currentLevel=level; + if (currentLevel==-1) + return; + cur=null; + while (lastlevel>=currentLevel) { + levels.remove(levels.size()-1); + if (levels.size()==0) { + lastlevel=0; + return; + } + lastlevel=((XmlsStackElement)levels.get(levels.size()-1)).level; + } + } + void addXmlnsAttr(Attr n) { + if (cur==null) { + cur=new XmlsStackElement(); + cur.level=currentLevel; + levels.add(cur); + lastlevel=currentLevel; + } + cur.nodes.add(n); + } + void getXmlnsAttr(Collection col) { + int size=levels.size()-1; + if (cur==null) { + cur=new XmlsStackElement(); + cur.level=currentLevel; + lastlevel=currentLevel; + levels.add(cur); + } + boolean parentRendered=false; + XmlsStackElement e=null; + if (size==-1) { + parentRendered=true; + } else { + e=(XmlsStackElement)levels.get(size); + if (e.rendered && e.level+1==currentLevel) + parentRendered=true; + + } + if (parentRendered) { + col.addAll(cur.nodes); + cur.rendered=true; + return; + } + + Map loa = new HashMap(); + for (;size>=0;size--) { + e=(XmlsStackElement)levels.get(size); + Iterator it=e.nodes.iterator(); + while (it.hasNext()) { + Attr n=(Attr)it.next(); + if (!loa.containsKey(n.getName())) + loa.put(n.getName(),n); + } + //if (e.rendered) + //break; + + }; + //cur.nodes.clear(); + //cur.nodes.addAll(loa.values()); + cur.rendered=true; + col.addAll(loa.values()); + } + + } + XmlAttrStack xmlattrStack=new XmlAttrStack(); + /** * Constructor Canonicalizer20010315 * * @param includeComments @@ -86,16 +174,16 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NValue=N.getValue(); String NUri =N.getNamespaceURI(); - if (!XMLNS_URI.equals(NUri)) { + if (XMLNS_URI!=NUri) { //It's not a namespace attr node. Add to the result and continue. result.add(N); continue; } + String NName=N.getLocalName(); + String NValue=N.getValue(); if (XML.equals(NName) && XML_LANG_URI.equals(NValue)) { //The default mapping for xml must not be output. @@ -120,64 +208,13 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { //Obtain all the namespaces defined in the parents, and added to the output. ns.getUnrenderedNodes(result); //output the attributes in the xml namespace. - addXmlAttributesSubtree(E, result); - firstCall=false; + xmlattrStack.getXmlnsAttr(result); + firstCall=false; } return result.iterator(); } - /** - * Float the xml:* attributes of the parent nodes to the root node of c14n - * @param E the root node. - * @param result the xml:* attributes to output. - */ - private void addXmlAttributesSubtree(Element E, SortedSet result) { - // E is in the node-set - Node parent = E.getParentNode(); - Map loa = new HashMap(); - - if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)) { - - // parent element is not in node set - for (Node ancestor = parent; - (ancestor != null) - && (ancestor.getNodeType() == Node.ELEMENT_NODE); - ancestor = ancestor.getParentNode()) { - Element el=((Element) ancestor); - if (!el.hasAttributes()) { - continue; - } - // for all ancestor elements - NamedNodeMap ancestorAttrs = el.getAttributes(); - - for (int i = 0; i < ancestorAttrs.getLength(); i++) { - // for all attributes in the ancestor element - Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); - - if (XML_LANG_URI.equals( - currentAncestorAttr.getNamespaceURI())) { - - // do we have an xml:* ? - if (!E.hasAttributeNS( - XML_LANG_URI, - currentAncestorAttr.getLocalName())) { - - // the xml:* attr is not in E - if (!loa.containsKey(currentAncestorAttr.getName())) { - loa.put(currentAncestorAttr.getName(), - currentAncestorAttr); - } - } - } - } - } - } - - result.addAll( loa.values()); - - } - /** * Returns the Attr[]s to be outputted for the given element. *
    @@ -192,7 +229,8 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { */ Iterator handleAttributes(Element E, NameSpaceSymbTable ns ) throws CanonicalizationException { // result will contain the attrs which have to be outputted - boolean isRealVisible=isVisible(E); + xmlattrStack.push(ns.getLevel()); + boolean isRealVisible=isVisibleDO(E,ns.getLevel())==1; NamedNodeMap attrs = null; int attrsLength = 0; if (E.hasAttributes()) { @@ -204,16 +242,15 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { SortedSet result = this.result; result.clear(); - for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NValue=N.getValue(); String NUri =N.getNamespaceURI(); - if (!XMLNS_URI.equals(NUri)) { + if (XMLNS_URI!=NUri) { //A non namespace definition node. - if (isRealVisible){ + if (XML_LANG_URI==NUri) { + xmlattrStack.addXmlnsAttr(N); + } else if (isRealVisible){ //The node is visible add the attribute to the list of output attributes. result.add(N); } @@ -221,7 +258,8 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { continue; } - + String NName=N.getLocalName(); + String NValue=N.getValue(); if ("xml".equals(NName) && XML_LANG_URI.equals(NValue)) { /* except omit namespace node with local name xml, which defines @@ -232,16 +270,26 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { //add the prefix binding to the ns symb table. //ns.addInclusiveMapping(NName,NValue,N,isRealVisible); if (isVisible(N)) { - //The xpath select this node output it if needed. - Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); - if (n!=null) { + if (!isRealVisible && ns.removeMappingIfRender(NName)) { + continue; + } + //The xpath select this node output it if needed. + //Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); + Node n=ns.addMappingAndRender(NName,NValue,N); + if (n!=null) { result.add(n); if (C14nHelper.namespaceIsRelative(N)) { Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; throw new CanonicalizationException( "c14n.Canonicalizer.RelativeNamespace", exArgs); - } - } + } + } + } else { + if (isRealVisible && NName!=XMLNS) { + ns.removeMapping(NName); + } else { + ns.addMapping(NName,NValue,N); + } } } if (isRealVisible) { @@ -254,84 +302,21 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { } else if ( !isVisible(xmlns)) { //There is a definition but the xmlns is not selected by the xpath. //then xmlns="" - n=ns.addMappingAndRenderXNodeSet(XMLNS,"",nullNode,true); + n=ns.addMappingAndRender(XMLNS,"",nullNode); } //output the xmlns def if needed. if (n!=null) { result.add(n); } //Float all xml:* attributes of the unselected parent elements to this one. - addXmlAttributes(E,result); + //addXmlAttributes(E,result); + xmlattrStack.getXmlnsAttr(result); + ns.getUnrenderedNodes(result); + } return result.iterator(); } - /** - * Float the xml:* attributes of the unselected parent nodes to the ciurrent node. - * @param E - * @param result - */ - private void addXmlAttributes(Element E, SortedSet result) { - /* The processing of an element node E MUST be modified slightly when an - * XPath node-set is given as input and the element's parent is omitted - * from the node-set. The method for processing the attribute axis of an - * element E in the node-set is enhanced. All element nodes along E's - * ancestor axis are examined for nearest occurrences of attributes in - * the xml namespace, such as xml:lang and xml:space (whether or not they - * are in the node-set). From this list of attributes, remove any that are - * in E's attribute axis (whether or not they are in the node-set). Then, - * lexicographically merge this attribute list with the nodes of E's - * attribute axis that are in the node-set. The result of visiting the - * attribute axis is computed by processing the attribute nodes in this - * merged attribute list. - */ - - // E is in the node-set - Node parent = E.getParentNode(); - Map loa = new HashMap(); - - if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE) - &&!isVisible(parent)) { - - // parent element is not in node set - for (Node ancestor = parent; - (ancestor != null) - && (ancestor.getNodeType() == Node.ELEMENT_NODE); - ancestor = ancestor.getParentNode()) { - Element el=((Element) ancestor); - if (!el.hasAttributes()) { - continue; - } - // for all ancestor elements - NamedNodeMap ancestorAttrs =el.getAttributes(); - - for (int i = 0; i < ancestorAttrs.getLength(); i++) { - - // for all attributes in the ancestor element - Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); - - if (XML_LANG_URI.equals( - currentAncestorAttr.getNamespaceURI())) { - - // do we have an xml:* ? - if (!E.hasAttributeNS( - XML_LANG_URI, - currentAncestorAttr.getLocalName())) { - - // the xml:* attr is not in E - if (!loa.containsKey(currentAncestorAttr.getName())) { - loa.put(currentAncestorAttr.getName(), - currentAncestorAttr); - } - } - } - } - } - } - result.addAll(loa.values()); - -} - /** * Always throws a CanonicalizationException because this is inclusive c14n. * @@ -363,4 +348,43 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { throw new CanonicalizationException( "c14n.Canonicalizer.UnsupportedOperation"); } + void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { + if (!input.isNeedsToBeExpanded()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc=XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc=XMLUtils.getOwnerDocument(input.getNodeSet()); + } + XMLUtils.circumventBug2650(doc); + + } + + void handleParent(Element e, NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + xmlattrStack.push(-1); + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS!=N.getNamespaceURI()) { + //Not a namespace definition, ignore. + if (XML_LANG_URI==N.getNamespaceURI()) { + xmlattrStack.addXmlnsAttr(N); + } + continue; + } + + String NName=N.getLocalName(); + String NValue=N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java index 18f697366cf51c12194970fda695aba978cda1bd..679c7b5088b7ca62547ca329e33a354d0f5f9015 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,20 +20,26 @@ */ package com.sun.org.apache.xml.internal.security.c14n.implementations; +import java.io.IOException; import java.util.Iterator; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; + import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces; import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** * Implements " Exclusive XML @@ -47,6 +52,7 @@ import org.w3c.dom.Node; * THIS implementation is a complete rewrite of the algorithm. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ * @see * XML Canonicalization, Version 1.0 */ @@ -55,7 +61,7 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of * the inclusive namespaces. */ - TreeSet _inclusiveNSSet = null; + TreeSet _inclusiveNSSet = new TreeSet(); static final String XMLNS_URI=Constants.NamespaceSpecNS; final SortedSet result = new TreeSet(COMPARE); /** @@ -143,10 +149,8 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NNodeValue=N.getNodeValue(); - if (!XMLNS_URI.equals(N.getNamespaceURI())) { + if (XMLNS_URI!=N.getNamespaceURI()) { //Not a namespace definition. //The Element is output element, add his prefix(if used) to visibyUtilized String prefix = N.getPrefix(); @@ -157,6 +161,8 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { result.add(N); continue; } + String NName=N.getLocalName(); + String NNodeValue=N.getNodeValue(); if (ns.addMapping(NName, NNodeValue,N)) { //New definition check if it is relative. @@ -168,17 +174,17 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } } } - + String prefix; if (E.getNamespaceURI() != null) { - String prefix = E.getPrefix(); + prefix = E.getPrefix(); if ((prefix == null) || (prefix.length() == 0)) { - visiblyUtilized.add(XMLNS); - } else { - visiblyUtilized.add(prefix); + prefix=XMLNS; } + } else { - visiblyUtilized.add(XMLNS); + prefix=XMLNS; } + visiblyUtilized.add(prefix); //This can be optimezed by I don't have time Iterator it=visiblyUtilized.iterator(); @@ -211,12 +217,6 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } - /** @inheritDoc */ - public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet - ) throws CanonicalizationException { - return engineCanonicalizeXPathNodeSet(xpathNodeSet,""); - } - /** * @inheritDoc * @param E @@ -236,21 +236,20 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { //The prefix visibly utilized(in the attribute or in the name) in the element Set visiblyUtilized =null; //It's the output selected. - boolean isOutputElement = isVisible(E); + boolean isOutputElement=isVisibleDO(E,ns.getLevel())==1; if (isOutputElement) { visiblyUtilized = (Set) this._inclusiveNSSet.clone(); } for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NNodeValue=N.getNodeValue(); - if ( !isVisible(N) ) { - //The node is not in the nodeset(if there is a nodeset) - continue; - } - if (!XMLNS_URI.equals(N.getNamespaceURI())) { + + if (XMLNS_URI!=N.getNamespaceURI()) { + if ( !isVisible(N) ) { + //The node is not in the nodeset(if there is a nodeset) + continue; + } //Not a namespace definition. if (isOutputElement) { //The Element is output element, add his prefix(if used) to visibyUtilized @@ -263,6 +262,25 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } continue; } + String NName=N.getLocalName(); + if (isOutputElement && !isVisible(N) && NName!=XMLNS) { + ns.removeMappingIfNotRender(NName); + continue; + } + String NNodeValue=N.getNodeValue(); + + if (!isOutputElement && isVisible(N) && _inclusiveNSSet.contains(NName) && !ns.removeMappingIfRender(NName)) { + Node n=ns.addMappingAndRender(NName,NNodeValue,N); + if (n!=null) { + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } + if (ns.addMapping(NName, NNodeValue,N)) { @@ -306,18 +324,20 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } result.add(key); } - } else /*if (_circunvented)*/ { - Iterator it=this._inclusiveNSSet.iterator(); - while (it.hasNext()) { - String s=(String)it.next(); - Attr key=ns.getMappingWithoutRendered(s); - if (key==null) { - continue; - } - result.add(key); - } } return result.iterator(); } + void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { + if (!input.isNeedsToBeExpanded() || _inclusiveNSSet.isEmpty()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc=XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc=XMLUtils.getOwnerDocument(input.getNodeSet()); + } + + XMLUtils.circumventBug2650(doc); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java index 025502bd5feff48f2fa166ff835b8b7d9776f839..375501248793936249faa0ca3743c32470c1b4b0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java @@ -28,6 +28,7 @@ import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; /** * Class Canonicalizer20010315ExclWithComments * + * @version $Revision: 1.5 $ */ public class Canonicalizer20010315ExclWithComments extends Canonicalizer20010315Excl { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java index 539bb3a3957fbd315eff3d674c79d66876e1eb56..4714e165bba6500b9d58913063f5eb274db242e0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java index 8108763750f95abde0d5df456fc143468435ec9a..05f22d8c1e8cc6573a74fb3c6b204c49bcd6413e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java @@ -27,9 +27,11 @@ import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; @@ -45,7 +47,6 @@ import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStrea import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; import org.w3c.dom.Comment; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -57,6 +58,7 @@ import org.xml.sax.SAXException; * Abstract base class for canonicalization algorithms. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ */ public abstract class CanonicalizerBase extends CanonicalizerSpi { //Constants to be outputed, In char array form, so @@ -122,6 +124,18 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { throws CanonicalizationException { return engineCanonicalizeSubTree(rootNode,(Node)null); } + /** + * Method engineCanonicalizeXPathNodeSet + * @inheritDoc + * @param xpathNodeSet + * @throws CanonicalizationException + */ + public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet) + throws CanonicalizationException { + this._xpathNodeSet = xpathNodeSet; + return engineCanonicalizeXPathNodeSetInternal(XMLUtils.getOwnerDocument(this._xpathNodeSet)); + } + /** * Canonicalizes a Subtree node. * @param input the root of the subtree to canicalize @@ -143,15 +157,8 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { return bytes; } else if (input.isNodeSet()) { nodeFilter=input.getNodeFilters(); - Document doc = null; - if (input.getSubNode() != null) { - doc=XMLUtils.getOwnerDocument(input.getSubNode()); - } else { - doc=XMLUtils.getOwnerDocument(input.getNodeSet()); - } - if (input.isNeedsToBeExpanded()) { - XMLUtils.circumventBug2650(doc); - } + + circumventBugIfNeeded(input); if (input.getSubNode() != null) { bytes = engineCanonicalizeXPathNodeSetInternal(input.getSubNode()); @@ -173,6 +180,13 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } } /** + * @param _writer The _writer to set. + */ + public void setWriter(OutputStream _writer) { + this._writer = _writer; + } + + /** * Canonicalizes a Subtree node. * * @param rootNode @@ -187,11 +201,13 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { this._excludeNode = excludeNode; try { NameSpaceSymbTable ns=new NameSpaceSymbTable(); + int nodeLevel=NODE_BEFORE_DOCUMENT_ELEMENT; if (rootNode instanceof Element) { //Fills the nssymbtable with the definitions of the parent of the root subnode getParentNameSpaces((Element)rootNode,ns); + nodeLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; } - this.canonicalizeSubTree(rootNode,ns,rootNode); + this.canonicalizeSubTree(rootNode,ns,rootNode,nodeLevel); this._writer.close(); if (this._writer instanceof ByteArrayOutputStream) { byte []result=((ByteArrayOutputStream)this._writer).toByteArray(); @@ -199,6 +215,12 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ((ByteArrayOutputStream)this._writer).reset(); } return result; + } else if (this._writer instanceof UnsyncByteArrayOutputStream) { + byte []result=((UnsyncByteArrayOutputStream)this._writer).toByteArray(); + if (reset) { + ((UnsyncByteArrayOutputStream)this._writer).reset(); + } + return result; } return null; @@ -219,13 +241,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { * @throws CanonicalizationException * @throws IOException */ - final void canonicalizeSubTree(Node currentNode, NameSpaceSymbTable ns,Node endnode) + final void canonicalizeSubTree(Node currentNode, NameSpaceSymbTable ns,Node endnode, + int documentLevel) throws CanonicalizationException, IOException { + if (isVisibleInt(currentNode)==-1) + return; Node sibling=null; Node parentNode=null; final OutputStream writer=this._writer; final Node excludeNode=this._excludeNode; final boolean includeComments=this._includeComments; + Map cache=new HashMap(); do { switch (currentNode.getNodeType()) { @@ -242,18 +268,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { case Node.DOCUMENT_FRAGMENT_NODE : case Node.DOCUMENT_NODE : ns.outputNodePush(); - //currentNode = currentNode.getFirstChild(); sibling= currentNode.getFirstChild(); break; case Node.COMMENT_NODE : if (includeComments) { - outputCommentToWriter((Comment) currentNode, writer); + outputCommentToWriter((Comment) currentNode, writer, documentLevel); } break; case Node.PROCESSING_INSTRUCTION_NODE : - outputPItoWriter((ProcessingInstruction) currentNode, writer); + outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); break; case Node.TEXT_NODE : @@ -262,6 +287,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.ELEMENT_NODE : + documentLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; if (currentNode==excludeNode) { break; } @@ -270,27 +296,27 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ns.outputNodePush(); writer.write('<'); String name=currentElement.getTagName(); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); Iterator attrs = this.handleAttributesSubtree(currentElement,ns); if (attrs!=null) { //we output all Attrs which are available while (attrs.hasNext()) { Attr attr = (Attr) attrs.next(); - outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); + outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer,cache); } } writer.write('>'); sibling= currentNode.getFirstChild(); if (sibling==null) { writer.write(_END_TAG); - writeStringToUtf8(name,writer); + UtfHelpper.writeStringToUtf8(name,writer); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); - if (parentNode != null) { + if (parentNode != null) { sibling= currentNode.getNextSibling(); - } + } } else { parentNode=currentElement; } @@ -298,7 +324,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } while (sibling==null && parentNode!=null) { writer.write(_END_TAG); - writeStringToUtf8(((Element)parentNode).getTagName(),writer); + UtfHelpper.writeByte(((Element)parentNode).getTagName(),writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -307,6 +333,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { sibling=parentNode.getNextSibling(); parentNode=parentNode.getParentNode(); if (!(parentNode instanceof Element)) { + documentLevel=NODE_AFTER_DOCUMENT_ELEMENT; parentNode=null; } } @@ -317,47 +344,8 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } while(true); } - /** - * Checks whether a Comment or ProcessingInstruction is before or after the - * document element. This is needed for prepending or appending "\n"s. - * - * @param currentNode comment or pi to check - * @return NODE_BEFORE_DOCUMENT_ELEMENT, NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT or NODE_AFTER_DOCUMENT_ELEMENT - * @see #NODE_BEFORE_DOCUMENT_ELEMENT - * @see #NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT - * @see #NODE_AFTER_DOCUMENT_ELEMENT - */ - final static int getPositionRelativeToDocumentElement(Node currentNode) { - if ((currentNode == null) || - (currentNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE) ) { - return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; - } - Element documentElement = currentNode.getOwnerDocument().getDocumentElement(); - if ( (documentElement == null) || (documentElement == currentNode) ){ - return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; - } - for (Node x = currentNode; x != null; x = x.getNextSibling()) { - if (x == documentElement) { - return CanonicalizerBase.NODE_BEFORE_DOCUMENT_ELEMENT; - } - } - - return CanonicalizerBase.NODE_AFTER_DOCUMENT_ELEMENT; - } - - /** - * Method engineCanonicalizeXPathNodeSet - * @inheritDoc - * @param xpathNodeSet - * @throws CanonicalizationException - */ - public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet) - throws CanonicalizationException { - this._xpathNodeSet = xpathNodeSet; - return engineCanonicalizeXPathNodeSetInternal(XMLUtils.getOwnerDocument(this._xpathNodeSet)); - } private byte[] engineCanonicalizeXPathNodeSetInternal(Node doc) throws CanonicalizationException { @@ -370,6 +358,12 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ((ByteArrayOutputStream)this._writer).reset(); } return sol; + } else if (this._writer instanceof UnsyncByteArrayOutputStream) { + byte []result=((UnsyncByteArrayOutputStream)this._writer).toByteArray(); + if (reset) { + ((UnsyncByteArrayOutputStream)this._writer).reset(); + } + return result; } return null; } catch (UnsupportedEncodingException ex) { @@ -390,11 +384,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { */ final void canonicalizeXPathNodeSet(Node currentNode,Node endnode ) throws CanonicalizationException, IOException { - boolean currentNodeIsVisible = false; - NameSpaceSymbTable ns=new NameSpaceSymbTable(); + if (isVisibleInt(currentNode)==-1) + return; + boolean currentNodeIsVisible = false; + NameSpaceSymbTable ns=new NameSpaceSymbTable(); + if (currentNode instanceof Element) + getParentNameSpaces((Element)currentNode,ns); Node sibling=null; Node parentNode=null; OutputStream writer=this._writer; + int documentLevel=NODE_BEFORE_DOCUMENT_ELEMENT; + Map cache=new HashMap(); do { switch (currentNode.getNodeType()) { @@ -416,14 +416,14 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.COMMENT_NODE : - if (this._includeComments && isVisible(currentNode)) { - outputCommentToWriter((Comment) currentNode, writer); + if (this._includeComments && (isVisibleDO(currentNode,ns.getLevel())==1)) { + outputCommentToWriter((Comment) currentNode, writer, documentLevel); } break; case Node.PROCESSING_INSTRUCTION_NODE : if (isVisible(currentNode)) - outputPItoWriter((ProcessingInstruction) currentNode, writer); + outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); break; case Node.TEXT_NODE : @@ -436,12 +436,6 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { || (nextSibling.getNodeType() == Node.CDATA_SECTION_NODE)); nextSibling = nextSibling.getNextSibling()) { - /* The XPath data model allows to select only the first of a - * sequence of mixed text and CDATA nodes. But we must output - * them all, so we must search: - * - * @see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6329 - */ outputTextToWriter(nextSibling.getNodeValue(), writer); currentNode=nextSibling; sibling=currentNode.getNextSibling(); @@ -451,15 +445,21 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.ELEMENT_NODE : + documentLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; Element currentElement = (Element) currentNode; //Add a level to the nssymbtable. So latter can be pop-back. String name=null; - currentNodeIsVisible=isVisible(currentNode); + int i=isVisibleDO(currentNode,ns.getLevel()); + if (i==-1) { + sibling= currentNode.getNextSibling(); + break; + } + currentNodeIsVisible=(i==1); if (currentNodeIsVisible) { ns.outputNodePush(); writer.write('<'); name=currentElement.getTagName(); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); } else { ns.push(); } @@ -469,7 +469,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { //we output all Attrs which are available while (attrs.hasNext()) { Attr attr = (Attr) attrs.next(); - outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); + outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer,cache); } } if (currentNodeIsVisible) { @@ -480,7 +480,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { if (sibling==null) { if (currentNodeIsVisible) { writer.write(_END_TAG); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -498,7 +498,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { while (sibling==null && parentNode!=null) { if (isVisible(parentNode)) { writer.write(_END_TAG); - writeStringToUtf8(((Element)parentNode).getTagName(),writer); + UtfHelpper.writeByte(((Element)parentNode).getTagName(),writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -511,6 +511,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { parentNode=parentNode.getParentNode(); if (!(parentNode instanceof Element)) { parentNode=null; + documentLevel=NODE_AFTER_DOCUMENT_ELEMENT; } } if (sibling==null) @@ -519,12 +520,38 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { sibling=currentNode.getNextSibling(); } while(true); } + int isVisibleDO(Node currentNode,int level) { + if (nodeFilter!=null) { + Iterator it=nodeFilter.iterator(); + while (it.hasNext()) { + int i=((NodeFilter)it.next()).isNodeIncludeDO(currentNode,level); + if (i!=1) + return i; + } + } + if ((this._xpathNodeSet!=null) && !this._xpathNodeSet.contains(currentNode)) + return 0; + return 1; + } + int isVisibleInt(Node currentNode) { + if (nodeFilter!=null) { + Iterator it=nodeFilter.iterator(); + while (it.hasNext()) { + int i=((NodeFilter)it.next()).isNodeInclude(currentNode); + if (i!=1) + return i; + } + } + if ((this._xpathNodeSet!=null) && !this._xpathNodeSet.contains(currentNode)) + return 0; + return 1; + } boolean isVisible(Node currentNode) { if (nodeFilter!=null) { Iterator it=nodeFilter.iterator(); while (it.hasNext()) { - if (!((NodeFilter)it.next()).isNodeInclude(currentNode)) + if (((NodeFilter)it.next()).isNodeInclude(currentNode)!=1) return false; } } @@ -533,19 +560,42 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { return true; } + void handleParent(Element e,NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS!=N.getNamespaceURI()) { + //Not a namespace definition, ignore. + continue; + } + + String NName=N.getLocalName(); + String NValue=N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } + /** * Adds to ns the definitons from the parent elements of el * @param el * @param ns */ - final static void getParentNameSpaces(Element el,NameSpaceSymbTable ns) { - List parents=new ArrayList(); + final void getParentNameSpaces(Element el,NameSpaceSymbTable ns) { + List parents=new ArrayList(10); Node n1=el.getParentNode(); if (!(n1 instanceof Element)) { return; } //Obtain all the parents of the elemnt - Element parent=(Element) el.getParentNode(); + Element parent=(Element) n1; while (parent!=null) { parents.add(parent); Node n=parent.getParentNode(); @@ -557,297 +607,15 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { //Visit them in reverse order. ListIterator it=parents.listIterator(parents.size()); while (it.hasPrevious()) { - Element ele=(Element)it.previous(); - if (!ele.hasAttributes()) { - continue; + Element ele=(Element)it.previous(); + handleParent(ele, ns); } - NamedNodeMap attrs = ele.getAttributes(); - int attrsLength = attrs.getLength(); - for (int i = 0; i < attrsLength; i++) { - Attr N = (Attr) attrs.item(i); - if (!Constants.NamespaceSpecNS.equals(N.getNamespaceURI())) { - //Not a namespace definition, ignore. - continue; - } - - String NName=N.getLocalName(); - String NValue=N.getNodeValue(); - if (XML.equals(NName) - && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { - continue; - } - ns.addMapping(NName,NValue,N); - } - } Attr nsprefix; if (((nsprefix=ns.getMappingWithoutRendered("xmlns"))!=null) && "".equals(nsprefix.getValue())) { ns.addMappingAndRender("xmlns","",nullNode); } } - /** - * Outputs an Attribute to the internal Writer. - * - * The string value of the node is modified by replacing - *
      - *
    • all ampersands (&) with &amp;
    • - *
    • all open angle brackets (<) with &lt;
    • - *
    • all quotation mark characters with &quot;
    • - *
    • and the whitespace characters #x9, #xA, and #xD, with character - * references. The character references are written in uppercase - * hexadecimal with no leading zeroes (for example, #xD is represented - * by the character reference &#xD;)
    • - *
    - * - * @param name - * @param value - * @param writer - * @throws IOException - */ - static final void outputAttrToWriter(final String name, final String value, final OutputStream writer) throws IOException { - writer.write(' '); - writeStringToUtf8(name,writer); - writer.write(equalsStr); - byte []toWrite; - final int length = value.length(); - for (int i=0;i < length; i++) { - char c = value.charAt(i); - - switch (c) { - - case '&' : - toWrite=_AMP_; - //writer.write(_AMP_); - break; - - case '<' : - toWrite=_LT_; - //writer.write(_LT_); - break; - - case '"' : - toWrite=_QUOT_; - //writer.write(_QUOT_); - break; - - case 0x09 : // '\t' - toWrite=__X9_; - //writer.write(__X9_); - break; - - case 0x0A : // '\n' - toWrite=__XA_; - //writer.write(__XA_); - break; - - case 0x0D : // '\r' - toWrite=__XD_; - //writer.write(__XD_); - break; - - default : - writeCharToUtf8(c,writer); - //this._writer.write(c); - continue; - } - writer.write(toWrite); - } - - writer.write('\"'); - } - - final static void writeCharToUtf8(final char c,final OutputStream out) throws IOException{ - char ch; - if (/*(c >= 0x0001) &&*/ (c <= 0x007F)) { - out.write(c); - return; - } - int bias; - int write; - if (c > 0x07FF) { - ch=(char)(c>>>12); - write=0xE0; - if (ch>0) { - write |= ( ch & 0x0F); - } - out.write(write); - write=0x80; - bias=0x3F; - } else { - write=0xC0; - bias=0x1F; - } - ch=(char)(c>>>6); - if (ch>0) { - write|= (ch & bias); - } - out.write(write); - out.write(0x80 | ((c) & 0x3F)); - - } - - final static void writeStringToUtf8(final String str,final OutputStream out) throws IOException{ - final int length=str.length(); - int i=0; - char c; - while (i= 0x0001) &&*/ (c <= 0x007F)) { - out.write(c); - continue; - } - char ch; - int bias; - int write; - if (c > 0x07FF) { - ch=(char)(c>>>12); - write=0xE0; - if (ch>0) { - write |= ( ch & 0x0F); - } - out.write(write); - write=0x80; - bias=0x3F; - } else { - write=0xC0; - bias=0x1F; - } - ch=(char)(c>>>6); - if (ch>0) { - write|= (ch & bias); - } - out.write(write); - out.write(0x80 | ((c) & 0x3F)); - continue; - - } - - } - /** - * Outputs a PI to the internal Writer. - * - * @param currentPI - * @param writer where to write the things - * @throws IOException - */ - static final void outputPItoWriter(ProcessingInstruction currentPI, OutputStream writer) throws IOException { - final int position = getPositionRelativeToDocumentElement(currentPI); - - if (position == NODE_AFTER_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - writer.write(_BEGIN_PI); - - final String target = currentPI.getTarget(); - int length = target.length(); - - for (int i = 0; i < length; i++) { - char c=target.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - - final String data = currentPI.getData(); - - length = data.length(); - - if (length > 0) { - writer.write(' '); - - for (int i = 0; i < length; i++) { - char c=data.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - } - - writer.write(_END_PI); - if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - } - - /** - * Method outputCommentToWriter - * - * @param currentComment - * @param writer writer where to write the things - * @throws IOException - */ - static final void outputCommentToWriter(Comment currentComment, OutputStream writer) throws IOException { - final int position = getPositionRelativeToDocumentElement(currentComment); - if (position == NODE_AFTER_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - writer.write(_BEGIN_COMM); - - final String data = currentComment.getData(); - final int length = data.length(); - - for (int i = 0; i < length; i++) { - char c=data.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - - writer.write(_END_COMM); - if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - } - - /** - * Outputs a Text of CDATA section to the internal Writer. - * - * @param text - * @param writer writer where to write the things - * @throws IOException - */ - static final void outputTextToWriter(final String text, final OutputStream writer) throws IOException { - final int length = text.length(); - byte []toWrite; - for (int i = 0; i < length; i++) { - char c = text.charAt(i); - - switch (c) { - - case '&' : - toWrite=_AMP_; - //writer.write(_AMP_); - break; - - case '<' : - toWrite=_LT_; - //writer.write(_LT_); - break; - - case '>' : - toWrite=_GT_; - //writer.write(_GT_); - break; - - case 0xD : - toWrite=__XD_; - //writer.write(__XD_); - break; - - default : - writeCharToUtf8(c,writer); - continue; - } - writer.write(toWrite); - } - } - /** * Obtain the attributes to output for this node in XPathNodeSet c14n. * @@ -870,13 +638,207 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { abstract Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns) throws CanonicalizationException; + abstract void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException; + /** + * Outputs an Attribute to the internal Writer. + * + * The string value of the node is modified by replacing + *
      + *
    • all ampersands (&) with &amp;
    • + *
    • all open angle brackets (<) with &lt;
    • + *
    • all quotation mark characters with &quot;
    • + *
    • and the whitespace characters #x9, #xA, and #xD, with character + * references. The character references are written in uppercase + * hexadecimal with no leading zeroes (for example, #xD is represented + * by the character reference &#xD;)
    • + *
    + * + * @param name + * @param value + * @param writer + * @throws IOException + */ + static final void outputAttrToWriter(final String name, final String value, final OutputStream writer, + final Map cache) throws IOException { + writer.write(' '); + UtfHelpper.writeByte(name,writer,cache); + writer.write(equalsStr); + byte []toWrite; + final int length = value.length(); + int i=0; + while (i < length) { + char c = value.charAt(i++); + + switch (c) { + + case '&' : + toWrite=_AMP_; + break; + + case '<' : + toWrite=_LT_; + break; + + case '"' : + toWrite=_QUOT_; + break; + + case 0x09 : // '\t' + toWrite=__X9_; + break; + + case 0x0A : // '\n' + toWrite=__XA_; + break; + + case 0x0D : // '\r' + toWrite=__XD_; + break; + + default : + if (c < 0x80 ) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + continue; + } + writer.write(toWrite); + } - /** - * @param _writer The _writer to set. - */ - public void setWriter(OutputStream _writer) { - this._writer = _writer; - } + writer.write('\"'); + } + + /** + * Outputs a PI to the internal Writer. + * + * @param currentPI + * @param writer where to write the things + * @throws IOException + */ + static final void outputPItoWriter(ProcessingInstruction currentPI, OutputStream writer,int position) throws IOException { + + if (position == NODE_AFTER_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + writer.write(_BEGIN_PI); + + final String target = currentPI.getTarget(); + int length = target.length(); + + for (int i = 0; i < length; i++) { + char c=target.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + } + } + + final String data = currentPI.getData(); + + length = data.length(); + + if (length > 0) { + writer.write(' '); + + for (int i = 0; i < length; i++) { + char c=data.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + } + } + } + + writer.write(_END_PI); + if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + } + + /** + * Method outputCommentToWriter + * + * @param currentComment + * @param writer writer where to write the things + * @throws IOException + */ + static final void outputCommentToWriter(Comment currentComment, OutputStream writer,int position) throws IOException { + if (position == NODE_AFTER_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + writer.write(_BEGIN_COMM); + + final String data = currentComment.getData(); + final int length = data.length(); + + for (int i = 0; i < length; i++) { + char c=data.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + } + } + + writer.write(_END_COMM); + if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + } + + /** + * Outputs a Text of CDATA section to the internal Writer. + * + * @param text + * @param writer writer where to write the things + * @throws IOException + */ + static final void outputTextToWriter(final String text, final OutputStream writer) throws IOException { + final int length = text.length(); + byte []toWrite; + for (int i = 0; i < length; i++) { + char c = text.charAt(i); + + switch (c) { + + case '&' : + toWrite=_AMP_; + break; + + case '<' : + toWrite=_LT_; + break; + + case '>' : + toWrite=_GT_; + break; + + case 0xD : + toWrite=__XD_; + break; + + default : + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + continue; + } + writer.write(toWrite); + } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java index bad23010f11c02eeacc16bc6abe61f0d631c4049..538d369748c0da7e07d1d7d8bc97ec2b17d177b6 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java @@ -20,16 +20,10 @@ */ package com.sun.org.apache.xml.internal.security.c14n.implementations; -import java.lang.reflect.Array; -import java.util.AbstractList; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; - import org.w3c.dom.Attr; @@ -46,21 +40,26 @@ import org.w3c.dom.Node; public class NameSpaceSymbTable { /**The map betwen prefix-> entry table. */ - SymbMap symb = new SymbMap(); + SymbMap symb; /**The level of nameSpaces (for Inclusive visibility).*/ int nameSpaces=0; /**The stacks for removing the definitions when doing pop.*/ - List level = new ArrayList(); + List level; boolean cloned=true; static final String XMLNS="xmlns"; + final static SymbMap initialMap=new SymbMap(); + static { + NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true,XMLNS); + ne.lastrendered=""; + initialMap.put(XMLNS,ne); + } /** * Default constractor **/ public NameSpaceSymbTable() { + level = new ArrayList(10); //Insert the default binding for xmlns. - NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true); - ne.lastrendered=""; - symb.put(XMLNS,ne); + symb=(SymbMap) initialMap.clone(); } /** @@ -75,8 +74,14 @@ public class NameSpaceSymbTable { NameSpaceSymbEntry n=(NameSpaceSymbEntry)(it.next()); //put them rendered? if ((!n.rendered) && (n.n!=null)) { + n=(NameSpaceSymbEntry) n.clone(); + needsClone(); + symb.put(n.prefix,n); + n.lastrendered=n.uri; + n.rendered=true; + result.add(n.n); - n.rendered=true; + } } } @@ -104,10 +109,6 @@ public class NameSpaceSymbTable { **/ public void push() { //Put the number of namespace definitions in the stack. - /**if (cloned) { - Object ob[]= {symb,cloned ? symb : null}; - level.add(ob); - } **/ level.add(null); cloned=false; } @@ -124,7 +125,7 @@ public class NameSpaceSymbTable { if (size==0) { cloned=false; } else - cloned=(level.get(size-1)!=symb); + cloned=(level.get(size-1)!=symb); } else { cloned=false; } @@ -134,8 +135,7 @@ public class NameSpaceSymbTable { final void needsClone() { if (!cloned) { - level.remove(level.size()-1); - level.add(symb); + level.set(level.size()-1,symb); symb=(SymbMap) symb.clone(); cloned=true; } @@ -200,7 +200,7 @@ public class NameSpaceSymbTable { return false; } //Creates and entry in the table for this new definition. - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,false); + NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,false,prefix); needsClone(); symb.put(prefix, ne); if (ob != null) { @@ -238,7 +238,7 @@ public class NameSpaceSymbTable { return null; } - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true); + NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true,prefix); ne.lastrendered=uri; needsClone(); symb.put(prefix, ne); @@ -251,53 +251,38 @@ public class NameSpaceSymbTable { } return ne.n; } - /** - * Adds & gets(if needed) the attribute node that defines the binding for the prefix. - * Take on account if the rules of rendering in the inclusive c14n. - * For inclusive c14n. - * @param prefix the prefix to obtain the attribute. - * @param outputNode the container element is an output element. - * @param uri the Uri of the definition - * @param n the attribute that have the definition - * @return null if there is no need to render the prefix. Otherwise the node of - * definition. - **/ - public Node addMappingAndRenderXNodeSet(String prefix, String uri,Attr n,boolean outputNode) { + + public int getLevel() { + // TODO Auto-generated method stub + return level.size(); + } + + public void removeMapping(String prefix) { NameSpaceSymbEntry ob = symb.get(prefix); - int visibleNameSpaces=nameSpaces; - if ((ob!=null) && uri.equals(ob.uri)) { - if (!ob.rendered) { - ob=(NameSpaceSymbEntry)ob.clone(); - needsClone(); - symb.put(prefix,ob); - ob.rendered=true; - ob.level=visibleNameSpaces; - return ob.n; - } - ob=(NameSpaceSymbEntry)ob.clone(); + + if (ob!=null) { needsClone(); - symb.put(prefix,ob); - if (outputNode && (((visibleNameSpaces-ob.level)<2) || XMLNS.equals(prefix)) ) { - ob.level=visibleNameSpaces; - return null; //Already rendered, just return nulll - } - ob.level=visibleNameSpaces; - return ob.n; - } + symb.put(prefix,null); + } + } - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true); - ne.level=nameSpaces; - ne.rendered=true; - needsClone(); - symb.put(prefix, ne); - if (ob != null) { - ne.lastrendered=ob.lastrendered; + public void removeMappingIfNotRender(String prefix) { + NameSpaceSymbEntry ob = symb.get(prefix); - if ((ob.lastrendered!=null)&& (ob.lastrendered.equals(uri))) { - ne.rendered=true; - } - } - return ne.n; + if (ob!=null && !ob.rendered) { + needsClone(); + symb.put(prefix,null); + } + } + + public boolean removeMappingIfRender(String prefix) { + NameSpaceSymbEntry ob = symb.get(prefix); + + if (ob!=null && ob.rendered) { + needsClone(); + symb.put(prefix,null); + } + return false; } } @@ -305,10 +290,11 @@ public class NameSpaceSymbTable { * The internal structure of NameSpaceSymbTable. **/ class NameSpaceSymbEntry implements Cloneable { - NameSpaceSymbEntry(String name,Attr n,boolean rendered) { + NameSpaceSymbEntry(String name,Attr n,boolean rendered,String prefix) { this.uri=name; this.rendered=rendered; this.n=n; + this.prefix=prefix; } /** @inheritDoc */ public Object clone() { @@ -320,6 +306,7 @@ class NameSpaceSymbEntry implements Cloneable { } /** The level where the definition was rendered(Only for inclusive) */ int level=0; + String prefix; /**The URI that the prefix defines */ String uri; /**The last output in the URI for this prefix (This for speed reason).*/ @@ -330,53 +317,57 @@ class NameSpaceSymbEntry implements Cloneable { Attr n; }; -class SymbMap implements Cloneable{ - int free=23; - NameSpaceSymbEntry[] entries=new NameSpaceSymbEntry[free]; - String[] keys=new String[free]; - - void put(String key, NameSpaceSymbEntry value) { +class SymbMap implements Cloneable { + int free=23; + NameSpaceSymbEntry[] entries; + String[] keys; + SymbMap() { + entries=new NameSpaceSymbEntry[free]; + keys=new String[free]; + } + void put(String key, NameSpaceSymbEntry value) { int index = index(key); - Object oldKey = keys[index]; - keys[index] = key; - entries[index] = value; + Object oldKey = keys[index]; + keys[index] = key; + entries[index] = value; if (oldKey==null || !oldKey.equals(key)) { - if (--free == 0) { - free=entries.length; - int newCapacity = free<<2; - rehash(newCapacity); - } + if (--free == 0) { + free=entries.length; + int newCapacity = free<<2; + rehash(newCapacity); + } } } List entrySet() { - List a=new ArrayList(); - for (int i=0;iint
    value @@ -384,37 +375,38 @@ class SymbMap implements Cloneable{ protected void rehash(int newCapacity) { int oldCapacity = keys.length; String oldKeys[] = keys; - NameSpaceSymbEntry oldVals[] = entries; + NameSpaceSymbEntry oldVals[] = entries; - keys = new String[newCapacity]; - entries = new NameSpaceSymbEntry[newCapacity]; + keys = new String[newCapacity]; + entries = new NameSpaceSymbEntry[newCapacity]; for (int i = oldCapacity; i-- > 0;) { if(oldKeys[i] != null) { String o = oldKeys[i]; int index = index(o); - keys[index] = o; - entries[index] = oldVals[i]; + keys[index] = o; + entries[index] = oldVals[i]; } } } - NameSpaceSymbEntry get(String key) { - return entries[index(key)]; - } - protected Object clone() { - // TODO Auto-generated method stub - try { - SymbMap copy=(SymbMap) super.clone(); - copy.entries=new NameSpaceSymbEntry[entries.length]; - System.arraycopy(entries,0,copy.entries,0,entries.length); - copy.keys=new String[keys.length]; - System.arraycopy(keys,0,copy.keys,0,keys.length); - - return copy; - } catch (CloneNotSupportedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; + + NameSpaceSymbEntry get(String key) { + return entries[index(key)]; + } + + protected Object clone() { + try { + SymbMap copy=(SymbMap) super.clone(); + copy.entries=new NameSpaceSymbEntry[entries.length]; + System.arraycopy(entries,0,copy.entries,0,entries.length); + copy.keys=new String[keys.length]; + System.arraycopy(keys,0,copy.keys,0,keys.length); + + return copy; + } catch (CloneNotSupportedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + return null; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java new file mode 100644 index 0000000000000000000000000000000000000000..cfcc06dd2c41c640c57398c16a256fd151c4b187 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java @@ -0,0 +1,155 @@ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +public class UtfHelpper { + + final static void writeByte(final String str,final OutputStream out,Map cache) throws IOException { + byte []result=(byte[]) cache.get(str); + if (result==null) { + result=getStringInUtf8(str); + cache.put(str,result); + } + + out.write(result); + + } + + final static void writeCharToUtf8(final char c,final OutputStream out) throws IOException{ + if (c < 0x80) { + out.write(c); + return; + } + if ((c >= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + out.write(0x3f); + return; + } + int bias; + int write; + char ch; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + out.write(write); + write=0x80; + bias=0x3F; + } else { + write=0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + out.write(write); + out.write(0x80 | ((c) & 0x3F)); + + } + + final static void writeStringToUtf8(final String str,final OutputStream out) throws IOException{ + final int length=str.length(); + int i=0; + char c; + while (i= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + out.write(0x3f); + continue; + } + char ch; + int bias; + int write; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + out.write(write); + write=0x80; + bias=0x3F; + } else { + write=0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + out.write(write); + out.write(0x80 | ((c) & 0x3F)); + + } + + } + public final static byte[] getStringInUtf8(final String str) { + final int length=str.length(); + boolean expanded=false; + byte []result=new byte[length]; + int i=0; + int out=0; + char c; + while (i= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + result[out++]=0x3f; + + continue; + } + if (!expanded) { + byte newResult[]=new byte[3*length]; + System.arraycopy(result, 0, newResult, 0, out); + result=newResult; + expanded=true; + } + char ch; + int bias; + byte write; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=(byte)0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + result[out++]=write; + write=(byte)0x80; + bias=0x3F; + } else { + write=(byte)0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + result[out++]=write; + result[out++]=(byte)(0x80 | ((c) & 0x3F));/**/ + + } + if (expanded) { + byte newResult[]=new byte[out]; + System.arraycopy(result, 0, newResult, 0, out); + result=newResult; + } + return result; + } + + + +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java index 7814216496dfa7dd9bd35ce8787e039efdca3d71..683acdbf003dc9a85579b3ff4a4576c37efec9f9 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java @@ -22,6 +22,7 @@ package com.sun.org.apache.xml.internal.security.encryption; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; @@ -30,6 +31,7 @@ import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -204,7 +206,7 @@ public class XMLCipher { * @since 1.0. */ private XMLCipher() { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher..."); _factory = new Factory(); _serializer = new Serializer(); @@ -266,7 +268,7 @@ public class XMLCipher { public static XMLCipher getInstance(String transformation) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(!isValidEncryptionAlgorithm(transformation)) @@ -294,7 +296,7 @@ public class XMLCipher { try { instance._contextCipher = Cipher.getInstance(jceAlgorithm); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + + logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + instance._contextCipher.getAlgorithm()); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); @@ -305,8 +307,39 @@ public class XMLCipher { return (instance); } - public static XMLCipher getInstance(String transformation,Cipher cipher) throws - XMLEncryptionException { + /** + * Returns an XMLCipher that implements the specified + * transformation, operates on the specified context document and serializes + * the document with the specified canonicalization algorithm before it + * encrypts the document. + *

    + * + * @param transformation the name of the transformation, e.g., + * XMLCipher.TRIPLEDES which is + * shorthand for + * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + * @param canon the name of the c14n algorithm, if + * null use standard serializer + * @return + * @throws XMLEncryptionException + */ + + public static XMLCipher getInstance(String transformation, String canon) + throws XMLEncryptionException { + XMLCipher instance = XMLCipher.getInstance(transformation); + + if (canon != null) { + try { + instance._canon = Canonicalizer.getInstance(canon); + } catch (InvalidCanonicalizerException ice) { + throw new XMLEncryptionException("empty", ice); + } + } + + return instance; + } + + public static XMLCipher getInstance(String transformation,Cipher cipher) throws XMLEncryptionException { // sanity checks logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) @@ -321,8 +354,8 @@ public class XMLCipher { instance._kek = null; - /* Create a canonicaliser - used when serialising DOM to octets - * prior to encryption (and for the reverse) */ + /* Create a canonicaliser - used when serialising DOM to octets + * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance @@ -346,41 +379,6 @@ public class XMLCipher { return (instance); } - - - /** - * Returns an XMLCipher that implements the specified - * transformation, operates on the specified context document and serializes - * the document with the specified canonicalization algorithm before it - * encrypts the document. - *

    - * - * @param transformation the name of the transformation, e.g., - * XMLCipher.TRIPLEDES which is - * shorthand for - * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" - * @param canon the name of the c14n algorithm, if - * null use standard serializer - * @return - * @throws XMLEncryptionException - */ - - public static XMLCipher getInstance(String transformation, String canon) - throws XMLEncryptionException { - XMLCipher instance = XMLCipher.getInstance(transformation); - - if (canon != null) { - try { - instance._canon = Canonicalizer.getInstance(canon); - } catch (InvalidCanonicalizerException ice) { - throw new XMLEncryptionException("empty", ice); - } - } - - return instance; - } - - /** * Returns an XMLCipher that implements the specified * transformation and operates on the specified context document. @@ -396,7 +394,7 @@ public class XMLCipher { public static XMLCipher getProviderInstance(String transformation, String provider) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(null == provider) @@ -429,9 +427,9 @@ public class XMLCipher { instance._contextCipher = Cipher.getInstance(jceAlgorithm, provider); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " + + logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " + instance._contextCipher.getAlgorithm()); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "provider.name = " + provider); + logger.log(java.util.logging.Level.FINE, "provider.name = " + provider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { @@ -490,7 +488,7 @@ public class XMLCipher { public static XMLCipher getInstance() throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation..."); XMLCipher instance = new XMLCipher(); @@ -532,7 +530,7 @@ public class XMLCipher { throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation"); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation"); if(null == provider) logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null.."); if("" == provider) @@ -578,7 +576,7 @@ public class XMLCipher { */ public void init(int opmode, Key key) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher..."); _ek = null; _ed = null; @@ -586,18 +584,18 @@ public class XMLCipher { switch (opmode) { case ENCRYPT_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE"); _ed = createEncryptedData(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case DECRYPT_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE"); break; case WRAP_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE"); _ek = createEncryptedKey(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case UNWRAP_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE"); break; default : logger.log(java.util.logging.Level.SEVERE, "Mode unexpectedly invalid"); @@ -622,7 +620,7 @@ public class XMLCipher { public EncryptedData getEncryptedData() { // Sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedData"); + logger.log(java.util.logging.Level.FINE, "Returning EncryptedData"); return _ed; } @@ -640,7 +638,7 @@ public class XMLCipher { public EncryptedKey getEncryptedKey() { // Sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey"); + logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey"); return _ek; } @@ -750,11 +748,11 @@ public class XMLCipher { */ private Document encryptElement(Element element) throws Exception{ - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); + logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); @@ -785,11 +783,11 @@ public class XMLCipher { */ private Document encryptElementContent(Element element) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element content..."); + logger.log(java.util.logging.Level.FINE, "Encrypting element content..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); @@ -815,7 +813,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Document source) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source document..."); + logger.log(java.util.logging.Level.FINE, "Processing source document..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == source) @@ -855,7 +853,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Element element) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); + logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -898,7 +896,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Element element, boolean content) throws /* XMLEncryption*/ Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); + logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -952,6 +950,34 @@ public class XMLCipher { return encryptData(context, element, false); } + /** + * Returns an EncryptedData interface. Use this operation if + * you want to have full control over the serialization of the element + * or element content. + * + * This does not change the source document in any way. + * + * @param context the context Document. + * @param type a URI identifying type information about the plaintext form + * of the encrypted content (may be null) + * @param serializedData the serialized data + * @return the EncryptedData + * @throws Exception + */ + public EncryptedData encryptData(Document context, String type, + InputStream serializedData) throws Exception { + + logger.log(java.util.logging.Level.FINE, "Encrypting element..."); + if (null == context) + logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); + if (null == serializedData) + logger.log(java.util.logging.Level.SEVERE, "Serialized data unexpectedly null..."); + if (_cipherMode != ENCRYPT_MODE) + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + + return encryptData(context, null, type, serializedData); + } + /** * Returns an EncryptedData interface. Use this operation if * you want to have full control over the contents of the @@ -966,160 +992,60 @@ public class XMLCipher { * @return the EncryptedData * @throws Exception */ - public EncryptedData encryptData(Document context, Element element, boolean contentMode) throws - /* XMLEncryption */ Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); - if (null == context) - logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); - if (null == element) - logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); - if (_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + public EncryptedData encryptData( + Document context, Element element, boolean contentMode) + throws /* XMLEncryption */ Exception { - _contextDocument = context; - - if (_algorithm == null) { - throw new XMLEncryptionException("XMLCipher instance without transformation specified"); - } - - String serializedOctets = null; - if (contentMode) { - NodeList children = element.getChildNodes(); - if ((null != children)) { - serializedOctets = _serializer.serialize(children); - } else { - Object exArgs[] = { "Element has no content." }; - throw new XMLEncryptionException("empty", exArgs); - } - } else { - serializedOctets = _serializer.serialize(element); - } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); - - byte[] encryptedBytes = null; - - // Now create the working cipher if none was created already - Cipher c; - if (_contextCipher == null) { - String jceAlgorithm = - JCEMapper.translateURItoJCEID(_algorithm); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); - - try { - if (_requestedJCEProvider == null) - c = Cipher.getInstance(jceAlgorithm); - else - c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); - } catch (NoSuchAlgorithmException nsae) { - throw new XMLEncryptionException("empty", nsae); - } catch (NoSuchProviderException nspre) { - throw new XMLEncryptionException("empty", nspre); - } catch (NoSuchPaddingException nspae) { - throw new XMLEncryptionException("empty", nspae); - } - } - else { - c = _contextCipher; - } - // Now perform the encryption - - try { - // Should internally generate an IV - // todo - allow user to set an IV - c.init(_cipherMode, _key); - } catch (InvalidKeyException ike) { - throw new XMLEncryptionException("empty", ike); - } - - try { - encryptedBytes = - c.doFinal(serializedOctets.getBytes("UTF-8")); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + - Integer.toString(c.getOutputSize( - serializedOctets.getBytes().length))); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + - Integer.toString(encryptedBytes.length)); - } catch (IllegalStateException ise) { - throw new XMLEncryptionException("empty", ise); - } catch (IllegalBlockSizeException ibse) { - throw new XMLEncryptionException("empty", ibse); - } catch (BadPaddingException bpe) { - throw new XMLEncryptionException("empty", bpe); - } catch (UnsupportedEncodingException uee) { - throw new XMLEncryptionException("empty", uee); - } - - // Now build up to a properly XML Encryption encoded octet stream - // IvParameterSpec iv; - - byte[] iv = c.getIV(); - byte[] finalEncryptedBytes = - new byte[iv.length + encryptedBytes.length]; - System.arraycopy(iv, 0, finalEncryptedBytes, 0, - iv.length); - System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, - iv.length, - encryptedBytes.length); - - String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + - base64EncodedEncryptedOctets.length()); - - try { - CipherData cd = _ed.getCipherData(); - CipherValue cv = cd.getCipherValue(); - // cv.setValue(base64EncodedEncryptedOctets.getBytes()); - cv.setValue(base64EncodedEncryptedOctets); - - if (contentMode) { - _ed.setType( - new URI(EncryptionConstants.TYPE_CONTENT).toString()); - } else { - _ed.setType( - new URI(EncryptionConstants.TYPE_ELEMENT).toString()); - } - EncryptionMethod method = - _factory.newEncryptionMethod(new URI(_algorithm).toString()); - _ed.setEncryptionMethod(method); - } catch (URI.MalformedURIException mfue) { - throw new XMLEncryptionException("empty", mfue); - } - return (_ed); - } - - - - public EncryptedData encryptData(Document context, byte [] serializedOctets, boolean contentMode) throws - /* XMLEncryption */ Exception { logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if (null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); - if (null == serializedOctets) - logger.log(java.util.logging.Level.SEVERE, "Canonicalized Data is unexpectedly null..."); + if (null == element) + logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if (_cipherMode != ENCRYPT_MODE) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + if (contentMode) { + return encryptData + (context, element, EncryptionConstants.TYPE_CONTENT, null); + } else { + return encryptData + (context, element, EncryptionConstants.TYPE_ELEMENT, null); + } + } + + private EncryptedData encryptData( + Document context, Element element, String type, + InputStream serializedData) throws /* XMLEncryption */ Exception { + _contextDocument = context; if (_algorithm == null) { - throw new XMLEncryptionException("XMLCipher instance without transformation specified"); + throw new XMLEncryptionException + ("XMLCipher instance without transformation specified"); } - - logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); + String serializedOctets = null; + if (serializedData == null) { + if (type == EncryptionConstants.TYPE_CONTENT) { + NodeList children = element.getChildNodes(); + if (null != children) { + serializedOctets = _serializer.serialize(children); + } else { + Object exArgs[] = { "Element has no content." }; + throw new XMLEncryptionException("empty", exArgs); + } + } else { + serializedOctets = _serializer.serialize(element); + } + logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); + } byte[] encryptedBytes = null; // Now create the working cipher if none was created already Cipher c; if (_contextCipher == null) { - String jceAlgorithm = - JCEMapper.translateURItoJCEID(_algorithm); - + String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { @@ -1148,41 +1074,47 @@ public class XMLCipher { } try { - encryptedBytes = - c.doFinal(serializedOctets); - - logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + + if (serializedData != null) { + int numBytes; + byte[] buf = new byte[8192]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((numBytes = serializedData.read(buf)) != -1) { + byte[] data = c.update(buf, 0, numBytes); + baos.write(data); + } + baos.write(c.doFinal()); + encryptedBytes = baos.toByteArray(); + } else { + encryptedBytes = c.doFinal(serializedOctets.getBytes("UTF-8")); + logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + Integer.toString(c.getOutputSize( - serializedOctets.length))); + serializedOctets.getBytes().length))); + } logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + - Integer.toString(encryptedBytes.length)); + Integer.toString(encryptedBytes.length)); } catch (IllegalStateException ise) { throw new XMLEncryptionException("empty", ise); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } catch (BadPaddingException bpe) { throw new XMLEncryptionException("empty", bpe); - } catch (Exception uee) { + } catch (UnsupportedEncodingException uee) { throw new XMLEncryptionException("empty", uee); } // Now build up to a properly XML Encryption encoded octet stream // IvParameterSpec iv; - byte[] iv = c.getIV(); byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length]; - System.arraycopy(iv, 0, finalEncryptedBytes, 0, - iv.length); - System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, - iv.length, - encryptedBytes.length); - + System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length); + System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, + encryptedBytes.length); String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + - base64EncodedEncryptedOctets.length()); + base64EncodedEncryptedOctets.length()); try { CipherData cd = _ed.getCipherData(); @@ -1190,15 +1122,11 @@ public class XMLCipher { // cv.setValue(base64EncodedEncryptedOctets.getBytes()); cv.setValue(base64EncodedEncryptedOctets); - if (contentMode) { - _ed.setType( - new URI(EncryptionConstants.TYPE_CONTENT).toString()); - } else { - _ed.setType( - new URI(EncryptionConstants.TYPE_ELEMENT).toString()); + if (type != null) { + _ed.setType(new URI(type).toString()); } EncryptionMethod method = - _factory.newEncryptionMethod(new URI(_algorithm).toString()); + _factory.newEncryptionMethod(new URI(_algorithm).toString()); _ed.setEncryptionMethod(method); } catch (URI.MalformedURIException mfue) { throw new XMLEncryptionException("empty", mfue); @@ -1206,7 +1134,6 @@ public class XMLCipher { return (_ed); } - /** * Returns an EncryptedData interface. Use this operation if * you want to load an EncryptedData structure from a DOM @@ -1219,7 +1146,7 @@ public class XMLCipher { */ public EncryptedData loadEncryptedData(Document context, Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted element..."); + logger.log(java.util.logging.Level.FINE, "Loading encrypted element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -1246,13 +1173,13 @@ public class XMLCipher { public EncryptedKey loadEncryptedKey(Document context, Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted key..."); + logger.log(java.util.logging.Level.FINE, "Loading encrypted key..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != UNWRAP_MODE && _cipherMode != DECRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."); _contextDocument = context; _ek = _factory.newEncryptedKey(element); @@ -1290,12 +1217,12 @@ public class XMLCipher { public EncryptedKey encryptKey(Document doc, Key key) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting key ..."); + logger.log(java.util.logging.Level.FINE, "Encrypting key ..."); if(null == key) logger.log(java.util.logging.Level.SEVERE, "Key unexpectedly null..."); if(_cipherMode != WRAP_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE..."); if (_algorithm == null) { @@ -1313,7 +1240,7 @@ public class XMLCipher { String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); + logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { if (_requestedJCEProvider == null) @@ -1345,8 +1272,8 @@ public class XMLCipher { String base64EncodedEncryptedOctets = Base64.encode(encryptedBytes); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + + logger.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets); + logger.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + base64EncodedEncryptedOctets.length()); CipherValue cv = _ek.getCipherData().getCipherValue(); @@ -1376,10 +1303,10 @@ public class XMLCipher { public Key decryptKey(EncryptedKey encryptedKey, String algorithm) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey..."); + logger.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey..."); if(_cipherMode != UNWRAP_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE..."); if (algorithm == null) { throw new XMLEncryptionException("Cannot decrypt a key without knowing the algorithm"); @@ -1387,7 +1314,7 @@ public class XMLCipher { if (_key == null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers"); + logger.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers"); KeyInfo ki = encryptedKey.getKeyInfo(); if (ki != null) { @@ -1418,7 +1345,7 @@ public class XMLCipher { JCEMapper.translateURItoJCEID( encryptedKey.getEncryptionMethod().getAlgorithm()); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm); + logger.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm); try { if (_requestedJCEProvider == null) @@ -1448,7 +1375,7 @@ public class XMLCipher { throw new XMLEncryptionException("empty", nsae); } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK"); + logger.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK"); return ret; @@ -1478,14 +1405,9 @@ public class XMLCipher { * * @param node the Node to clear. */ - private void removeContent(Node node) { - NodeList list = node.getChildNodes(); - if (list.getLength() > 0) { - Node n = list.item(0); - if (null != n) { - n.getParentNode().removeChild(n); - } - removeContent(node); + private static void removeContent(Node node) { + while (node.hasChildNodes()) { + node.removeChild(node.getFirstChild()); } } @@ -1499,7 +1421,7 @@ public class XMLCipher { private Document decryptElement(Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting element..."); + logger.log(java.util.logging.Level.FINE, "Decrypting element..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); @@ -1512,7 +1434,7 @@ public class XMLCipher { } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + octets); + logger.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + octets); Node sourceParent = element.getParentNode(); @@ -1573,7 +1495,7 @@ public class XMLCipher { public byte[] decryptToByteArray(Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting to ByteArray..."); + logger.log(java.util.logging.Level.FINE, "Decrypting to ByteArray..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); @@ -2226,7 +2148,7 @@ public class XMLCipher { AgreementMethod newAgreementMethod(Element element) throws XMLEncryptionException { if (null == element) { - //complain + throw new NullPointerException("element is null"); } String algorithm = element.getAttributeNS(null, @@ -2292,7 +2214,7 @@ public class XMLCipher { CipherData newCipherData(Element element) throws XMLEncryptionException { if (null == element) { - // complain + throw new NullPointerException("element is null"); } int type = 0; @@ -2352,7 +2274,7 @@ public class XMLCipher { (Element) transformsElements.item(0); if (transformsElement != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element"); + logger.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element"); try { result.setTransforms(new TransformsImpl(transformsElement)); } @@ -2411,34 +2333,28 @@ public class XMLCipher { XMLEncryptionException { EncryptedData result = null; - NodeList dataElements = element.getElementsByTagNameNS( - EncryptionConstants.EncryptionSpecNS, - EncryptionConstants._TAG_CIPHERDATA); + NodeList dataElements = element.getElementsByTagNameNS( + EncryptionConstants.EncryptionSpecNS, + EncryptionConstants._TAG_CIPHERDATA); - // Need to get the last CipherData found, as earlier ones will - // be for elements in the KeyInfo lists + // Need to get the last CipherData found, as earlier ones will + // be for elements in the KeyInfo lists Element dataElement = - (Element) dataElements.item(dataElements.getLength() - 1); + (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedData(data); - try { - result.setId(element.getAttributeNS( - null, EncryptionConstants._ATT_ID)); - result.setType(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TYPE)).toString()); - result.setMimeType(element.getAttributeNS( - null, EncryptionConstants._ATT_MIMETYPE)); - result.setEncoding(new URI( - element.getAttributeNS( - null, Constants._ATT_ENCODING)).toString()); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setId(element.getAttributeNS( + null, EncryptionConstants._ATT_ID)); + result.setType( + element.getAttributeNS(null, EncryptionConstants._ATT_TYPE)); + result.setMimeType(element.getAttributeNS( + null, EncryptionConstants._ATT_MIMETYPE)); + result.setEncoding( + element.getAttributeNS(null, Constants._ATT_ENCODING)); Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( @@ -2450,18 +2366,18 @@ public class XMLCipher { } // BFL 16/7/03 - simple implementation - // TODO: Work out how to handle relative URI + // TODO: Work out how to handle relative URI Element keyInfoElement = (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { - try { - result.setKeyInfo(new KeyInfo(keyInfoElement, null)); - } catch (XMLSecurityException xse) { - throw new XMLEncryptionException("Error loading Key Info", - xse); - } + try { + result.setKeyInfo(new KeyInfo(keyInfoElement, null)); + } catch (XMLSecurityException xse) { + throw new XMLEncryptionException("Error loading Key Info", + xse); + } } // TODO: Implement @@ -2511,31 +2427,25 @@ public class XMLCipher { EncryptedKey newEncryptedKey(Element element) throws XMLEncryptionException { EncryptedKey result = null; - NodeList dataElements = element.getElementsByTagNameNS( - EncryptionConstants.EncryptionSpecNS, - EncryptionConstants._TAG_CIPHERDATA); + NodeList dataElements = element.getElementsByTagNameNS( + EncryptionConstants.EncryptionSpecNS, + EncryptionConstants._TAG_CIPHERDATA); Element dataElement = - (Element) dataElements.item(dataElements.getLength() - 1); + (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedKey(data); - try { - result.setId(element.getAttributeNS( - null, EncryptionConstants._ATT_ID)); - result.setType(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TYPE)).toString()); - result.setMimeType(element.getAttributeNS( - null, EncryptionConstants._ATT_MIMETYPE)); - result.setEncoding(new URI( - element.getAttributeNS( - null, Constants._ATT_ENCODING)).toString()); - result.setRecipient(element.getAttributeNS( - null, EncryptionConstants._ATT_RECIPIENT)); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setId(element.getAttributeNS( + null, EncryptionConstants._ATT_ID)); + result.setType( + element.getAttributeNS(null, EncryptionConstants._ATT_TYPE)); + result.setMimeType(element.getAttributeNS( + null, EncryptionConstants._ATT_MIMETYPE)); + result.setEncoding( + element.getAttributeNS(null, Constants._ATT_ENCODING)); + result.setRecipient(element.getAttributeNS( + null, EncryptionConstants._ATT_RECIPIENT)); Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( @@ -2550,12 +2460,12 @@ public class XMLCipher { (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { - try { - result.setKeyInfo(new KeyInfo(keyInfoElement, null)); - } catch (XMLSecurityException xse) { - throw new XMLEncryptionException("Error loading Key Info", - xse); - } + try { + result.setKeyInfo(new KeyInfo(keyInfoElement, null)); + } catch (XMLSecurityException xse) { + throw new XMLEncryptionException + ("Error loading Key Info", xse); + } } // TODO: Implement @@ -2581,7 +2491,8 @@ public class XMLCipher { EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CARRIEDKEYNAME).item(0); if (null != carriedNameElement) { - result.setCarriedName(carriedNameElement.getNodeValue()); + result.setCarriedName + (carriedNameElement.getFirstChild().getNodeValue()); } return (result); @@ -2680,13 +2591,8 @@ public class XMLCipher { EncryptionProperty newEncryptionProperty(Element element) { EncryptionProperty result = newEncryptionProperty(); - try { - result.setTarget(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TARGET)).toString()); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setTarget( + element.getAttributeNS(null, EncryptionConstants._ATT_TARGET)); result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); // TODO: Make this lot work... @@ -2943,7 +2849,7 @@ public class XMLCipher { } catch (URI.MalformedURIException mfue) { //complain } - algorithm = tmpAlgorithm.toString(); + algorithmURI = tmpAlgorithm.toString(); } // @@ -3183,7 +3089,7 @@ public class XMLCipher { _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERVALUE); result.appendChild(_contextDocument.createTextNode( - new String(cipherValue))); + cipherValue)); return (result); } @@ -3247,8 +3153,7 @@ public class XMLCipher { } if (null != super.getType()) { result.setAttributeNS( - null, EncryptionConstants._ATT_TYPE, - super.getType().toString()); + null, EncryptionConstants._ATT_TYPE, super.getType()); } if (null != super.getMimeType()) { result.setAttributeNS( @@ -3258,7 +3163,7 @@ public class XMLCipher { if (null != super.getEncoding()) { result.setAttributeNS( null, EncryptionConstants._ATT_ENCODING, - super.getEncoding().toString()); + super.getEncoding()); } if (null != super.getEncryptionMethod()) { result.appendChild(((EncryptionMethodImpl) @@ -3383,8 +3288,7 @@ public class XMLCipher { } if (null != super.getType()) { result.setAttributeNS( - null, EncryptionConstants._ATT_TYPE, - super.getType().toString()); + null, EncryptionConstants._ATT_TYPE, super.getType()); } if (null != super.getMimeType()) { result.setAttributeNS(null, @@ -3392,7 +3296,7 @@ public class XMLCipher { } if (null != super.getEncoding()) { result.setAttributeNS(null, Constants._ATT_ENCODING, - super.getEncoding().toString()); + super.getEncoding()); } if (null != getRecipient()) { result.setAttributeNS(null, @@ -3468,13 +3372,17 @@ public class XMLCipher { * @param type */ public void setType(String type) { - URI tmpType = null; - try { - tmpType = new URI(type); - } catch (URI.MalformedURIException mfue) { - // complain + if (type == null || type.length() == 0) { + this.type = null; + } else { + URI tmpType = null; + try { + tmpType = new URI(type); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.type = tmpType.toString(); } - this.type = tmpType.toString(); } /** * @@ -3502,13 +3410,17 @@ public class XMLCipher { * @param encoding */ public void setEncoding(String encoding) { - URI tmpEncoding = null; - try { - tmpEncoding = new URI(encoding); - } catch (URI.MalformedURIException mfue) { - // complain + if (encoding == null || encoding.length() == 0) { + this.encoding = null; + } else { + URI tmpEncoding = null; + try { + tmpEncoding = new URI(encoding); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.encoding = tmpEncoding.toString(); } - this.encoding = tmpEncoding.toString(); } /** * @@ -3635,7 +3547,7 @@ public class XMLCipher { _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD); result.setAttributeNS(null, EncryptionConstants._ATT_ALGORITHM, - algorithm.toString()); + algorithm); if (keySize > 0) { result.appendChild( ElementProxy.createElementForFamily(_contextDocument, @@ -3735,8 +3647,7 @@ public class XMLCipher { private class EncryptionPropertyImpl implements EncryptionProperty { private String target = null; private String id = null; - private String attributeName = null; - private String attributeValue = null; + private HashMap attributeMap = new HashMap(); private List encryptionInformation = null; /** @@ -3752,13 +3663,24 @@ public class XMLCipher { } /** @inheritDoc */ public void setTarget(String target) { - URI tmpTarget = null; - try { - tmpTarget = new URI(target); - } catch (URI.MalformedURIException mfue) { - // complain + if (target == null || target.length() == 0) { + this.target = null; + } else if (target.startsWith("#")) { + /* + * This is a same document URI reference. Do not parse, + * because com.sun.org.apache.xml.internal.utils.URI considers this an + * illegal URI because it has no scheme. + */ + this.target = target; + } else { + URI tmpTarget = null; + try { + tmpTarget = new URI(target); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.target = tmpTarget.toString(); } - this.target = tmpTarget.toString(); } /** @inheritDoc */ public String getId() { @@ -3770,12 +3692,11 @@ public class XMLCipher { } /** @inheritDoc */ public String getAttribute(String attribute) { - return (attributeValue); + return (String) attributeMap.get(attribute); } /** @inheritDoc */ public void setAttribute(String attribute, String value) { - attributeName = attribute; - attributeValue = value; + attributeMap.put(attribute, value); } /** @inheritDoc */ public Iterator getEncryptionInformation() { @@ -3805,7 +3726,7 @@ public class XMLCipher { EncryptionConstants._TAG_ENCRYPTIONPROPERTY); if (null != target) { result.setAttributeNS(null, EncryptionConstants._ATT_TARGET, - target.toString()); + target); } if (null != id) { result.setAttributeNS(null, EncryptionConstants._ATT_ID, @@ -3839,7 +3760,13 @@ public class XMLCipher { * @param doc */ public TransformsImpl(Document doc) { - super(doc); + if (doc == null) { + throw new RuntimeException("Document is null"); + } + + this._doc = doc; + this._constructionElement = createElementForFamilyLocal(this._doc, + this.getBaseNamespace(), this.getBaseLocalName()); } /** * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java index 9d1db588eb6d25d52d7abd05a31d211e744248e3..65b9a604b661bc08063b161ce47ee8c84cb0a955 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java @@ -108,84 +108,78 @@ public class XMLCipherInput { return null; } - /** - * Internal method to get bytes in decryption mode + /** + * Internal method to get bytes in decryption mode * @return the decripted bytes * @throws XMLEncryptionException - */ - - private byte[] getDecryptBytes() throws XMLEncryptionException { + */ + private byte[] getDecryptBytes() throws XMLEncryptionException { - String base64EncodedEncryptedOctets = null; + String base64EncodedEncryptedOctets = null; if (_cipherData.getDataType() == CipherData.REFERENCE_TYPE) { - // Fun time! - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Found a reference type CipherData"); - CipherReference cr = _cipherData.getCipherReference(); - - // Need to wrap the uri in an Attribute node so that we can - // Pass to the resource resolvers - - Attr uriAttr = cr.getURIAsAttr(); - XMLSignatureInput input = null; - - try { - ResourceResolver resolver = - ResourceResolver.getInstance(uriAttr, null); - input = resolver.resolve(uriAttr, null); - } catch (ResourceResolverException ex) { - throw new XMLEncryptionException("empty", ex); - } - - if (input != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Managed to resolve URI \"" + cr.getURI() + "\""); - } - else { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Failed to resolve URI \"" + cr.getURI() + "\""); - } - - // Lets see if there are any transforms - Transforms transforms = cr.getTransforms(); - if (transforms != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Have transforms in cipher reference"); - try { - com.sun.org.apache.xml.internal.security.transforms.Transforms dsTransforms = - transforms.getDSTransforms(); - input = dsTransforms.performTransforms(input); - } catch (TransformationException ex) { - throw new XMLEncryptionException("empty", ex); - } - } - - try { - return input.getBytes(); - } - catch (IOException ex) { - throw new XMLEncryptionException("empty", ex); - } catch (CanonicalizationException ex) { - throw new XMLEncryptionException("empty", ex); - } - - // retrieve the cipher text + // Fun time! + logger.log(java.util.logging.Level.FINE, "Found a reference type CipherData"); + CipherReference cr = _cipherData.getCipherReference(); + + // Need to wrap the uri in an Attribute node so that we can + // Pass to the resource resolvers + + Attr uriAttr = cr.getURIAsAttr(); + XMLSignatureInput input = null; + + try { + ResourceResolver resolver = + ResourceResolver.getInstance(uriAttr, null); + input = resolver.resolve(uriAttr, null); + } catch (ResourceResolverException ex) { + throw new XMLEncryptionException("empty", ex); + } + + if (input != null) { + logger.log(java.util.logging.Level.FINE, "Managed to resolve URI \"" + cr.getURI() + "\""); + } else { + logger.log(java.util.logging.Level.FINE, "Failed to resolve URI \"" + cr.getURI() + "\""); + } + + // Lets see if there are any transforms + Transforms transforms = cr.getTransforms(); + if (transforms != null) { + logger.log(java.util.logging.Level.FINE, "Have transforms in cipher reference"); + try { + com.sun.org.apache.xml.internal.security.transforms.Transforms dsTransforms = + transforms.getDSTransforms(); + input = dsTransforms.performTransforms(input); + } catch (TransformationException ex) { + throw new XMLEncryptionException("empty", ex); + } + } + + try { + return input.getBytes(); + } catch (IOException ex) { + throw new XMLEncryptionException("empty", ex); + } catch (CanonicalizationException ex) { + throw new XMLEncryptionException("empty", ex); + } + + // retrieve the cipher text } else if (_cipherData.getDataType() == CipherData.VALUE_TYPE) { - CipherValue cv = _cipherData.getCipherValue(); - base64EncodedEncryptedOctets = new String(cv.getValue()); + base64EncodedEncryptedOctets = + _cipherData.getCipherValue().getValue(); } else { - throw new XMLEncryptionException("CipherData.getDataType() returned unexpected value"); - } + throw new XMLEncryptionException("CipherData.getDataType() returned unexpected value"); + } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); + logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); byte[] encryptedBytes = null; - try { - encryptedBytes = Base64.decode(base64EncodedEncryptedOctets); + encryptedBytes = Base64.decode(base64EncodedEncryptedOctets); } catch (Base64DecodingException bde) { throw new XMLEncryptionException("empty", bde); } - return (encryptedBytes); - - } - + return (encryptedBytes); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java index e071b1474c62dd13a6a77bb535c2b5d35420c213..6477d9bba2c24a1bd37ecb7f80677976e8529527 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class ContentHandlerAlreadyRegisteredException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java index 1750257f625d0937cf4daa87e815250ce7f455e7..cf588b8d488fa6eac65c5b7ad333ee226961b13e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java @@ -25,6 +25,8 @@ package com.sun.org.apache.xml.internal.security.keys; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import javax.crypto.SecretKey; @@ -88,15 +90,22 @@ import org.w3c.dom.NodeList; * The containsXXX() methods return whether the KeyInfo * contains the corresponding type. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyInfo extends SignatureElementProxy { /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(KeyInfo.class.getName()); + List x509Datas=null; + List encryptedKeys=null; - + static final List nullList; + static { + List list = new ArrayList(); + list.add(null); + nullList = Collections.unmodifiableList(list); + } /** * Constructor KeyInfo @@ -108,7 +117,6 @@ public class KeyInfo extends SignatureElementProxy { XMLUtils.addReturnToElement(this._constructionElement); - } /** @@ -119,8 +127,8 @@ public class KeyInfo extends SignatureElementProxy { * @throws XMLSecurityException */ public KeyInfo(Element element, String BaseURI) throws XMLSecurityException { - super(element, BaseURI); + // _storageResolvers.add(null); } @@ -131,7 +139,7 @@ public class KeyInfo extends SignatureElementProxy { */ public void setId(String Id) { - if ((this._state == MODE_SIGN) && (Id != null)) { + if ((Id != null)) { this._constructionElement.setAttributeNS(null, Constants._ATT_ID, Id); IdResolver.registerElementById(this._constructionElement, Id); } @@ -162,10 +170,8 @@ public class KeyInfo extends SignatureElementProxy { */ public void add(KeyName keyname) { - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(keyname.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -219,11 +225,8 @@ public class KeyInfo extends SignatureElementProxy { * @param keyvalue */ public void add(KeyValue keyvalue) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(keyvalue.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -241,11 +244,8 @@ public class KeyInfo extends SignatureElementProxy { * @param mgmtdata */ public void add(MgmtData mgmtdata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(mgmtdata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -254,11 +254,8 @@ public class KeyInfo extends SignatureElementProxy { * @param pgpdata */ public void add(PGPData pgpdata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(pgpdata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -279,11 +276,8 @@ public class KeyInfo extends SignatureElementProxy { * @param retrievalmethod */ public void add(RetrievalMethod retrievalmethod) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(retrievalmethod.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -292,11 +286,8 @@ public class KeyInfo extends SignatureElementProxy { * @param spkidata */ public void add(SPKIData spkidata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(spkidata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -305,11 +296,11 @@ public class KeyInfo extends SignatureElementProxy { * @param x509data */ public void add(X509Data x509data) { - - if (this._state == MODE_SIGN) { + if (x509Datas==null) + x509Datas=new ArrayList(); + x509Datas.add(x509data); this._constructionElement.appendChild(x509data.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -321,12 +312,11 @@ public class KeyInfo extends SignatureElementProxy { public void add(EncryptedKey encryptedKey) throws XMLEncryptionException { - - if (this._state == MODE_SIGN) { + if (encryptedKeys==null) + encryptedKeys=new ArrayList(); + encryptedKeys.add(encryptedKey); XMLCipher cipher = XMLCipher.getInstance(); this._constructionElement.appendChild(cipher.martial(encryptedKey)); - } - } /** @@ -335,11 +325,8 @@ public class KeyInfo extends SignatureElementProxy { * @param element */ public void addUnknownElement(Element element) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(element); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -403,6 +390,9 @@ public class KeyInfo extends SignatureElementProxy { *@return the number of the X509Data tags */ public int lengthX509Data() { + if (x509Datas!=null) { + return x509Datas.size(); + } return this.length(Constants.SignatureSpecNS, Constants._TAG_X509DATA); } @@ -550,7 +540,9 @@ public class KeyInfo extends SignatureElementProxy { * @throws XMLSecurityException */ public X509Data itemX509Data(int i) throws XMLSecurityException { - + if (x509Datas!=null) { + return (X509Data) x509Datas.get(i); + } Element e = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), Constants._TAG_X509DATA,i); @@ -569,7 +561,9 @@ public class KeyInfo extends SignatureElementProxy { */ public EncryptedKey itemEncryptedKey(int i) throws XMLSecurityException { - + if (encryptedKeys!=null) { + return (EncryptedKey) encryptedKeys.get(i); + } Element e = XMLUtils.selectXencNode(this._constructionElement.getFirstChild(), EncryptionConstants._TAG_ENCRYPTEDKEY,i); @@ -707,20 +701,20 @@ public class KeyInfo extends SignatureElementProxy { PublicKey pk = this.getPublicKeyFromInternalResolvers(); if (pk != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I could find a key using the per-KeyInfo key resolvers"); + log.log(java.util.logging.Level.FINE, "I could find a key using the per-KeyInfo key resolvers"); return pk; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I couldn't find a key using the per-KeyInfo key resolvers"); + log.log(java.util.logging.Level.FINE, "I couldn't find a key using the per-KeyInfo key resolvers"); pk = this.getPublicKeyFromStaticResolvers(); if (pk != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I could find a key using the system-wide key resolvers"); + log.log(java.util.logging.Level.FINE, "I could find a key using the system-wide key resolvers"); return pk; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I couldn't find a key using the system-wide key resolvers"); + log.log(java.util.logging.Level.FINE, "I couldn't find a key using the system-wide key resolvers"); return null; } @@ -732,46 +726,29 @@ public class KeyInfo extends SignatureElementProxy { * @throws KeyResolverException */ PublicKey getPublicKeyFromStaticResolvers() throws KeyResolverException { - - for (int i = 0; i < KeyResolver.length(); i++) { - KeyResolver keyResolver = KeyResolver.item(i); + int length=KeyResolver.length(); + int storageLength=this._storageResolvers.size(); + Iterator it= KeyResolver.iterator(); + for (int i = 0; i < length; i++) { + KeyResolverSpi keyResolver = (KeyResolverSpi) it.next(); Node currentChild=this._constructionElement.getFirstChild(); + String uri= this.getBaseURI(); while (currentChild!=null) { if (currentChild.getNodeType() == Node.ELEMENT_NODE) { - if (this._storageResolvers.size() == 0) { - - // if we do not have storage resolvers, we verify with null - StorageResolver storage = null; - - if (keyResolver.canResolve((Element) currentChild, - this.getBaseURI(), storage)) { - PublicKey pk = - keyResolver.resolvePublicKey((Element) currentChild, - this.getBaseURI(), - storage); - - if (pk != null) { - return pk; - } - } - } else { - for (int k = 0; k < this._storageResolvers.size(); k++) { + for (int k = 0; k < storageLength; k++) { StorageResolver storage = (StorageResolver) this._storageResolvers.get(k); - if (keyResolver.canResolve((Element) currentChild, - this.getBaseURI(), storage)) { - PublicKey pk = - keyResolver.resolvePublicKey((Element) currentChild, - this.getBaseURI(), + PublicKey pk = + keyResolver.engineLookupAndResolvePublicKey((Element) currentChild, + uri, storage); - if (pk != null) { - return pk; - } + if (pk != null) { + KeyResolver.hit(it); + return pk; } } - } } currentChild=currentChild.getNextSibling(); } @@ -786,50 +763,27 @@ public class KeyInfo extends SignatureElementProxy { * @throws KeyResolverException */ PublicKey getPublicKeyFromInternalResolvers() throws KeyResolverException { - - for (int i = 0; i < this.lengthInternalKeyResolver(); i++) { + int length=lengthInternalKeyResolver(); + int storageLength=this._storageResolvers.size(); + for (int i = 0; i < length; i++) { KeyResolverSpi keyResolver = this.itemInternalKeyResolver(i); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Try " + keyResolver.getClass().getName()); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Try " + keyResolver.getClass().getName()); Node currentChild=this._constructionElement.getFirstChild(); + String uri=this.getBaseURI(); while (currentChild!=null) { if (currentChild.getNodeType() == Node.ELEMENT_NODE) { - if (this._storageResolvers.size() == 0) { - - // if we do not have storage resolvers, we verify with null - StorageResolver storage = null; - - if (keyResolver.engineCanResolve((Element) currentChild, - this.getBaseURI(), - storage)) { - PublicKey pk = - keyResolver - .engineResolvePublicKey((Element) currentChild, this - .getBaseURI(), storage); + for (int k = 0; k < storageLength; k++) { + StorageResolver storage = + (StorageResolver) this._storageResolvers.get(k); + PublicKey pk = keyResolver + .engineLookupAndResolvePublicKey((Element) currentChild, uri, storage); if (pk != null) { - return pk; + return pk; } } - } else { - for (int k = 0; k < this._storageResolvers.size(); k++) { - StorageResolver storage = - (StorageResolver) this._storageResolvers.get(k); - - if (keyResolver.engineCanResolve((Element) currentChild, - this.getBaseURI(), - storage)) { - PublicKey pk = keyResolver - .engineResolvePublicKey((Element) currentChild, this - .getBaseURI(), storage); - - if (pk != null) { - return pk; - } - } - } - } } currentChild=currentChild.getNextSibling(); } @@ -850,12 +804,12 @@ public class KeyInfo extends SignatureElementProxy { X509Certificate cert = this.getX509CertificateFromInternalResolvers(); if (cert != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I could find a X509Certificate using the per-KeyInfo key resolvers"); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I couldn't find a X509Certificate using the per-KeyInfo key resolvers"); @@ -863,12 +817,12 @@ public class KeyInfo extends SignatureElementProxy { cert = this.getX509CertificateFromStaticResolvers(); if (cert != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I could find a X509Certificate using the system-wide key resolvers"); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I couldn't find a X509Certificate using the system-wide key resolvers"); @@ -885,53 +839,44 @@ public class KeyInfo extends SignatureElementProxy { */ X509Certificate getX509CertificateFromStaticResolvers() throws KeyResolverException { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Start getX509CertificateFromStaticResolvers() with " + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Start getX509CertificateFromStaticResolvers() with " + KeyResolver.length() + " resolvers"); + String uri=this.getBaseURI(); + int length= KeyResolver.length(); + int storageLength=this._storageResolvers.size(); + Iterator it = KeyResolver.iterator(); + for (int i = 0; i com.sun.org.apache.xml.internal.security.keys package. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyUtils { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java index ba9769043a39e229a21f4b918adc9cf86adc7d3f..4d5a7a6b975f6f30b490cdaa0248d0707f6eae9b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ package com.sun.org.apache.xml.internal.security.keys.content; /** * Empty interface just to identify Elements that can be cildren of ds:KeyInfo. * - * @author $Author: blautenb $ + * @author $Author: mullan $ */ public interface KeyInfoContent { } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java index dfff3c322111375895fbe66e5827b109180384b0..6794ea675866713ffab8f54bf33f15d8a7446c07 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyName extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyName.class.getName()); - /** * Constructor KeyName * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java index ab8b959f75cbe757c5e178c05000f793e9169532..0d3ee810d2392a2a30f885e66d94cf52f705f303 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java @@ -20,11 +20,8 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import java.security.PublicKey; - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.DSAKeyValue; import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.RSAKeyValue; @@ -34,140 +31,131 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * The KeyValue element contains a single public key that may be useful in * validating the signature. Structured formats for defining DSA (REQUIRED) * and RSA (RECOMMENDED) public keys are defined in Signature Algorithms * (section 6.4). The KeyValue element may include externally defined public - * keys values represented as PCDATA or element types from an external namespace. + * keys values represented as PCDATA or element types from an external + * namespace. * - * @author $Author: vishal $ + * @author $Author: mullan $ */ public class KeyValue extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyValue.class.getName()); - - /** - * Constructor KeyValue - * - * @param doc - * @param dsaKeyValue - */ - public KeyValue(Document doc, DSAKeyValue dsaKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(dsaKeyValue.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param rsaKeyValue - */ - public KeyValue(Document doc, RSAKeyValue rsaKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(rsaKeyValue.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param unknownKeyValue - */ - public KeyValue(Document doc, Element unknownKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(unknownKeyValue); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param pk - */ - public KeyValue(Document doc, PublicKey pk) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - - if (pk instanceof java.security.interfaces.DSAPublicKey) { - DSAKeyValue dsa = new DSAKeyValue(this._doc, pk); - - this._constructionElement.appendChild(dsa.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } else if (pk instanceof java.security.interfaces.RSAPublicKey) { - RSAKeyValue rsa = new RSAKeyValue(this._doc, pk); - - this._constructionElement.appendChild(rsa.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - } - - /** - * Constructor KeyValue - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public KeyValue(Element element, String BaseURI) + /** + * Constructor KeyValue + * + * @param doc + * @param dsaKeyValue + */ + public KeyValue(Document doc, DSAKeyValue dsaKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(dsaKeyValue.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param rsaKeyValue + */ + public KeyValue(Document doc, RSAKeyValue rsaKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(rsaKeyValue.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param unknownKeyValue + */ + public KeyValue(Document doc, Element unknownKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(unknownKeyValue); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param pk + */ + public KeyValue(Document doc, PublicKey pk) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + + if (pk instanceof java.security.interfaces.DSAPublicKey) { + DSAKeyValue dsa = new DSAKeyValue(this._doc, pk); + + this._constructionElement.appendChild(dsa.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } else if (pk instanceof java.security.interfaces.RSAPublicKey) { + RSAKeyValue rsa = new RSAKeyValue(this._doc, pk); + + this._constructionElement.appendChild(rsa.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + } + + /** + * Constructor KeyValue + * + * @param element + * @param BaseURI + * @throws XMLSecurityException + */ + public KeyValue(Element element, String BaseURI) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Method getPublicKey - * - * @return the public key - * @throws XMLSecurityException - */ - public PublicKey getPublicKey() throws XMLSecurityException { - - - Element rsa = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), - Constants._TAG_RSAKEYVALUE,0); - - if (rsa != null) { - RSAKeyValue kv = new RSAKeyValue(rsa, - this._baseURI); - + super(element, BaseURI); + } + + /** + * Method getPublicKey + * + * @return the public key + * @throws XMLSecurityException + */ + public PublicKey getPublicKey() throws XMLSecurityException { + + Element rsa = XMLUtils.selectDsNode + (this._constructionElement.getFirstChild(), + Constants._TAG_RSAKEYVALUE,0); + + if (rsa != null) { + RSAKeyValue kv = new RSAKeyValue(rsa, this._baseURI); return kv.getPublicKey(); - } + } - Element dsa = XMLUtils.selectDsNode(this._constructionElement, - Constants._TAG_DSAKEYVALUE,0); - - - if (dsa != null) { - DSAKeyValue kv = new DSAKeyValue(dsa, - this._baseURI); + Element dsa = XMLUtils.selectDsNode + (this._constructionElement.getFirstChild(), + Constants._TAG_DSAKEYVALUE,0); + if (dsa != null) { + DSAKeyValue kv = new DSAKeyValue(dsa, this._baseURI); return kv.getPublicKey(); - } - + } - return null; - } + return null; + } - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_KEYVALUE; - } + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_KEYVALUE; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java index 52662d9129b65387e3fc839585464be240c9ca93..185e3557170973109d4fa2629b354f523c530866 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class MgmtData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(MgmtData.class.getName()); - /** * Constructor MgmtData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java index 7829c36527f14e55be2834b213639ee7c115fc47..010c907a8d9bb4e37e9968f5b297482a873c4f1a 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ * $todo$ Implement */ public class PGPData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(PGPData.class.getName()); - /** * Constructor PGPData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java index feb8b26d3b587924f010567a29ee398e89bef2bf..3c4956b7787c3a86e1882b3d5a4a4032800a5175 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java @@ -20,9 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.transforms.Transforms; @@ -33,17 +30,13 @@ import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RetrievalMethod extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(RetrievalMethod.class.getName()); //J- /** DSA retrieval */ public static final String TYPE_DSA = Constants.SignatureSpecNS + "DSAKeyValue"; @@ -133,7 +126,7 @@ public class RetrievalMethod extends SignatureElementProxy try { Element transformsElem = - XMLUtils.selectDsNode(this._constructionElement, + XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), Constants ._TAG_TRANSFORMS, 0); diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java index 64bb23c62310aa1ceb27370cab985a3a9a78a760..95cef8d5491d88b7bc27619c4e845845e675f4de 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ * $todo$ implement */ public class SPKIData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SPKIData.class.getName()); - /** * Constructor SPKIData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java index d60f3ad6518751a19bbaa7f7b39400db793aef5b..199b1dcb020dd507faf245a0c41ab085329bff92 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java @@ -41,7 +41,7 @@ import org.w3c.dom.Node; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509Data extends SignatureElementProxy implements KeyInfoContent { @@ -72,60 +72,17 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { throws XMLSecurityException { super(element, BaseURI); - - boolean noElements=true; Node sibling=this._constructionElement.getFirstChild(); while (sibling!=null) { if (sibling.getNodeType()!=Node.ELEMENT_NODE) { sibling=sibling.getNextSibling(); continue; } - noElements=false; - Element currentElem = (Element) sibling; - sibling=sibling.getNextSibling(); - String localname = currentElem.getLocalName(); - - if (currentElem.getNamespaceURI().equals(Constants.SignatureSpecNS)) { - if (localname.equals(Constants._TAG_X509ISSUERSERIAL)) { - XMLX509IssuerSerial is = new XMLX509IssuerSerial(currentElem, - BaseURI); - - this.add(is); - } else if (localname.equals(Constants._TAG_X509SKI)) { - XMLX509SKI ski = new XMLX509SKI(currentElem, BaseURI); - - this.add(ski); - } else if (localname.equals(Constants._TAG_X509SUBJECTNAME)) { - XMLX509SubjectName sn = new XMLX509SubjectName(currentElem, - BaseURI); - - this.add(sn); - } else if (localname.equals(Constants._TAG_X509CERTIFICATE)) { - XMLX509Certificate cert = new XMLX509Certificate(currentElem, - BaseURI); - - this.add(cert); - } else if (localname.equals(Constants._TAG_X509CRL)) { - XMLX509CRL crl = new XMLX509CRL(currentElem, BaseURI); - - this.add(crl); - } else { - log.log(java.util.logging.Level.WARNING, "Found a " + currentElem.getTagName() + " element in " - + Constants._TAG_X509DATA); - this.addUnknownElement(currentElem); - } - } else { - log.log(java.util.logging.Level.WARNING, "Found a " + currentElem.getTagName() + " element in " - + Constants._TAG_X509DATA); - this.addUnknownElement(currentElem); - } + return; } - if (noElements) { - Object exArgs[] = { "Elements", Constants._TAG_X509DATA }; - - throw new XMLSecurityException("xml.WrongContent", exArgs); - } - + /* No Elements found */ + Object exArgs[] = { "Elements", Constants._TAG_X509DATA }; + throw new XMLSecurityException("xml.WrongContent", exArgs); } /** @@ -169,11 +126,9 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { */ public void add(XMLX509IssuerSerial xmlX509IssuerSerial) { - if (this._state == MODE_SIGN) { this._constructionElement .appendChild(xmlX509IssuerSerial.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -202,11 +157,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509SKI */ public void add(XMLX509SKI xmlX509SKI) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509SKI.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -233,11 +185,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509SubjectName */ public void add(XMLX509SubjectName xmlX509SubjectName) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509SubjectName.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -266,11 +215,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509Certificate */ public void add(XMLX509Certificate xmlX509Certificate) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509Certificate.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -288,11 +234,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509CRL */ public void add(XMLX509CRL xmlX509CRL) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509CRL.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -301,11 +244,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param element */ public void addUnknownElement(Element element) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(element); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -479,7 +419,7 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * TODO implement **/ public Element itemUnknownElement(int i) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "itemUnknownElement not implemented:"+i); + log.log(java.util.logging.Level.FINE, "itemUnknownElement not implemented:"+i); return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java index 19fb7758f6299e7611970611184d9997805a935a..ef735c3dad6eb6c3398393b3b46bfec02f2eaf39 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.keyvalues; - - import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; @@ -39,18 +37,13 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class DSAKeyValue extends SignatureElementProxy implements KeyValueContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(DSAKeyValue.class.getName()); - /** * Constructor DSAKeyValue * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java index 608758e16ce8c958b6ca2d886bb76b0410ffe8be..31e761443c57008433c6b28557a8219930d9605c 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -32,7 +31,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; * * * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public interface KeyValueContent { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java index 6fc33aded203f25c290fc92041818dfc0642f2b7..71b23cda593a477f71890181c886a7e437a028aa 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.keyvalues; - - import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; @@ -39,19 +37,13 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RSAKeyValue extends SignatureElementProxy implements KeyValueContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger( - RSAKeyValue.class.getName()); - /** * Constructor RSAKeyValue * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java index 7c9f5be1f69a2b7550e110cadb59d058e026c1db..b68c444dc08c15daabce2c5a8259da80f5b067e1 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java @@ -20,30 +20,20 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * - * - * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public class XMLX509CRL extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509CRL.class.getName()); - /** * Constructor XMLX509CRL * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java index 51f81e529015f5e7855502cce097970d067c36a7..630d9ccc279f3849c12d4e236c9d9fc7d0c69068 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.io.ByteArrayInputStream; import java.security.PublicKey; import java.security.cert.CertificateException; @@ -34,18 +32,13 @@ import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509Certificate extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509Certificate.class.getName()); - /** Field JCA_CERT_ID */ public static final String JCA_CERT_ID = "X.509"; @@ -146,23 +139,25 @@ public class XMLX509Certificate extends SignatureElementProxy return null; } - /** @inheritDoc */ - public boolean equals(Object obj) { + /** @inheritDoc */ + public boolean equals(Object obj) { - try { - if (!obj.getClass().getName().equals(this.getClass().getName())) { + if (obj == null) { return false; - } - - XMLX509Certificate other = (XMLX509Certificate) obj; - - /** $todo$ or should be create X509Certificates and use the equals() from the Certs */ - return java.security.MessageDigest.isEqual(other.getCertificateBytes(), - this.getCertificateBytes()); - } catch (XMLSecurityException ex) { - return false; - } - } + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } + XMLX509Certificate other = (XMLX509Certificate) obj; + try { + + /** $todo$ or should be create X509Certificates and use the equals() from the Certs */ + return java.security.MessageDigest.isEqual + (other.getCertificateBytes(), this.getCertificateBytes()); + } catch (XMLSecurityException ex) { + return false; + } + } /** @inheritDoc */ public String getBaseLocalName() { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java index adbf4978fec7b364de896f7a73993509fb996ff5..02bf9f82d3962210b4e85c15a69ac3b6806c2e7d 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ package com.sun.org.apache.xml.internal.security.keys.content.x509; /** * Just used for tagging contents that are allowed inside a ds:X509Data Element. * - * @author $Author: blautenb $ + * @author $Author: mullan $ */ public interface XMLX509DataContent { } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java index d0701592d5464a53cb5c4dabeadc3421eca93f33..1d16b2b622f5a4e12376923221e8ae996446c0f2 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.math.BigInteger; import java.security.cert.X509Certificate; @@ -33,148 +31,139 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509IssuerSerial extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger( XMLX509IssuerSerial.class.getName()); - /** - * Constructor XMLX509IssuerSerial - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public XMLX509IssuerSerial(Element element, String BaseURI) + /** + * Constructor XMLX509IssuerSerial + * + * @param element + * @param baseURI + * @throws XMLSecurityException + */ + public XMLX509IssuerSerial(Element element, String baseURI) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - BigInteger X509SerialNumber) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this.addTextElement(X509IssuerName, Constants._TAG_X509ISSUERNAME); - XMLUtils.addReturnToElement(this._constructionElement); - this.addTextElement(X509SerialNumber.toString(), Constants._TAG_X509SERIALNUMBER); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - String X509SerialNumber) { - this(doc, X509IssuerName, new BigInteger(X509SerialNumber)); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - int X509SerialNumber) { - this(doc, X509IssuerName, - new BigInteger(Integer.toString(X509SerialNumber))); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param x509certificate - */ - public XMLX509IssuerSerial(Document doc, X509Certificate x509certificate) { - - this(doc, - RFC2253Parser.normalize(x509certificate.getIssuerDN().getName()), - x509certificate.getSerialNumber()); - } - - /** - * Method getSerialNumber - * - * - * @return the serial number - */ - public BigInteger getSerialNumber() { - - String text = - this.getTextFromChildElement(Constants._TAG_X509SERIALNUMBER, - Constants.SignatureSpecNS); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "In dem X509SerialNumber wurde gefunden: " + text); - - return new BigInteger(text); - } - - /** - * Method getSerialNumberInteger - * - * - * @return the serial number as plain int - */ - public int getSerialNumberInteger() { - return this.getSerialNumber().intValue(); - } - - /** - * Method getIssuerName - * - * - * @return the issuer name - */ - public String getIssuerName() { - - return RFC2253Parser - .normalize(this - .getTextFromChildElement(Constants._TAG_X509ISSUERNAME, - Constants.SignatureSpecNS)); - } - - /** @inheritDoc */ - public boolean equals(Object obj) { - - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } - - XMLX509IssuerSerial other = (XMLX509IssuerSerial) obj; - - - if (other.getSerialNumber().equals(this.getSerialNumber()) - && other.getIssuerName().equals(this.getIssuerName())) { - return true; - } - - return false; - } - - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_X509ISSUERSERIAL; - } + super(element, baseURI); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + BigInteger x509SerialNumber) { + + super(doc); + XMLUtils.addReturnToElement(this._constructionElement); + addTextElement(x509IssuerName, Constants._TAG_X509ISSUERNAME); + addTextElement(x509SerialNumber.toString(), Constants._TAG_X509SERIALNUMBER); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + String x509SerialNumber) { + this(doc, x509IssuerName, new BigInteger(x509SerialNumber)); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + int x509SerialNumber) { + this(doc, x509IssuerName, + new BigInteger(Integer.toString(x509SerialNumber))); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509certificate + */ + public XMLX509IssuerSerial(Document doc, X509Certificate x509certificate) { + + this(doc, + RFC2253Parser.normalize(x509certificate.getIssuerDN().getName()), + x509certificate.getSerialNumber()); + } + + /** + * Method getSerialNumber + * + * @return the serial number + */ + public BigInteger getSerialNumber() { + + String text = this.getTextFromChildElement + (Constants._TAG_X509SERIALNUMBER, Constants.SignatureSpecNS); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "X509SerialNumber text: " + text); + + return new BigInteger(text); + } + + /** + * Method getSerialNumberInteger + * + * @return the serial number as plain int + */ + public int getSerialNumberInteger() { + return this.getSerialNumber().intValue(); + } + + /** + * Method getIssuerName + * + * @return the issuer name + */ + public String getIssuerName() { + + return RFC2253Parser + .normalize(this + .getTextFromChildElement(Constants._TAG_X509ISSUERNAME, + Constants.SignatureSpecNS)); + } + + /** @inheritDoc */ + public boolean equals(Object obj) { + + if (obj == null) { + return false; + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } + + XMLX509IssuerSerial other = (XMLX509IssuerSerial) obj; + + return this.getSerialNumber().equals(other.getSerialNumber()) + && this.getIssuerName().equals(other.getIssuerName()); + } + + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_X509ISSUERSERIAL; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java index fcbb19e245ac88670610010e36d2c480f89c3d66..fbbb17e6a5400278fdf4dd273b6b8964ce5e5e7e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -36,192 +34,143 @@ import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; -import sun.security.util.DerValue; - - /** * Handles SubjectKeyIdentifier (SKI) for X.509v3. * - * @author $Author: raul $ - * @see Interface X509Extension + * @author $Author: mullan $ + * @see Interface X509Extension */ public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(XMLX509SKI.class.getName()); - /** - * SubjectKeyIdentifier (id-ce-subjectKeyIdentifier) (2.5.29.14): - * This extension identifies the public key being certified. It enables - * distinct keys used by the same subject to be differentiated - * (e.g., as key updating occurs). - *
    - * A key identifer shall be unique with respect to all key identifiers - * for the subject with which it is used. This extension is always non-critical. - */ - public static final String SKI_OID = "2.5.29.14"; - - /** - * Constructor X509SKI - * - * @param doc - * @param skiBytes - */ - public XMLX509SKI(Document doc, byte[] skiBytes) { - - super(doc); - - this.addBase64Text(skiBytes); - } - - /** - * Constructor XMLX509SKI - * - * @param doc - * @param x509certificate - * @throws XMLSecurityException - */ - public XMLX509SKI(Document doc, X509Certificate x509certificate) - throws XMLSecurityException { - - super(doc); - - this.addBase64Text(XMLX509SKI.getSKIBytesFromCert(x509certificate)); - } - - /** - * Constructor XMLX509SKI - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public XMLX509SKI(Element element, String BaseURI) + /** + * SubjectKeyIdentifier (id-ce-subjectKeyIdentifier) (2.5.29.14): + * This extension identifies the public key being certified. It enables + * distinct keys used by the same subject to be differentiated + * (e.g., as key updating occurs). + *
    + * A key identifer shall be unique with respect to all key identifiers + * for the subject with which it is used. This extension is always non-critical. + */ + public static final String SKI_OID = "2.5.29.14"; + + /** + * Constructor X509SKI + * + * @param doc + * @param skiBytes + */ + public XMLX509SKI(Document doc, byte[] skiBytes) { + super(doc); + this.addBase64Text(skiBytes); + } + + /** + * Constructor XMLX509SKI + * + * @param doc + * @param x509certificate + * @throws XMLSecurityException + */ + public XMLX509SKI(Document doc, X509Certificate x509certificate) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Method getSKIBytes - * - * @return the skibytes - * @throws XMLSecurityException - */ - public byte[] getSKIBytes() throws XMLSecurityException { - return this.getBytesFromTextChild(); - } - - /** - * Method getSKIBytesFromCert - * - * @param cert - * @return sky bytes from the given certificate - * - * @throws XMLSecurityException - * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String) - */ - public static byte[] getSKIBytesFromCert(X509Certificate cert) + super(doc); + this.addBase64Text(XMLX509SKI.getSKIBytesFromCert(x509certificate)); + } + + /** + * Constructor XMLX509SKI + * + * @param element + * @param BaseURI + * @throws XMLSecurityException + */ + public XMLX509SKI(Element element, String BaseURI) throws XMLSecurityException { - - try { - - /* - * Gets the DER-encoded OCTET string for the extension value (extnValue) - * identified by the passed-in oid String. The oid string is - * represented by a set of positive whole numbers separated by periods. - */ - byte[] derEncodedValue = cert.getExtensionValue(XMLX509SKI.SKI_OID); - - if (cert.getVersion() < 3) { + super(element, BaseURI); + } + + /** + * Method getSKIBytes + * + * @return the skibytes + * @throws XMLSecurityException + */ + public byte[] getSKIBytes() throws XMLSecurityException { + return this.getBytesFromTextChild(); + } + + /** + * Method getSKIBytesFromCert + * + * @param cert + * @return ski bytes from the given certificate + * + * @throws XMLSecurityException + * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String) + */ + public static byte[] getSKIBytesFromCert(X509Certificate cert) + throws XMLSecurityException { + + if (cert.getVersion() < 3) { Object exArgs[] = { new Integer(cert.getVersion()) }; - throw new XMLSecurityException("certificate.noSki.lowVersion", exArgs); - } - - byte[] extensionValue = null; - - /** - * Use sun.security.util.DerValue if it is present. - */ - try { - DerValue dervalue = new DerValue(derEncodedValue); - if (dervalue == null) { - throw new XMLSecurityException("certificate.noSki.null"); - } - if (dervalue.tag != DerValue.tag_OctetString) { - throw new XMLSecurityException("certificate.noSki.notOctetString"); - } - extensionValue = dervalue.getOctetString(); - } catch (NoClassDefFoundError e) { - } - - /** - * Fall back to org.bouncycastle.asn1.DERInputStream - */ - if (extensionValue == null) { - try { - Class clazz = Class.forName("org.bouncycastle.asn1.DERInputStream"); - if (clazz != null) { - Constructor constructor = clazz.getConstructor(new Class[]{InputStream.class}); - InputStream is = (InputStream) constructor.newInstance(new Object[]{new ByteArrayInputStream(derEncodedValue)}); - Method method = clazz.getMethod("readObject", new Class[]{}); - Object obj = method.invoke(is, new Object[]{}); - if (obj == null) { - throw new XMLSecurityException("certificate.noSki.null"); - } - Class clazz2 = Class.forName("org.bouncycastle.asn1.ASN1OctetString"); - if (!clazz2.isInstance(obj)) { - throw new XMLSecurityException("certificate.noSki.notOctetString"); - } - Method method2 = clazz2.getMethod("getOctets", new Class[]{}); - extensionValue = (byte[]) method2.invoke(obj, new Object[]{}); - } - } catch (Throwable t) { - } - } - - /** - * Strip away first two bytes from the DerValue (tag and length) - */ - byte abyte0[] = new byte[extensionValue.length - 2]; - - System.arraycopy(extensionValue, 2, abyte0, 0, abyte0.length); - - /* - byte abyte0[] = new byte[derEncodedValue.length - 4]; - System.arraycopy(derEncodedValue, 4, abyte0, 0, abyte0.length); + } + + /* + * Gets the DER-encoded OCTET string for the extension value + * (extnValue) identified by the passed-in oid String. The oid + * string is represented by a set of positive whole numbers + * separated by periods. + */ + byte[] extensionValue = cert.getExtensionValue(XMLX509SKI.SKI_OID); + if (extensionValue == null) { + throw new XMLSecurityException("certificate.noSki.null"); + } + + /** + * Strip away first four bytes from the extensionValue + * The first two bytes are the tag and length of the extensionValue + * OCTET STRING, and the next two bytes are the tag and length of + * the skid OCTET STRING. */ - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Base64 of SKI is " + Base64.encode(abyte0)); + byte skidValue[] = new byte[extensionValue.length - 4]; + + System.arraycopy(extensionValue, 4, skidValue, 0, skidValue.length); - return abyte0; - } catch (IOException ex) { - throw new XMLSecurityException("generic.EmptyMessage", ex); - } - } + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Base64 of SKI is " + Base64.encode(skidValue)); + } - /** @inheritDoc */ - public boolean equals(Object obj) { + return skidValue; + } - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } + /** @inheritDoc */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } - XMLX509SKI other = (XMLX509SKI) obj; + XMLX509SKI other = (XMLX509SKI) obj; - try { - return java.security.MessageDigest.isEqual(other.getSKIBytes(), + try { + return java.security.MessageDigest.isEqual(other.getSKIBytes(), this.getSKIBytes()); - } catch (XMLSecurityException ex) { - return false; - } - } - - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_X509SKI; - } + } catch (XMLSecurityException ex) { + return false; + } + } + + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_X509SKI; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java index 548ec7ba57d1bad16553ffe908677a3e0ffc4603..8d51da2e2fdd29b4a604f9c3bd9a77249a8e5c34 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.security.cert.X509Certificate; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; @@ -33,15 +31,11 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509SubjectName extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509SubjectName.class.getName()); - /** * Constructor X509SubjectName * @@ -88,23 +82,21 @@ public class XMLX509SubjectName extends SignatureElementProxy return RFC2253Parser.normalize(this.getTextFromTextChild()); } - /** @inheritDoc */ - public boolean equals(Object obj) { - - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } - - XMLX509SubjectName other = (XMLX509SubjectName) obj; - String otherSubject = other.getSubjectName(); - String thisSubject = this.getSubjectName(); + /** @inheritDoc */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } - if (otherSubject.equals(thisSubject)) { - return true; - } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } - return false; + XMLX509SubjectName other = (XMLX509SubjectName) obj; + String otherSubject = other.getSubjectName(); + String thisSubject = this.getSubjectName(); + return thisSubject.equals(otherSubject); } /** @inheritDoc */ diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java index 6e3d408d43de05c4011dc37349b59c18b3763302..3b3508005cbdbb23661f0fb7e31c5a6f76be7fc0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -29,7 +28,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class InvalidKeyResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java index 488a59731c424cc0d37fff21f0f5dfe2c311c136..1da9dbb362f6926468faa00cc42ccc529d7cfa97 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -26,6 +25,7 @@ package com.sun.org.apache.xml.internal.security.keys.keyresolver; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import javax.crypto.SecretKey; @@ -39,7 +39,8 @@ import org.w3c.dom.Node; * KeyResolver is factory class for subclass of KeyResolverSpi that * represent child element of KeyInfo. * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version %I%, %G% */ public class KeyResolver { @@ -72,6 +73,7 @@ public class KeyResolver { InstantiationException { this._resolverSpi = (KeyResolverSpi) Class.forName(className).newInstance(); + this._resolverSpi.setGlobalResolver(true); } /** @@ -83,40 +85,82 @@ public class KeyResolver { return KeyResolver._resolverVector.size(); } + public static void hit(Iterator hintI) { + ResolverIterator hint = (ResolverIterator) hintI; + int i = hint.i; + if (i!=1 && hint.res ==_resolverVector) { + List resolverVector=(List)((ArrayList)_resolverVector).clone(); + Object ob=resolverVector.remove(i-1); + resolverVector.add(0,ob); + _resolverVector=resolverVector; + } else { + //System.out.println("KeyResolver hitting"); + } + } + /** - * Method item + * Method getInstance + * + * @param element + * @param BaseURI + * @param storage + * @return The certificate represented by the element. * - * @param i - * @return the number i resolver registerd * @throws KeyResolverException */ - public static KeyResolver item(int i) throws KeyResolverException { + public static final X509Certificate getX509Certificate( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException { + + // use the old vector to not be hit by updates + List resolverVector = KeyResolver._resolverVector; + for (int i = 0; i < resolverVector.size(); i++) { + KeyResolver resolver= + (KeyResolver) resolverVector.get(i); - KeyResolver resolver = (KeyResolver) KeyResolver._resolverVector.get(i); - if (resolver==null) { - throw new KeyResolverException("utils.resolver.noClass"); + if (resolver==null) { + Object exArgs[] = { + (((element != null) + && (element.getNodeType() == Node.ELEMENT_NODE)) + ? element.getTagName() + : "null") }; + + throw new KeyResolverException("utils.resolver.noClass", exArgs); + } + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); + + X509Certificate cert=resolver.resolveX509Certificate(element, BaseURI, storage); + if (cert!=null) { + return cert; + } } - return resolver; - } + Object exArgs[] = { + (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE)) + ? element.getTagName() + : "null") }; + throw new KeyResolverException("utils.resolver.noClass", exArgs); + } /** * Method getInstance * * @param element * @param BaseURI * @param storage - * @return the instance that happends to implement the thing. + * @return the public key contained in the element * * @throws KeyResolverException */ - public static final KeyResolver getInstance( + public static final PublicKey getPublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - for (int i = 0; i < KeyResolver._resolverVector.size(); i++) { + List resolverVector = KeyResolver._resolverVector; + for (int i = 0; i < resolverVector.size(); i++) { KeyResolver resolver= - (KeyResolver) KeyResolver._resolverVector.get(i); + (KeyResolver) resolverVector.get(i); if (resolver==null) { Object exArgs[] = { @@ -127,11 +171,19 @@ public class KeyResolver { throw new KeyResolverException("utils.resolver.noClass", exArgs); } - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); - - if (resolver.canResolve(element, BaseURI, storage)) { - return resolver; + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); + + PublicKey cert=resolver.resolvePublicKey(element, BaseURI, storage); + if (cert!=null) { + if (i!=0 && resolverVector==_resolverVector) { + //update resolver. + resolverVector=(List)((ArrayList)_resolverVector).clone(); + Object ob=resolverVector.remove(i); + resolverVector.add(0,ob); + _resolverVector=resolverVector; + } + return cert; } } @@ -182,34 +234,6 @@ public class KeyResolver { KeyResolver._resolverVector.add(0, className); } - /* - * Method resolve - * - * @param element - * - * @throws KeyResolverException - */ - - /** - * Method resolveStatic - * - * @param element - * @param BaseURI - * @param storage - * @return resolve from the static register an element - * - * @throws KeyResolverException - */ - public static PublicKey resolveStatic( - Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException { - - KeyResolver myResolver = KeyResolver.getInstance(element, BaseURI, - storage); - - return myResolver.resolvePublicKey(element, BaseURI, storage); - } - /** * Method resolve * @@ -223,7 +247,7 @@ public class KeyResolver { public PublicKey resolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolvePublicKey(element, BaseURI, storage); + return this._resolverSpi.engineLookupAndResolvePublicKey(element, BaseURI, storage); } /** @@ -239,7 +263,7 @@ public class KeyResolver { public X509Certificate resolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolveX509Certificate(element, BaseURI, + return this._resolverSpi.engineLookupResolveX509Certificate(element, BaseURI, storage); } @@ -253,7 +277,7 @@ public class KeyResolver { public SecretKey resolveSecretKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolveSecretKey(element, BaseURI, + return this._resolverSpi.engineLookupAndResolveSecretKey(element, BaseURI, storage); } @@ -277,14 +301,6 @@ public class KeyResolver { return this._resolverSpi.engineGetProperty(key); } - /** - * Method getPropertyKeys - * - * @return the properties key registerd in this resolver - */ - public String[] getPropertyKeys() { - return this._resolverSpi.engineGetPropertyKeys(); - } /** * Method understandsProperty @@ -296,18 +312,6 @@ public class KeyResolver { return this._resolverSpi.understandsProperty(propertyToTest); } - /** - * Method canResolve - * - * @param element - * @param BaseURI - * @param storage - * @return true if can resolve the key in the element - */ - public boolean canResolve(Element element, String BaseURI, - StorageResolver storage) { - return this._resolverSpi.engineCanResolve(element, BaseURI, storage); - } /** * Method resolverClassName @@ -317,4 +321,37 @@ public class KeyResolver { public String resolverClassName() { return this._resolverSpi.getClass().getName(); } + + static class ResolverIterator implements Iterator { + List res; + Iterator it; + int i; + public ResolverIterator(List list) { + res = list; + it = res.iterator(); + } + public boolean hasNext() { + // TODO Auto-generated method stub + return it.hasNext(); + } + + public Object next() { + i++; + KeyResolver resolver = (KeyResolver) it.next(); + if (resolver==null) { + throw new RuntimeException("utils.resolver.noClass"); + } + + return resolver._resolverSpi; + } + + public void remove() { + // TODO Auto-generated method stub + + } + + }; + public static Iterator iterator() { + return new ResolverIterator(_resolverVector); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java index 4248c8dfa6b280119a59b98acd6ac82c7261cf78..f0069949b2f804ec02fe458b4179c80ca023a059 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -31,7 +30,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; * * * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public class KeyResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java index a6b99825ebc5294f67fe34e55e7c8fac7d7f1bad..dc2865bcfc4d67632320bda1a65d2b22e05e18a4 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java @@ -20,17 +20,15 @@ */ package com.sun.org.apache.xml.internal.security.keys.keyresolver; - - import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.HashMap; import javax.crypto.SecretKey; import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver; import org.w3c.dom.Element; - /** * This class is abstract class for a child KeyInfo Elemnet. * @@ -41,14 +39,10 @@ import org.w3c.dom.Element; * JAVACLASS="MyPackage.MyKeyValueImpl"//gt; * * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public abstract class KeyResolverSpi { - - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyResolverSpi.class.getName()); - /** * This method helps the {@link com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver} to decide whether a * {@link com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi} is able to perform the requested action. @@ -56,10 +50,12 @@ public abstract class KeyResolverSpi { * @param element * @param BaseURI * @param storage - * @return true if can resolve the key in the element + * @return */ - abstract public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage); + public boolean engineCanResolve(Element element, String BaseURI, + StorageResolver storage) { + throw new UnsupportedOperationException(); + } /** * Method engineResolvePublicKey @@ -71,9 +67,60 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public PublicKey engineResolvePublicKey( + public PublicKey engineResolvePublicKey( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + throw new UnsupportedOperationException(); + }; + + /** + * Method engineResolvePublicKey + * + * @param element + * @param BaseURI + * @param storage + * @return resolved public key from the registered from the element. + * + * @throws KeyResolverException + */ + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolvePublicKey(element, BaseURI, storage); + } + + private KeyResolverSpi cloneIfNeeded() throws KeyResolverException { + KeyResolverSpi tmp=this; + if (globalResolver) { + try { + tmp = (KeyResolverSpi) getClass().newInstance(); + } catch (InstantiationException e) { + throw new KeyResolverException("",e); + } catch (IllegalAccessException e) { + throw new KeyResolverException("",e); + } + } + return tmp; + } + + /** + * Method engineResolveCertificate + * + * @param element + * @param BaseURI + * @param storage + * @return resolved X509Certificate key from the registered from the elements + * + * @throws KeyResolverException + */ + public X509Certificate engineResolveX509Certificate( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException{ + throw new UnsupportedOperationException(); + }; /** * Method engineResolveCertificate @@ -85,9 +132,30 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolveX509Certificate(element, BaseURI, storage); + + } + /** + * Method engineResolveSecretKey + * + * @param element + * @param BaseURI + * @param storage + * @return resolved SecretKey key from the registered from the elements + * + * @throws KeyResolverException + */ + public SecretKey engineResolveSecretKey( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException{ + throw new UnsupportedOperationException(); + }; /** * Method engineResolveSecretKey @@ -99,12 +167,19 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public SecretKey engineResolveSecretKey( + public SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolveSecretKey(element, BaseURI, storage); + } /** Field _properties */ - protected java.util.Map _properties = new java.util.HashMap(10); + protected java.util.Map _properties = null; + + protected boolean globalResolver=false; /** * Method engineSetProperty @@ -113,19 +188,8 @@ public abstract class KeyResolverSpi { * @param value */ public void engineSetProperty(String key, String value) { - - java.util.Iterator i = this._properties.keySet().iterator(); - - while (i.hasNext()) { - String c = (String) i.next(); - - if (c.equals(key)) { - key = c; - - break; - } - } - + if (_properties==null) + _properties=new HashMap(); this._properties.put(key, value); } @@ -136,31 +200,12 @@ public abstract class KeyResolverSpi { * @return obtain the property appointed by key */ public String engineGetProperty(String key) { - - java.util.Iterator i = this._properties.keySet().iterator(); - - while (i.hasNext()) { - String c = (String) i.next(); - - if (c.equals(key)) { - key = c; - - break; - } - } + if (_properties==null) + return null; return (String) this._properties.get(key); } - /** - * Method engineGetPropertyKeys - * - * @return the keys of properties known by this resolver - */ - public String[] engineGetPropertyKeys() { - return new String[0]; - } - /** * Method understandsProperty * @@ -168,17 +213,13 @@ public abstract class KeyResolverSpi { * @return true if understood the property */ public boolean understandsProperty(String propertyToTest) { + if (_properties==null) + return false; - String[] understood = this.engineGetPropertyKeys(); - - if (understood != null) { - for (int i = 0; i < understood.length; i++) { - if (understood[i].equals(propertyToTest)) { - return true; - } - } - } - - return false; + return this._properties.get(propertyToTest)!=null; } + public void setGlobalResolver(boolean globalResolver) { + this.globalResolver = globalResolver; + } + } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java index efda14c1a4a0066417e062dae7100c9e908f5539..20bf7bad777fa08e94f5f79fddb9fcd45646a18e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java @@ -37,46 +37,10 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class DSAKeyValueResolver extends KeyResolverSpi { - /** Field _dsaKeyElement */ - private Element _dsaKeyElement = null; - - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - - if (element == null) { - return false; - } - - boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_KEYVALUE); - boolean isDSAKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_DSAKEYVALUE); - - if (isKeyValue) { - - this._dsaKeyElement = - XMLUtils.selectDsNode(element.getFirstChild(),Constants._TAG_DSAKEYVALUE,0); - - if (this._dsaKeyElement != null) { - return true; - } - } else if (isDSAKeyValue) { - - // this trick is needed to allow the RetrievalMethodResolver to eat a - // ds:DSAKeyValue directly (without KeyValue) - this._dsaKeyElement = element; - - return true; - } - - return false; - } - /** * Method engineResolvePublicKey * @@ -85,20 +49,30 @@ public class DSAKeyValueResolver extends KeyResolverSpi { * @param storage * @return null if no {@link PublicKey} could be obtained */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) { + if (element == null) { + return null; + } + Element dsaKeyElement=null; + boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_KEYVALUE); + if (isKeyValue) { + dsaKeyElement = + XMLUtils.selectDsNode(element.getFirstChild(),Constants._TAG_DSAKEYVALUE,0); + } else if (XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_DSAKEYVALUE)) { + // this trick is needed to allow the RetrievalMethodResolver to eat a + // ds:DSAKeyValue directly (without KeyValue) + dsaKeyElement = element; + } - if (this._dsaKeyElement == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._dsaKeyElement == null)) { - return null; - } + if (dsaKeyElement == null) { + return null; } try { - DSAKeyValue dsaKeyValue = new DSAKeyValue(this._dsaKeyElement, + DSAKeyValue dsaKeyValue = new DSAKeyValue(dsaKeyElement, BaseURI); PublicKey pk = dsaKeyValue.getPublicKey(); @@ -112,13 +86,13 @@ public class DSAKeyValueResolver extends KeyResolverSpi { /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage){ return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java index 4b44f1c50d15434bf71c3bf98cf349f4921422bd..6adc050e8935b37d90faa61fe67d373d72353a33 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java @@ -56,7 +56,6 @@ public class EncryptedKeyResolver extends KeyResolverSpi { RSAKeyValueResolver.class.getName()); - Key _key; Key _kek; String _algorithm; @@ -66,7 +65,6 @@ public class EncryptedKeyResolver extends KeyResolverSpi { * @param algorithm */ public EncryptedKeyResolver(String algorithm) { - _key = null; _kek = null; _algorithm=algorithm; } @@ -78,64 +76,49 @@ public class EncryptedKeyResolver extends KeyResolverSpi { */ public EncryptedKeyResolver(String algorithm, Key kek) { - _key = null; _algorithm = algorithm; _kek = kek; } - /** - * Method engineCanResolve - * - * @param element - * @param BaseURI - * @param storage - * @return true if can resolve the key in the element - * - */ - - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "EncryptedKeyResolver - Can I resolve " + element.getTagName()); - - if (element == null) { - return false; - } - - boolean isEncryptedKey = XMLUtils.elementIsInEncryptionSpace(element, - EncryptionConstants._TAG_ENCRYPTEDKEY); - - if (isEncryptedKey) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Passed an Encrypted Key"); - try { - XMLCipher cipher = XMLCipher.getInstance(); - cipher.init(XMLCipher.UNWRAP_MODE, _kek); - EncryptedKey ek = cipher.loadEncryptedKey(element); - _key = cipher.decryptKey(ek, _algorithm); - } - catch (Exception e) {} - } - - return (_key != null); - } - /** @inheritDoc */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { - return (SecretKey) _key; + SecretKey key=null; + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "EncryptedKeyResolver - Can I resolve " + element.getTagName()); + + if (element == null) { + return null; + } + + boolean isEncryptedKey = XMLUtils.elementIsInEncryptionSpace(element, + EncryptionConstants._TAG_ENCRYPTEDKEY); + + if (isEncryptedKey) { + log.log(java.util.logging.Level.FINE, "Passed an Encrypted Key"); + try { + XMLCipher cipher = XMLCipher.getInstance(); + cipher.init(XMLCipher.UNWRAP_MODE, _kek); + EncryptedKey ek = cipher.loadEncryptedKey(element); + key = (SecretKey) cipher.decryptKey(ek, _algorithm); + } + catch (Exception e) {} + } + + return key; } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java index 541de7307f458702c775dffb48f4e5e648db3fc6..fb38e8725908901a545533d178af3b79ad3ca120 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -38,7 +37,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RSAKeyValueResolver extends KeyResolverSpi { @@ -48,75 +47,55 @@ public class RSAKeyValueResolver extends KeyResolverSpi { RSAKeyValueResolver.class.getName()); /** Field _rsaKeyElement */ - private Element _rsaKeyElement = null; - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName()); + /** @inheritDoc */ + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName()); if (element == null) { - return false; + return null; } - boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_KEYVALUE); - boolean isRSAKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_RSAKEYVALUE); - - if (isKeyValue) { - this._rsaKeyElement = XMLUtils.selectDsNode(element.getFirstChild(), - Constants._TAG_RSAKEYVALUE, 0); - - if (this._rsaKeyElement != null) { - return true; - } - } else if (isRSAKeyValue) { - + boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_KEYVALUE); + Element rsaKeyElement=null; + if (isKeyValue) { + rsaKeyElement = XMLUtils.selectDsNode(element.getFirstChild(), + Constants._TAG_RSAKEYVALUE, 0); + } else if (XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RSAKEYVALUE)) { // this trick is needed to allow the RetrievalMethodResolver to eat a // ds:RSAKeyValue directly (without KeyValue) - this._rsaKeyElement = element; - - return true; - } - - return false; - } - - /** @inheritDoc */ - public PublicKey engineResolvePublicKey( - Element element, String BaseURI, StorageResolver storage) { + rsaKeyElement = element; + } - if (this._rsaKeyElement == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - if (!weCanResolve || (this._rsaKeyElement == null)) { - return null; - } + if (rsaKeyElement == null) { + return null; } try { - RSAKeyValue rsaKeyValue = new RSAKeyValue(this._rsaKeyElement, + RSAKeyValue rsaKeyValue = new RSAKeyValue(rsaKeyElement, BaseURI); return rsaKeyValue.getPublicKey(); } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); } return null; } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java index d8d98bdb9e9651f47049990b377e4a6f7267c344..3dff21824457cf144b05888576feecc1ec74bd4b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java @@ -28,7 +28,15 @@ import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; + +import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.keys.content.RetrievalMethod; import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509Certificate; @@ -44,6 +52,7 @@ import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** @@ -55,7 +64,7 @@ import org.w3c.dom.Node; * RetrievalMethodResolver cannot handle itself, resolving of the extracted * element is delegated back to the KeyResolver mechanism. * - * @author $Author: raul $ + * @author $Author: mullan $ modified by Dave Garcia */ public class RetrievalMethodResolver extends KeyResolverSpi { @@ -65,198 +74,170 @@ public class RetrievalMethodResolver extends KeyResolverSpi { RetrievalMethodResolver.class.getName()); /** - * Method engineCanResolve + * Method engineResolvePublicKey * @inheritDoc * @param element * @param BaseURI * @param storage * */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) + { + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RETRIEVALMETHOD)) { + return null; + } - if - (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_RETRIEVALMETHOD)) { - return false; - } + try { + //Create a retrieval method over the given element + RetrievalMethod rm = new RetrievalMethod(element, BaseURI); + String type = rm.getType(); + XMLSignatureInput resource=resolveInput(rm,BaseURI); + if (RetrievalMethod.TYPE_RAWX509.equals(type)) { + //a raw certificate, direct parsing is done! + X509Certificate cert=getRawCertificate(resource); + if (cert != null) { + return cert.getPublicKey(); + } + return null; + }; + Element e = obtainRefrenceElement(resource); + return resolveKey(e,BaseURI,storage); + } catch (XMLSecurityException ex) { + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + } catch (CertificateException ex) { + log.log(java.util.logging.Level.FINE, "CertificateException", ex); + } catch (IOException ex) { + log.log(java.util.logging.Level.FINE, "IOException", ex); + } catch (ParserConfigurationException e) { + log.log(java.util.logging.Level.FINE, "ParserConfigurationException", e); + } catch (SAXException e) { + log.log(java.util.logging.Level.FINE, "SAXException", e); + } + return null; + } - return true; + static private Element obtainRefrenceElement(XMLSignatureInput resource) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, KeyResolverException { + Element e; + if (resource.isElement()){ + e=(Element) resource.getSubNode(); + } else if (resource.isNodeSet()) { + //Retrieved resource is a nodeSet + e=getDocumentElement(resource.getNodeSet()); + } else { + //Retrieved resource is an inputStream + byte inputBytes[] = resource.getBytes(); + e = getDocFromBytes(inputBytes); + //otherwise, we parse the resource, create an Element and delegate + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); + } + return e; } /** - * Method engineResolvePublicKey + * Method engineResolveX509Certificate * @inheritDoc * @param element * @param BaseURI * @param storage * */ - public PublicKey engineResolvePublicKey( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RETRIEVALMETHOD)) { + return null; + } - try { + try { RetrievalMethod rm = new RetrievalMethod(element, BaseURI); - Attr uri = rm.getURIAttr(); - - // type can be null because it's optional - String type = rm.getType(); - Transforms transforms = rm.getTransforms(); - ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); - - if (resRes != null) { - XMLSignatureInput resource = resRes.resolve(uri, BaseURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Before applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - - if (transforms != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "We have Transforms"); - - resource = transforms.performTransforms(resource); - } - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "After applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Resolved to resource " + resource.getSourceURI()); - } - - byte inputBytes[] = resource.getBytes(); - - if ((type != null) && type.equals(RetrievalMethod.TYPE_RAWX509)) { - - // if the resource stores a raw certificate, we have to handle it - CertificateFactory certFact = - CertificateFactory - .getInstance(XMLX509Certificate.JCA_CERT_ID); - X509Certificate cert = - (X509Certificate) certFact - .generateCertificate(new ByteArrayInputStream(inputBytes)); - - if (cert != null) { - return cert.getPublicKey(); - } - } else { - - // otherwise, we parse the resource, create an Element and delegate - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); - - Element e = this.getDocFromBytes(inputBytes); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}" - + e.getLocalName() + " Element"); - - if (e != null) { - KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e), - BaseURI, storage); - - if (newKeyResolver != null) { - return newKeyResolver.resolvePublicKey(getFirstElementChild(e), BaseURI, - storage); - } - } - } - } + String type = rm.getType(); + XMLSignatureInput resource=resolveInput(rm,BaseURI); + if (RetrievalMethod.TYPE_RAWX509.equals(type)) { + X509Certificate cert=getRawCertificate(resource); + return cert; + } + Element e = obtainRefrenceElement(resource); + return resolveCertificate(e,BaseURI,storage); } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "CertificateException", ex); + log.log(java.util.logging.Level.FINE, "CertificateException", ex); } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "IOException", ex); - } - + log.log(java.util.logging.Level.FINE, "IOException", ex); + } catch (ParserConfigurationException e) { + log.log(java.util.logging.Level.FINE, "ParserConfigurationException", e); + } catch (SAXException e) { + log.log(java.util.logging.Level.FINE, "SAXException", e); + } return null; } /** - * Method engineResolveX509Certificate - * @inheritDoc - * @param element + * Retrieves a x509Certificate from the given information + * @param e * @param BaseURI * @param storage - * + * @return + * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( - Element element, String BaseURI, StorageResolver storage) - { - - try { - RetrievalMethod rm = new RetrievalMethod(element, BaseURI); - Attr uri = rm.getURIAttr(); - Transforms transforms = rm.getTransforms(); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Asked to resolve URI " + uri); - - ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); - - if (resRes != null) { - XMLSignatureInput resource = resRes.resolve(uri, BaseURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Before applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - - if (transforms != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "We have Transforms"); - - resource = transforms.performTransforms(resource); - } - - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "After applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Resolved to resource " + resource.getSourceURI()); - } - - byte inputBytes[] = resource.getBytes(); - - if ((rm.getType() != null) - && rm.getType().equals(RetrievalMethod.TYPE_RAWX509)) { - - // if the resource stores a raw certificate, we have to handle it - CertificateFactory certFact = - CertificateFactory - .getInstance(XMLX509Certificate.JCA_CERT_ID); - X509Certificate cert = - (X509Certificate) certFact - .generateCertificate(new ByteArrayInputStream(inputBytes)); - - if (cert != null) { - return cert; - } - } else { - - // otherwise, we parse the resource, create an Element and delegate - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); - - Element e = this.getDocFromBytes(inputBytes); - - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}" - + e.getLocalName() + " Element"); - - if (e != null) { - KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e), - BaseURI, storage); + static private X509Certificate resolveCertificate(Element e,String BaseURI,StorageResolver storage) throws KeyResolverException{ + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}"+ e.getLocalName() + " Element"); + //An element has been provided + if (e != null) { + return KeyResolver.getX509Certificate(e,BaseURI, storage); + } + return null; + } - if (newKeyResolver != null) { - return newKeyResolver.resolveX509Certificate(getFirstElementChild(e), BaseURI, - storage); + /** + * Retrieves a x509Certificate from the given information + * @param e + * @param BaseURI + * @param storage + * @return + * @throws KeyResolverException + */ + static private PublicKey resolveKey(Element e,String BaseURI,StorageResolver storage) throws KeyResolverException{ + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}"+ e.getLocalName() + " Element"); + //An element has been provided + if (e != null) { + return KeyResolver.getPublicKey(e,BaseURI, storage); } - } - } - } - } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); - } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "CertificateException", ex); - } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "IOException", ex); - } + return null; + } - return null; + static private X509Certificate getRawCertificate(XMLSignatureInput resource) throws CanonicalizationException, IOException, CertificateException{ + byte inputBytes[] = resource.getBytes(); + // if the resource stores a raw certificate, we have to handle it + CertificateFactory certFact =CertificateFactory.getInstance(XMLX509Certificate.JCA_CERT_ID); + X509Certificate cert =(X509Certificate) certFact.generateCertificate(new ByteArrayInputStream(inputBytes)); + return cert; + } + /** + * Resolves the input from the given retrieval method + * @return + * @throws XMLSecurityException + */ + static private XMLSignatureInput resolveInput(RetrievalMethod rm,String BaseURI) throws XMLSecurityException{ + Attr uri = rm.getURIAttr(); + //Apply the trnasforms + Transforms transforms = rm.getTransforms(); + ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); + if (resRes != null) { + XMLSignatureInput resource = resRes.resolve(uri, BaseURI); + if (transforms != null) { + log.log(java.util.logging.Level.FINE, "We have Transforms"); + resource = transforms.performTransforms(resource); + } + return resource; + } + return null; } /** @@ -266,18 +247,13 @@ public class RetrievalMethodResolver extends KeyResolverSpi { * @return the Document Element after parsing bytes * @throws KeyResolverException if something goes wrong */ - Element getDocFromBytes(byte[] bytes) throws KeyResolverException { - + static Element getDocFromBytes(byte[] bytes) throws KeyResolverException { try { - javax.xml.parsers.DocumentBuilderFactory dbf = - javax.xml.parsers.DocumentBuilderFactory.newInstance(); - + javax.xml.parsers.DocumentBuilderFactory dbf =javax.xml.parsers.DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); - javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); org.w3c.dom.Document doc = db.parse(new java.io.ByteArrayInputStream(bytes)); - return doc.getDocumentElement(); } catch (org.xml.sax.SAXException ex) { throw new KeyResolverException("empty", ex); @@ -296,16 +272,43 @@ public class RetrievalMethodResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; } - static Element getFirstElementChild(Element e){ - Node n=e.getFirstChild(); - while (n!=null && n.getNodeType()!=Node.ELEMENT_NODE) { - n=n.getNextSibling(); - } - return (Element)n; + + static Element getDocumentElement(Set set) { + Iterator it=set.iterator(); + Element e=null; + while (it.hasNext()) { + Node currentNode=(Node)it.next(); + if (currentNode instanceof Element) { + e=(Element)currentNode; + break; + } + + } + List parents=new ArrayList(10); + + //Obtain all the parents of the elemnt + do { + parents.add(e); + Node n=e.getParentNode(); + if (!(n instanceof Element )) { + break; + } + e=(Element)n; + } while (e!=null); + //Visit them in reverse order. + ListIterator it2=parents.listIterator(parents.size()-1); + Element ele=null; + while (it2.hasPrevious()) { + ele=(Element)it2.previous(); + if (set.contains(ele)) { + return ele; + } + } + return null; } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java index 16264c998687fce2ae6c3c52c10211462561e0fb..06a49c6708e7c70dfb639bb2d0dffa0bbae7092a 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -41,7 +40,7 @@ import org.w3c.dom.Element; * Resolves Certificates which are directly contained inside a * ds:X509Certificate Element. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509CertificateResolver extends KeyResolverSpi { @@ -49,47 +48,7 @@ public class X509CertificateResolver extends KeyResolverSpi { static java.util.logging.Logger log = java.util.logging.Logger.getLogger(X509CertificateResolver.class.getName()); - /** Field _dsaKeyElement */ - Element[] _x509CertKeyElements = null; - - /** - * Method engineCanResolve - * @inheritDoc - * @param element - * @param BaseURI - * @param storage - * - */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - if (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_X509DATA)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - this._x509CertKeyElements = XMLUtils.selectDsNodes(element.getFirstChild(), - Constants._TAG_X509CERTIFICATE); - - if ((this._x509CertKeyElements != null) - && (this._x509CertKeyElements.length > 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - /** Field _x509certObject[] */ - XMLX509Certificate _x509certObject[] = null; /** * Method engineResolvePublicKey @@ -100,11 +59,11 @@ public class X509CertificateResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -123,43 +82,33 @@ public class X509CertificateResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { try { - if ((this._x509CertKeyElements == null) - || (this._x509CertKeyElements.length == 0)) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509CertKeyElements == null) - || (this._x509CertKeyElements.length == 0)) { - return null; - } + Element[] els=XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509CERTIFICATE); + if ((els == null) || (els.length == 0)) { + Element el=XMLUtils.selectDsNode(element.getFirstChild(), + Constants._TAG_X509DATA,0); + if (el!=null) { + return engineLookupResolveX509Certificate(el, BaseURI, storage); + } + return null; } - this._x509certObject = - new XMLX509Certificate[this._x509CertKeyElements.length]; - // populate Object array - for (int i = 0; i < this._x509CertKeyElements.length; i++) { - this._x509certObject[i] = - new XMLX509Certificate(this._x509CertKeyElements[i] - , BaseURI); - } - - for (int i = 0; i < this._x509certObject.length; i++) { - X509Certificate cert = this._x509certObject[i].getX509Certificate(); - - if (cert != null) { - return cert; + for (int i = 0; i < els.length; i++) { + XMLX509Certificate xmlCert=new XMLX509Certificate(els[i], BaseURI); + X509Certificate cert = xmlCert.getX509Certificate(); + if (cert!=null) { + return cert; } } - return null; } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); throw new KeyResolverException("generic.EmptyMessage", ex); } @@ -173,7 +122,7 @@ public class X509CertificateResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java index c4e824747ba198707875933156e282f6cbb0aa77..8f717e716897187aaaa2828bb5d6bca6d0ba76de 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -39,7 +38,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509IssuerSerialResolver extends KeyResolverSpi { @@ -48,44 +47,13 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { java.util.logging.Logger.getLogger( X509IssuerSerialResolver.class.getName()); - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - X509Data x509data = null; - try { - x509data = new X509Data(element, BaseURI); - } catch (XMLSignatureException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - if (x509data == null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - return false; - } - - if (x509data.containsIssuerSerial()) { - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - return false; - } /** @inheritDoc */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -96,10 +64,31 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + + X509Data x509data = null; + try { + x509data = new X509Data(element, BaseURI); + } catch (XMLSignatureException ex) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } catch (XMLSecurityException ex) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + + if (x509data == null) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + + if (!x509data.containsIssuerSerial()) { + return null; + } try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509ISSUERSERIAL }; @@ -107,53 +96,52 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - X509Data x509data = new X509Data(element, BaseURI); int noOfISS = x509data.lengthIssuerSerial(); while (storage.hasNext()) { X509Certificate cert = storage.next(); XMLX509IssuerSerial certSerial = new XMLX509IssuerSerial(element.getOwnerDocument(), cert); - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate Issuer: " + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Found Certificate Issuer: " + certSerial.getIssuerName()); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate Serial: " + log.log(java.util.logging.Level.FINE, "Found Certificate Serial: " + certSerial.getSerialNumber().toString()); } for (int i=0; i 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } /** * Method engineResolvePublicKey @@ -102,11 +57,11 @@ public class X509SKIResolver extends KeyResolverSpi { * @return null if no {@link PublicKey} could be obtained * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -125,46 +80,55 @@ public class X509SKIResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - - try { - if (this._x509childNodes == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509childNodes == null)) { - return null; - } - } - + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + } + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_X509DATA)) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + /** Field _x509childObject[] */ + XMLX509SKI x509childObject[] = null; + + Element x509childNodes[] = null; + x509childNodes = XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509SKI); + + if (!((x509childNodes != null) + && (x509childNodes.length > 0))) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509SKI }; KeyResolverException ex = new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - this._x509childObject = - new XMLX509SKI[this._x509childNodes.length]; + x509childObject = new XMLX509SKI[x509childNodes.length]; - for (int i = 0; i < this._x509childNodes.length; i++) { - this._x509childObject[i] = - new XMLX509SKI(this._x509childNodes[i], BaseURI); + for (int i = 0; i < x509childNodes.length; i++) { + x509childObject[i] = + new XMLX509SKI(x509childNodes[i], BaseURI); } while (storage.hasNext()) { X509Certificate cert = storage.next(); XMLX509SKI certSKI = new XMLX509SKI(element.getOwnerDocument(), cert); - for (int i = 0; i < this._x509childObject.length; i++) { - if (certSKI.equals(this._x509childObject[i])) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Return PublicKey from " + for (int i = 0; i < x509childObject.length; i++) { + if (certSKI.equals(x509childObject[i])) { + log.log(java.util.logging.Level.FINE, "Return PublicKey from " + cert.getSubjectDN().getName()); return cert; @@ -186,7 +150,7 @@ public class X509SKIResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java index 5da6a7d8fd75d5288c62fe171d7ef9a647ce9305..05e82226c4c3a377304a0a1a8311f2a56ff42ee6 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java @@ -38,7 +38,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509SubjectNameResolver extends KeyResolverSpi { @@ -47,50 +47,6 @@ public class X509SubjectNameResolver extends KeyResolverSpi { java.util.logging.Logger.getLogger( X509SubjectNameResolver.class.getName()); - /** Field _x509childNodes */ - private Element[] _x509childNodes = null; - - /** Field _x509childObject[] */ - private XMLX509SubjectName _x509childObject[] = null; - - /** - * Method engineCanResolve - * @inheritDoc - * @param element - * @param BaseURI - * @param storage - * - */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - - if (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_X509DATA) ) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - - - this._x509childNodes = XMLUtils.selectDsNodes(element, - Constants._TAG_X509SUBJECTNAME); - - if ((this._x509childNodes != null) - && (this._x509childNodes.length > 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } /** * Method engineResolvePublicKey @@ -101,11 +57,11 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * @return null if no {@link PublicKey} could be obtained * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -124,37 +80,46 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + Element[] x509childNodes = null; + XMLX509SubjectName x509childObject[] = null; + + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_X509DATA) ) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + x509childNodes = XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509SUBJECTNAME); - try { - if (this._x509childNodes == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509childNodes == null)) { - return null; + if (!((x509childNodes != null) + && (x509childNodes.length > 0))) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; } - } + try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509SUBJECTNAME }; KeyResolverException ex = new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - this._x509childObject = - new XMLX509SubjectName[this._x509childNodes.length]; + x509childObject = + new XMLX509SubjectName[x509childNodes.length]; - for (int i = 0; i < this._x509childNodes.length; i++) { - this._x509childObject[i] = - new XMLX509SubjectName(this._x509childNodes[i], + for (int i = 0; i < x509childNodes.length; i++) { + x509childObject[i] = + new XMLX509SubjectName(x509childNodes[i], BaseURI); } @@ -163,24 +128,24 @@ public class X509SubjectNameResolver extends KeyResolverSpi { XMLX509SubjectName certSN = new XMLX509SubjectName(element.getOwnerDocument(), cert); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate SN: " + certSN.getSubjectName()); + log.log(java.util.logging.Level.FINE, "Found Certificate SN: " + certSN.getSubjectName()); - for (int i = 0; i < this._x509childObject.length; i++) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Element SN: " - + this._x509childObject[i].getSubjectName()); + for (int i = 0; i < x509childObject.length; i++) { + log.log(java.util.logging.Level.FINE, "Found Element SN: " + + x509childObject[i].getSubjectName()); - if (certSN.equals(this._x509childObject[i])) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "match !!! "); + if (certSN.equals(x509childObject[i])) { + log.log(java.util.logging.Level.FINE, "match !!! "); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "no match..."); + log.log(java.util.logging.Level.FINE, "no match..."); } } return null; } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); throw new KeyResolverException("generic.EmptyMessage", ex); } @@ -194,7 +159,7 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java index 46fee3d4240467ab6fbac1bc4240439a15464426..f1a8dd3400d090235e1d1dfe9ea5c621a75c9bde 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage; - - import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -36,7 +33,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.implementations.Sin /** * This class collects customized resolvers for Certificates. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class StorageResolver { @@ -45,7 +42,7 @@ public class StorageResolver { java.util.logging.Logger.getLogger(StorageResolver.class.getName()); /** Field _storageResolvers */ - List _storageResolvers = new ArrayList(); + List _storageResolvers = null; /** Field _iterator */ Iterator _iterator = null; @@ -71,7 +68,8 @@ public class StorageResolver { * @param resolver */ public void add(StorageResolverSpi resolver) { - + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._storageResolvers.add(resolver); this._iterator = null; @@ -126,6 +124,8 @@ public class StorageResolver { public Iterator getIterator() { if (this._iterator == null) { + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._iterator = new StorageResolverIterator(this._storageResolvers.iterator()); } @@ -140,6 +140,8 @@ public class StorageResolver { public boolean hasNext() { if (this._iterator == null) { + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._iterator = new StorageResolverIterator(this._storageResolvers.iterator()); } @@ -158,15 +160,13 @@ public class StorageResolver { /** * Class StorageResolverIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class StorageResolverIterator implements Iterator { + static class StorageResolverIterator implements Iterator { /** Field _resolvers */ - Iterator _resolvers = null; - - /** Field _currentResolver */ - int _currentResolver = 0; + Iterator _resolvers = null; /** * Constructor FilesystemIterator @@ -179,17 +179,16 @@ public class StorageResolver { /** @inheritDoc */ public boolean hasNext() { - return _resolvers.hasNext(); + return _resolvers.hasNext(); } /** @inheritDoc */ public Object next() { - return _resolvers.next(); + return _resolvers.next(); } /** * Method remove - * */ public void remove() { throw new UnsupportedOperationException( diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java index 2388ef19bc8244437c8f3d3163cfdc254ef48435..29dff030f78b03f346028a1361f50ecf26724838 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class StorageResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java index dc95e60407f2b4346a5a8bbbbfef917a689f6b7d..25f3e2828d2e8441ff81b32ebd5ee8f511410994 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import java.util.Iterator; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class StorageResolverSpi { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java index 6c6909665c30cbdd5250ce898b8d44cfdb2415d5..06fb5694befe6849bc27c6f9729d567f38e71d37 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -40,12 +37,11 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverExce import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; import com.sun.org.apache.xml.internal.security.utils.Base64; - /** * This {@link StorageResolverSpi} makes all raw (binary) {@link X509Certificate}s * which reside as files in a single directory available to the {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { @@ -131,20 +127,20 @@ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { dn = cert.getSubjectDN().getName(); added = true; } catch (FileNotFoundException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateNotYetValidException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateExpiredException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } if (added) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Added certificate: " + dn); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Added certificate: " + dn); } } } @@ -157,9 +153,10 @@ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { /** * Class FilesystemIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class FilesystemIterator implements Iterator { + private static class FilesystemIterator implements Iterator { /** Field _certs */ List _certs = null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java index ad1eb6b149465880ca5e61b14ab42b4b67a19b96..18632433ca515217153e33b1368751603006489b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.X509Certificate; @@ -37,7 +34,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; * Makes the Certificates from a JAVA {@link KeyStore} object available to the * {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyStoreResolver extends StorageResolverSpi { @@ -66,9 +63,10 @@ public class KeyStoreResolver extends StorageResolverSpi { /** * Class KeyStoreIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class KeyStoreIterator implements Iterator { + static class KeyStoreIterator implements Iterator { /** Field _keyStore */ KeyStore _keyStore = null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java index 6c4f260b9d1b51c5ee44b53e7f9421b0539b6cb6..7e61b2a244d23ed955dec16b304ad5221e6894d0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.security.cert.X509Certificate; import java.util.Iterator; @@ -33,7 +30,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; * This {@link StorageResolverSpi} makes a single {@link X509Certificate} * available to the {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class SingleCertificateResolver extends StorageResolverSpi { @@ -61,9 +58,10 @@ public class SingleCertificateResolver extends StorageResolverSpi { /** * Class InternalIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class InternalIterator implements Iterator { + static class InternalIterator implements Iterator { /** Field _alreadyReturned */ boolean _alreadyReturned = false; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd index 1e886bf17760aad26920c92726ae1c9554deb86a..f57b9fabe4d3aa59de28f6c0c3930a8251a2a916 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd @@ -1,73 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml index d0d6edcee6956942553a2055b1362f08fa2f8e60..aea1595741b81fcf21298cc510e3cbb496acf636 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml @@ -1,380 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd index 3a08c64f4b6a93c30b83468c3827df0fe0231c9c..d69852ff8421c3400819831b6c16b56ce3f8d0af 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd @@ -1,347 +1,347 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd index 969dbb18c21e32ae80080095121f3c4939e08710..b2cc19f63a1f6958529002476d12ce11c39061ef 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd @@ -3,7 +3,7 @@ Joseph Reagle $last changed 20001215$ http://www.w3.org/2000/09/xmldsig# - $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $ + $Revision: 1.6 $ on $Date: 2008/07/24 16:15:03 $ by $Author: mullan $ Copyright 2001 The Internet Society and W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd index df126b30e684091b32a748cd2e408f5fb9d651a9..e8288a526c3995e0737456793c25660ebe25ab2b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd @@ -11,7 +11,7 @@ + + + + +This package contains classes that allow the creation +and manipulation of service tags. +This com.sun.servicetag package is intended for +Sun internal use only. +

    +

    +
    Service Tag
    +
    A service tag is an XML-based data structure that contains identifying +information about an instance of a product or component on a system. +
    +
    +
    +
    Service Tag Registry
    +
    A service tag registry is a XML-based registry that contains +the service tags of all the tagged components on a system. The +service tag registry is present on systems that have the +Service Tags software installed. +
    +
    +
    +
    Registration Data
    +
    A registration data is a container of one or more +service tags that identify the +components for product registration and will be used to interface +with the Sun Connection registration services. +
    +
    + +This package contains the methods to create service tags, set up the +registration data for product registration, add service tags to and +remove them from the system service tag registry. +

    +All methods defined in this package will throw {@code NullPointerException} +if {@code null} is passed in any input parameter unless it is stated otherwise. +In addition, they are multi-thread safe. + + + + diff --git a/src/share/classes/com/sun/servicetag/resources/Putback-Notes.txt b/src/share/classes/com/sun/servicetag/resources/Putback-Notes.txt new file mode 100644 index 0000000000000000000000000000000000000000..70e8cffbd6f636c2625f820dc3480c1961bba047 --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/Putback-Notes.txt @@ -0,0 +1,25 @@ +README for auto-generating of the offline registration page. + +1. register.html is defined by the xDesign team. + +2. Before putback in the workspace, we need to modify the + register.html to contain the following: + + (a) replace the pathname of the jdk_header.png image to + + + (b) replace the product name from: + Java Development Kit Version 6 Update 5 (e.g.) + to: + Java Development Kit @@JDK_VERSION@@ + + (c) replace the form action for the "Register My JDK" button with: + +

    + + (d) Add this input in the form for posting data after + the line: + + + +3. The jdk_header.png is located under /lib/servicetag directory. diff --git a/make/tools/auto_multi/Makefile b/src/share/classes/com/sun/servicetag/resources/javase_5_swordfish.properties similarity index 71% rename from make/tools/auto_multi/Makefile rename to src/share/classes/com/sun/servicetag/resources/javase_5_swordfish.properties index f5db35099ad75c79a33e9e0f4ad67207be10b452..8b58c32f097a31b77c28a0caf80ae7650553e0bb 100644 --- a/make/tools/auto_multi/Makefile +++ b/src/share/classes/com/sun/servicetag/resources/javase_5_swordfish.properties @@ -1,5 +1,4 @@ -# -# Copyright 1998-2005 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 @@ -21,23 +20,10 @@ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. -# - -# -# Makefile for building the automulti tool -# - -BUILDDIR = ../.. -PACKAGE = build.tools.automulti -PRODUCT = tools -PROGRAM = automulti -include $(BUILDDIR)/common/Defs.gmk - -BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src -BUILDTOOL_MAIN = $(PKGDIR)/AutoMulti.java - -# -# Build tool jar rules. -# -include $(BUILDDIR)/common/BuildToolJar.gmk +servicetag.jdk.urn = urn:uuid:d5bed446-05f2-42ed-ba0a-153105a52413 +servicetag.jdk.name = J2SE 5.0 Development Kit +servicetag.jre.urn = urn:uuid:5c6686aa-fd05-46a6-ba3e-700e2d5f7043 +servicetag.jre.name = J2SE 5.0 Runtime Environment +servicetag.parent.urn = urn:uuid:f3c20172-557a-11d7-93d0-d6a41ea318df +servicetag.parent.name = Java 2 Platform, Standard Edition 5.0 diff --git a/src/share/classes/com/sun/servicetag/resources/javase_6_swordfish.properties b/src/share/classes/com/sun/servicetag/resources/javase_6_swordfish.properties new file mode 100644 index 0000000000000000000000000000000000000000..982c9666c40ec5dc849151ba148a07bade08850c --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/javase_6_swordfish.properties @@ -0,0 +1,29 @@ +# 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. + +servicetag.jdk.urn = urn:uuid:b58ef9a8-5ae8-11db-a023-080020a9ed93 +servicetag.jdk.name = Java SE 6 Development Kit +servicetag.jre.urn = urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc +servicetag.jre.name = Java SE 6 Runtime Environment +servicetag.parent.urn = urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3 +servicetag.parent.name = Java Platform Standard Edition 6 (Java SE 6) diff --git a/src/share/classes/sun/nio/ch/exceptions b/src/share/classes/com/sun/servicetag/resources/javase_7_swordfish.properties similarity index 74% rename from src/share/classes/sun/nio/ch/exceptions rename to src/share/classes/com/sun/servicetag/resources/javase_7_swordfish.properties index 55d295f871d4c5b03273f102d2c7d9188c975916..45eebd2d319d7e034087de872e7986d8b7a6c668 100644 --- a/src/share/classes/sun/nio/ch/exceptions +++ b/src/share/classes/com/sun/servicetag/resources/javase_7_swordfish.properties @@ -1,5 +1,4 @@ -# -# Copyright 2000-2007 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 @@ -21,19 +20,10 @@ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. -# - -# Generated exception classes for sun.nio.ch - -SINCE=1.4 -PACKAGE=sun.nio.ch -# This year should only change if the generated source is modified. -COPYRIGHT_YEARS=2000-2007 - - -SUPER=IllegalStateException -gen AlreadyBoundException " - * Unchecked exception thrown when an attempt is made to bind a {@link - * SocketChannel} that is already bound." \ - 9002280723481772026L +servicetag.jdk.urn = JSEZ9-007-ZZZZ +servicetag.jdk.name = Java SE 7 Development Kit +servicetag.jre.urn = JSERE-007-ZZZZ +servicetag.jre.name = Java SE 7 Runtime Environment +servicetag.parent.urn = urn:uuid:dc1704fe-264f-11dc-9482-080020a9ed93 +servicetag.parent.name = Java Platform Standard Edition 7 (Java SE 7) diff --git a/src/share/classes/com/sun/servicetag/resources/jdk_header.png b/src/share/classes/com/sun/servicetag/resources/jdk_header.png new file mode 100644 index 0000000000000000000000000000000000000000..011cfd4cd8aad0697b25257240ac338021f531c0 Binary files /dev/null and b/src/share/classes/com/sun/servicetag/resources/jdk_header.png differ diff --git a/src/share/classes/com/sun/servicetag/resources/product_registration.xsd b/src/share/classes/com/sun/servicetag/resources/product_registration.xsd new file mode 100644 index 0000000000000000000000000000000000000000..43d27455b46c45a28edd1d14343ecd546ea6c1ec --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/product_registration.xsd @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/servicetag/resources/register.html b/src/share/classes/com/sun/servicetag/resources/register.html new file mode 100644 index 0000000000000000000000000000000000000000..23e9d717ab7ec713ea51f24141057792c0656f29 --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/register.html @@ -0,0 +1,105 @@ + + + + +Register your JDK + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
     

    Thank you for installing the + Java Development Kit @@JDK_VERSION@@ + from Sun Microsystems.

    +

    Registering your product will give you the following benefits:

    +
      +
    • Notification of new versions, patches, and updates
    • +
    • Special offers on Sun developer products, services and training
    • +
    • Access to early releases and documentation
    • +
    +

    Product registration is FREE, quick and easy!

    +
    +

    All you need is a Sun Developer Network or other Sun Online account. If you don't already have one, you will be prompted to create one.

    + + + + + +
    + + + + You need to be connected to the Internet to register this Sun product.
    +
    +
      +

    Sun Microsystems, Inc. respects your privacy. + We will use your personal information for communications + and management of your Sun Online Account, the services + and applications you access using your Sun Online Account, + and the products and systems you register with your Sun Online Account.

    +

    For more information on the data that will be collected as + part of the registration process and how it will be managed
    + see http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html.
    +
    + For more information on Sun's Privacy Policy see http://www.sun.com/privacy/ or contact privacy@sun.com.

      
      
    + + diff --git a/src/share/classes/com/sun/servicetag/resources/register_ja.html b/src/share/classes/com/sun/servicetag/resources/register_ja.html new file mode 100644 index 0000000000000000000000000000000000000000..56ee84f54267a45cc9d4231c65f9c526b7e1a3ea --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/register_ja.html @@ -0,0 +1,91 @@ + + + + +JDK 製å“登録 + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
     

    Sun Microsystems ã® Java Development Kit @@JDK_VERSION@@ をインストールã—ã¦ã„ãŸã ãã€ã‚りãŒã¨ã†ã”ã–ã„ã¾ã™ã€‚

    +

    製å“登録をã™ã‚‹ã¨ã€æ¬¡ã®ã‚ˆã†ãªç‰¹å…¸ã‚’å—ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

    +
      +
    • 最新ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã€ãƒ‘ッãƒã€ãŠã‚ˆã³æ›´æ–°ã«ã¤ã„ã¦ã®é€šçŸ¥
    • +
    • Sun ã®é–‹ç™ºè€…å‘ã‘製å“ã€ã‚µãƒ¼ãƒ“スã€ãŠã‚ˆã³ãƒˆãƒ¬ãƒ¼ãƒ‹ãƒ³ã‚°ã®ç‰¹åˆ¥è²©å£²
    • +
    • アーリーリリースãŠã‚ˆã³ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¸ã®ã‚¢ã‚¯ã‚»ã‚¹
    • +
    +

    製å“登録ã¯ç„¡æ–™ã§ã‚りã€è¿…速ã§ç°¡å˜ã§ã™ã€‚

    +
    +

    å¿…è¦ã«ãªã‚‹ã®ã¯ã€Sun 開発者å‘ã‘ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¾ãŸã¯ãã®ä»–ã® Sun オンラインアカウントã ã‘ã§ã™ã€‚ ã¾ã ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒãªã„å ´åˆã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ä½œæˆãŒæ±‚ã‚られã¾ã™ã€‚

    + + + + + +
    + + +
    ã“ã® Sun 製å“を登録ã™ã‚‹ã«ã¯ã€ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã«æŽ¥ç¶šã—ã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
    +
    +
      +

    Sun Microsystems, Inc. ã¯ã€ãŠå®¢æ§˜ã®ãƒ—ライãƒã‚·ãƒ¼ã‚’å°Šé‡ã—ã¾ã™ã€‚ ãŠå®¢æ§˜ã®å€‹äººæƒ…å ±ã¯ã€ãŠå®¢æ§˜ã® Sun オンラインアカウントã€ãŠå®¢æ§˜ãŒ Sun オンラインアカウントを使用ã—ã¦ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã‚µãƒ¼ãƒ“スã¨ã‚¢ãƒ—リケーションã€ãŠã‚ˆã³ãŠå®¢æ§˜ãŒ Sun オンラインアカウントã§ç™»éŒ²ã™ã‚‹è£½å“ã¨ã‚·ã‚¹ãƒ†ãƒ ã®é€šä¿¡ã¨ç®¡ç†ã«ä½¿ç”¨ã—ã¾ã™ã€‚

    +

    登録ã®éš›ã«åŽé›†ã•れるデータやã€ãれらãŒã©ã®ã‚ˆã†ã«ç®¡ç†ã•れるã‹ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€
    http://java.sun.com/javase/ja/registration/JDKRegistrationPrivacy.html ã‚’å‚ç…§ã—ã¦ãã ã•ã„。

    Sun ã®ãƒ—ライãƒã‚·ãƒ¼ãƒãƒªã‚·ãƒ¼ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€http://jp.sun.com/privacy/ ã‚’å‚ç…§ã™ã‚‹ã‹ã€ãŠå•ã„åˆã‚ã›ãƒ•ォームã‹ã‚‰ãŠå•ã„åˆã‚ã›ãã ã•ã„。

      
      
    + + diff --git a/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html b/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html new file mode 100644 index 0000000000000000000000000000000000000000..c47929fb7445d2aceae6f9ac4ef9b4fe658a1e8d --- /dev/null +++ b/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html @@ -0,0 +1,92 @@ + + + + +注册您的 JDK + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
     

    感谢您安装 Sun Microsystems 的 Java Development Kit @@JDK_VERSION@@。

    +

    注册产å“åŽæ‚¨å°†èŽ·å¾—å¦‚ä¸‹å¢žå€¼æœåŠ¡ï¼š

    +
      +
    • 获得新版本ã€ä¿®è¡¥ç¨‹åºå’Œæ›´æ–°çš„通知æœåŠ¡
    • +
    • 获得有关 Sun å¼€å‘者产å“ã€æœåŠ¡å’ŒåŸ¹è®­çš„ä¼˜æƒ 
    • +
    • 获得对早期版本和文档的访问æƒé™
    • +
    +

    äº§å“æ³¨å†Œæ˜¯å…费的,å³å¿«é€Ÿåˆè½»æ¾ï¼

    +
    +

    您需è¦å…·æœ‰ Sun å¼€å‘者网络或其他 Sun è”æœºå¸æˆ·ã€‚如果您没有,系统将æç¤ºæ‚¨åˆ›å»ºä¸€ä¸ªã€‚

    + + + + + +
    + + +
    您需è¦è¿žæŽ¥åˆ° Internet æ¥æ³¨å†Œæ­¤ Sun 产å“。
    +
    +
      +

    Sun Microsystems, Inc. å°Šé‡æ‚¨çš„éšç§ã€‚我们会将您的个人信æ¯ç”¨äºŽé€šä¿¡å’Œ Sun è”æœºå¸æˆ·çš„管ç†ã€Sun è”æœºå¸æˆ·è®¿é—®çš„æœåŠ¡å’Œåº”ç”¨ç¨‹åºä»¥åŠç”¨äºŽä½¿ç”¨ Sun è”æœºå¸æˆ·æ³¨å†Œçš„产å“和系统。

    +

    有关注册过程中收集的数æ®ä»¥åŠè¿™äº›æ•°æ®çš„ç®¡ç†æ–¹å¼çš„æ›´å¤šä¿¡æ¯ï¼Œ
    请访问 http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html。

    有关 Sun éšç§æ”¿ç­–的更多信æ¯ï¼Œè¯·è®¿é—® http://www.sun.com/privacy/ 或与 privacy@sun.com è”系。

      
      
    + + diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties index 6087def3607ad0e1ff5767b4b77da96cc14795d7..4dac249bfa02d51e370a6693bd856ab04fd70f2a 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=Sample Text Sample Text ColorChooser.swatchesNameText=Swatches ColorChooser.swatchesMnemonic=83 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Recent: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=Red ColorChooser.rgbRedMnemonic=68 ColorChooser.rgbGreenText=Green ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=Blue ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties index 93660548035468b21864fdfb7bcdc953afc12d11..b345597773881824428b934cda91e5d4f2b9b6bd 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=90 ColorChooser.sampleText=Beispieltext Beispieltext ColorChooser.swatchesNameText=Muster ColorChooser.swatchesMnemonic=77 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Aktuell: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=Rot ColorChooser.rgbRedMnemonic=82 ColorChooser.rgbGreenText=Gr\u00fcn ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=Blau ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties index b553b26f06525ebef312d8cbd5cf0869e12f0f7f..75877dd656062c436e9e2b3b1731b8daba8a6f29 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=Texto de ejemplo Texto de ejemplo ColorChooser.swatchesNameText=Muestras ColorChooser.swatchesMnemonic=77 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Reciente: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=V -ColorChooser.hsbBlueText=A +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=Rojo ColorChooser.rgbRedMnemonic=74 ColorChooser.rgbGreenText=Verde ColorChooser.rgbGreenMnemonic=86 ColorChooser.rgbBlueText=Azul ColorChooser.rgbBlueMnemonic=76 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties index b18de0274a8730ab954abe08225f4e9e20a4a3d4..333a1a82fa1d8752299892ccd84cd4bd1c7de94b 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=Echantillon de texte Echantillon de texte ColorChooser.swatchesNameText=Echantillons ColorChooser.swatchesMnemonic=69 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Dernier : -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=V -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RVB ColorChooser.rgbMnemonic=86 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=Rouge ColorChooser.rgbRedMnemonic=71 ColorChooser.rgbGreenText=Vert ColorChooser.rgbGreenMnemonic=84 ColorChooser.rgbBlueText=Bleu ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties index 1c9f3790e6fbbbacaf63cbd67ce2b4c8c1a50141..7bc69dbcf5e45583730c7822c5b90d301e94c229 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=Testo di prova Testo di prova ColorChooser.swatchesNameText=Colori campione ColorChooser.swatchesMnemonic=67 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Recenti: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=Rosso ColorChooser.rgbRedMnemonic=79 ColorChooser.rgbGreenText=Verde ColorChooser.rgbGreenMnemonic=69 ColorChooser.rgbBlueText=Blu ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties index 1b5a131cabde008e5c76b926bb78114cf6faffa7..5603e9aa1bc09c79c2adf13930945d5454500362 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=\u30b5\u30f3\u30d7\u30eb\u30c6\u30ad\u30b9\u30c8 \u30b5\u30f3\u30d7\u30eb\u30c6\u30ad\u30b9\u30c8 ColorChooser.swatchesNameText=\u30b5\u30f3\u30d7\u30eb(S) ColorChooser.swatchesMnemonic=83 -ColorChooser.swatchesDisplayedMnemonicIndex=5 ColorChooser.swatchesRecentText=\u6700\u65b0: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=\u8d64(D) ColorChooser.rgbRedMnemonic=68 ColorChooser.rgbGreenText=\u7dd1(N) ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=\u9752(B) ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties index 9b873a43a61bcf05987a333192fb6237223d4f20..f3866d01f31f8bed0405cc6f7c4713d220359514 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=\uc0d8\ud50c \ud14d\uc2a4\ud2b8 \uc0d8\ud50c \ud14d\uc2a4\ud2b8 ColorChooser.swatchesNameText=\uacac\ubcf8(S) ColorChooser.swatchesMnemonic=83 -ColorChooser.swatchesDisplayedMnemonicIndex=3 ColorChooser.swatchesRecentText=\ucd5c\uadfc \ubaa9\ub85d: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=\ube68\uac04\uc0c9(D) ColorChooser.rgbRedMnemonic=68 ColorChooser.rgbGreenText=\ub179\uc0c9(N) ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=\ud30c\ub780\uc0c9(B) ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties index 2b8561b812e83b7de7d18cd73ab5525ad77dce5b..17ef3b2be265be857aedcc9c5027a6c660b8a795 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=84 ColorChooser.sampleText=Exempeltext Exempeltext ColorChooser.swatchesNameText=Prov ColorChooser.swatchesMnemonic=80 -ColorChooser.swatchesDisplayedMnemonicIndex=0 ColorChooser.swatchesRecentText=Tidigare: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=R\u00f6d ColorChooser.rgbRedMnemonic=82 ColorChooser.rgbGreenText=Gr\u00f6n ColorChooser.rgbGreenMnemonic=71 ColorChooser.rgbBlueText=Bl\u00e5 ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties index 7ef35330d865a29703dc9b50f09ce6de22d0dfea..b030c20a944d95f0be26af00df8bdaf1c34146d5 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=\u6837\u54c1\u6587\u672c \u6837\u54c1\u6587\u672c ColorChooser.swatchesNameText=\u6837\u54c1(S) ColorChooser.swatchesMnemonic=83 -ColorChooser.swatchesDisplayedMnemonicIndex=3 ColorChooser.swatchesRecentText=\u6700\u8fd1: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=\u7ea2 ColorChooser.rgbRedMnemonic=68 ColorChooser.rgbGreenText=\u7eff ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=\u84dd ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties index dba0d76de2884113001e0d72dd7a2e68495ceb53..47f99f0dcc90f5c6d736729c223288390c8f8292 100644 --- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties @@ -101,30 +101,41 @@ ColorChooser.resetMnemonic=82 ColorChooser.sampleText=\u7bc4\u4f8b\u6587\u5b57 \u7bc4\u4f8b\u6587\u5b57 ColorChooser.swatchesNameText=\u8abf\u8272\u677f(S) ColorChooser.swatchesMnemonic=83 -ColorChooser.swatchesDisplayedMnemonicIndex=4 ColorChooser.swatchesRecentText=\u6700\u65b0\u9078\u64c7: -ColorChooser.hsbNameText=HSB # Each of the ColorChooser types can define a mnemonic, as a KeyEvent.VK_XXX # constant, and an index into the text to render the mnemonic as. The # mnemonic is xxxMnemonic and the index of the character to underline is # xxxDisplayedMnemonicIndex. -ColorChooser.hsbMnemonic=72 -ColorChooser.hsbDisplayedMnemonicIndex=0 -ColorChooser.hsbHueText=H -ColorChooser.hsbSaturationText=S -ColorChooser.hsbBrightnessText=B -ColorChooser.hsbRedText=R -ColorChooser.hsbGreenText=G -ColorChooser.hsbBlueText=B +ColorChooser.hsvNameText=HSV +ColorChooser.hsvMnemonic=72 +ColorChooser.hsvHueText=Hue +ColorChooser.hsvSaturationText=Saturation +ColorChooser.hsvValueText=Value +ColorChooser.hsvTransparencyText=Transparency +ColorChooser.hslNameText=HSL +ColorChooser.hslMnemonic=76 +ColorChooser.hslHueText=Hue +ColorChooser.hslSaturationText=Saturation +ColorChooser.hslLightnessText=Lightness +ColorChooser.hslTransparencyText=Transparency ColorChooser.rgbNameText=RGB ColorChooser.rgbMnemonic=71 -ColorChooser.rgbDisplayedMnemonicIndex=1 ColorChooser.rgbRedText=\u7d05\u8272(D) ColorChooser.rgbRedMnemonic=68 ColorChooser.rgbGreenText=\u7da0\u8272(N) ColorChooser.rgbGreenMnemonic=78 ColorChooser.rgbBlueText=\u85cd\u8272(B) ColorChooser.rgbBlueMnemonic=66 +ColorChooser.rgbAlphaText=Alpha +ColorChooser.rgbHexCodeText=Color Code +ColorChooser.rgbHexCodeMnemonic=67 +ColorChooser.cmykNameText=CMYK +ColorChooser.cmykMnemonic=77 +ColorChooser.cmykCyanText=Cyan +ColorChooser.cmykMagentaText=Magenta +ColorChooser.cmykYellowText=Yellow +ColorChooser.cmykBlackText=Black +ColorChooser.cmykAlphaText=Alpha ############ OPTION PANE STRINGS ############# # Mnemonic keys correspond to KeyEvent.VK_XXX constant diff --git a/src/share/classes/com/sun/tools/extcheck/ExtCheck.java b/src/share/classes/com/sun/tools/extcheck/ExtCheck.java index b83381a6514889a310fae5f3d8c208aaf9aadaf7..b69cf00cd8bd799cbd4633c03faea623d9fb07a7 100644 --- a/src/share/classes/com/sun/tools/extcheck/ExtCheck.java +++ b/src/share/classes/com/sun/tools/extcheck/ExtCheck.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 @@ -256,13 +256,13 @@ public class ExtCheck { private boolean isNotOlderThan(String already,String target) throws NumberFormatException { - if (already == null || already.length() < 1) { + if (already == null || already.length() < 1) { throw new NumberFormatException("Empty version string"); } - // Until it matches scan and compare numbers - StringTokenizer dtok = new StringTokenizer(target, ".", true); - StringTokenizer stok = new StringTokenizer(already, ".", true); + // Until it matches scan and compare numbers + StringTokenizer dtok = new StringTokenizer(target, ".", true); + StringTokenizer stok = new StringTokenizer(already, ".", true); while (dtok.hasMoreTokens() || stok.hasMoreTokens()) { int dver; int sver; @@ -276,19 +276,19 @@ public class ExtCheck { } else sver = 0; - 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 + 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..eda2dfc747f0bbfae0db24bd7b0cd7a249e4f590 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 @@ -61,7 +61,8 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl private ThreadGroupReference threadGroup; // This is cached only while this one thread is suspended. Each time - // the thread is resumed, we clear this and start with a fresh one. + // the thread is resumed, we abandon the current cache object and + // create a new intialized one. private static class LocalCache { JDWP.ThreadReference.Status status = null; List frames = null; @@ -74,6 +75,28 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl boolean triedCurrentContended = false; } + /* + * The localCache instance var is set by resetLocalCache to an initialized + * object as shown above. This occurs when the ThreadReference + * object is created, and when the mirrored thread is resumed. + * The fields are then filled in by the relevant methods as they + * are called. A problem can occur if resetLocalCache is called + * (ie, a resume() is executed) at certain points in the execution + * of some of these methods - see 6751643. To avoid this, each + * method that wants to use this cache must make a local copy of + * this variable and use that. This means that each invocation of + * these methods will use a copy of the cache object that was in + * effect at the point that the copy was made; if a racy resume + * occurs, it won't affect the method's local copy. This means that + * the values returned by these calls may not match the state of + * the debuggee at the time the caller gets the values. EG, + * frameCount() is called and comes up with 5 frames. But before + * it returns this, a resume of the debuggee thread is executed in a + * different debugger thread. The thread is resumed and running at + * the time that the value 5 is returned. Or even worse, the thread + * could be suspended again and have a different number of frames, eg, 24, + * but this call will still return 5. + */ private LocalCache localCache; private void resetLocalCache() { @@ -129,8 +152,9 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl } /** - * Note that we only cache the name string while suspended because - * it can change via Thread.setName arbitrarily + * Note that we only cache the name string while the entire VM is suspended + * because the name can change via Thread.setName arbitrarily while this + * thread is running. */ public String name() { String name = null; @@ -240,19 +264,20 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl } private JDWP.ThreadReference.Status jdwpStatus() { - JDWP.ThreadReference.Status myStatus = localCache.status; + LocalCache snapshot = localCache; + JDWP.ThreadReference.Status myStatus = snapshot.status; try { if (myStatus == null) { myStatus = JDWP.ThreadReference.Status.process(vm, this); if ((myStatus.suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0) { // thread is suspended, we can cache the status. - localCache.status = myStatus; + snapshot.status = myStatus; } } } catch (JDWPException exc) { throw exc.toJDIException(); } - return myStatus; + return myStatus; } public int status() { @@ -304,9 +329,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl } public int frameCount() throws IncompatibleThreadStateException { + LocalCache snapshot = localCache; try { - if (localCache.frameCount == -1) { - localCache.frameCount = JDWP.ThreadReference.FrameCount + if (snapshot.frameCount == -1) { + snapshot.frameCount = JDWP.ThreadReference.FrameCount .process(vm, this).frameCount; } } catch (JDWPException exc) { @@ -318,7 +344,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl throw exc.toJDIException(); } } - return localCache.frameCount; + return snapshot.frameCount; } public List frames() throws IncompatibleThreadStateException { @@ -335,22 +361,22 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl * local is known to be non-null. Should only be called from * a sync method. */ - private boolean isSubrange(LocalCache localCache, + private boolean isSubrange(LocalCache snapshot, int start, int length) { - if (start < localCache.framesStart) { + if (start < snapshot.framesStart) { return false; } if (length == -1) { - return (localCache.framesLength == -1); + return (snapshot.framesLength == -1); } - if (localCache.framesLength == -1) { - if ((start + length) > (localCache.framesStart + - localCache.frames.size())) { + if (snapshot.framesLength == -1) { + if ((start + length) > (snapshot.framesStart + + snapshot.frames.size())) { throw new IndexOutOfBoundsException(); } return true; } - return ((start + length) <= (localCache.framesStart + localCache.framesLength)); + return ((start + length) <= (snapshot.framesStart + snapshot.framesLength)); } public List frames(int start, int length) @@ -371,14 +397,14 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl // Lock must be held while creating stack frames so if that two threads // do this at the same time, one won't clobber the subset created by the other. - + LocalCache snapshot = localCache; try { - if (localCache.frames == null || !isSubrange(localCache, start, length)) { + if (snapshot.frames == null || !isSubrange(snapshot, start, length)) { JDWP.ThreadReference.Frames.Frame[] jdwpFrames = JDWP.ThreadReference.Frames. process(vm, this, start, length).frames; int count = jdwpFrames.length; - localCache.frames = new ArrayList(count); + snapshot.frames = new ArrayList(count); for (int i = 0; i ownedMonitors() throws IncompatibleThreadStateException { + LocalCache snapshot = localCache; try { - if (localCache.ownedMonitors == null) { - localCache.ownedMonitors = Arrays.asList( + if (snapshot.ownedMonitors == null) { + snapshot.ownedMonitors = Arrays.asList( (ObjectReference[])JDWP.ThreadReference.OwnedMonitors. process(vm, this).owned); if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { vm.printTrace(description() + " temporarily caching owned monitors"+ - " (count = " + localCache.ownedMonitors.size() + ")"); + " (count = " + snapshot.ownedMonitors.size() + ")"); } } } catch (JDWPException exc) { @@ -435,54 +462,57 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl throw exc.toJDIException(); } } - return localCache.ownedMonitors; + return snapshot.ownedMonitors; } public ObjectReference currentContendedMonitor() throws IncompatibleThreadStateException { + LocalCache snapshot = localCache; try { - if (localCache.contendedMonitor == null && - !localCache.triedCurrentContended) { - localCache.contendedMonitor = JDWP.ThreadReference.CurrentContendedMonitor. + if (snapshot.contendedMonitor == null && + !snapshot.triedCurrentContended) { + snapshot.contendedMonitor = JDWP.ThreadReference.CurrentContendedMonitor. process(vm, this).monitor; - localCache.triedCurrentContended = true; - if ((localCache.contendedMonitor != null) && + snapshot.triedCurrentContended = true; + if ((snapshot.contendedMonitor != null) && ((vm.traceFlags & vm.TRACE_OBJREFS) != 0)) { vm.printTrace(description() + " temporarily caching contended monitor"+ - " (id = " + localCache.contendedMonitor.uniqueID() + ")"); + " (id = " + snapshot.contendedMonitor.uniqueID() + ")"); } } } catch (JDWPException exc) { switch (exc.errorCode()) { + case JDWP.Error.THREAD_NOT_SUSPENDED: case JDWP.Error.INVALID_THREAD: /* zombie */ throw new IncompatibleThreadStateException(); default: throw exc.toJDIException(); } } - return localCache.contendedMonitor; + return snapshot.contendedMonitor; } public List ownedMonitorsAndFrames() throws IncompatibleThreadStateException { + LocalCache snapshot = localCache; try { - if (localCache.ownedMonitorsInfo == null) { + if (snapshot.ownedMonitorsInfo == null) { JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor[] minfo; minfo = JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.process(vm, this).owned; - localCache.ownedMonitorsInfo = new ArrayList(minfo.length); + snapshot.ownedMonitorsInfo = new ArrayList(minfo.length); for (int i=0; i < minfo.length; i++) { JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor mi = minfo[i]; MonitorInfo mon = new MonitorInfoImpl(vm, minfo[i].monitor, this, minfo[i].stack_depth); - localCache.ownedMonitorsInfo.add(mon); + snapshot.ownedMonitorsInfo.add(mon); } if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { vm.printTrace(description() + " temporarily caching owned monitors"+ - " (count = " + localCache.ownedMonitorsInfo.size() + ")"); + " (count = " + snapshot.ownedMonitorsInfo.size() + ")"); } } @@ -495,7 +525,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl throw exc.toJDIException(); } } - return localCache.ownedMonitorsInfo; + return snapshot.ownedMonitorsInfo; } public void popFrames(StackFrame frame) throws IncompatibleThreadStateException { 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/EventDispatchThread.java b/src/share/classes/java/awt/EventDispatchThread.java index 35bde43447a9969a0cbd1b4b3dd4bcf535d4b658..d12a4a67c40f37b9c58b57fa9cc6951ef005902e 100644 --- a/src/share/classes/java/awt/EventDispatchThread.java +++ b/src/share/classes/java/awt/EventDispatchThread.java @@ -39,6 +39,7 @@ import java.util.Vector; import java.util.logging.*; import sun.awt.dnd.SunDragSourceContextPeer; +import sun.awt.EventQueueDelegate; /** * EventDispatchThread is a package-private AWT class which takes @@ -243,10 +244,16 @@ class EventDispatchThread extends Thread { try { AWTEvent event; boolean eventOK; + EventQueueDelegate.Delegate delegate = + EventQueueDelegate.getDelegate(); do { - event = (id == ANY_EVENT) - ? theQueue.getNextEvent() - : theQueue.getNextEvent(id); + if (delegate != null && id == ANY_EVENT) { + event = delegate.getNextEvent(theQueue); + } else { + event = (id == ANY_EVENT) + ? theQueue.getNextEvent() + : theQueue.getNextEvent(id); + } eventOK = true; synchronized (eventFilters) { @@ -272,7 +279,14 @@ class EventDispatchThread extends Thread { eventLog.log(Level.FINEST, "Dispatching: " + event); } + Object handle = null; + if (delegate != null) { + handle = delegate.beforeDispatch(event); + } theQueue.dispatchEvent(event); + if (delegate != null) { + delegate.afterDispatch(event, handle); + } return true; } catch (ThreadDeath death) { diff --git a/src/share/classes/java/awt/EventQueue.java b/src/share/classes/java/awt/EventQueue.java index f9c265262104f0cc6a1e8110f87ea94afbb8733c..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 diff --git a/src/share/classes/java/beans/DefaultPersistenceDelegate.java b/src/share/classes/java/beans/DefaultPersistenceDelegate.java index 6553a517200cb5df5f82c759508f9b1af8fc32e1..5339aba83e49659d30c220ebc70169bfa1d30f3d 100644 --- a/src/share/classes/java/beans/DefaultPersistenceDelegate.java +++ b/src/share/classes/java/beans/DefaultPersistenceDelegate.java @@ -298,7 +298,7 @@ public class DefaultPersistenceDelegate extends PersistenceDelegate { oldL = (EventListener[])MethodUtil.invoke(m, oldInstance, new Object[]{}); newL = (EventListener[])MethodUtil.invoke(m, newInstance, new Object[]{}); } - catch (Throwable e2) { + catch (Exception e2) { try { Method m = type.getMethod("getListeners", new Class[]{Class.class}); oldL = (EventListener[])MethodUtil.invoke(m, oldInstance, new Object[]{listenerType}); diff --git a/src/share/classes/java/beans/EventHandler.java b/src/share/classes/java/beans/EventHandler.java index 5b5be0528a6411a855a9bec2f05e785879f3b0d5..2cc005c79273f740f2431a0fd8404751662046cc 100644 --- a/src/share/classes/java/beans/EventHandler.java +++ b/src/share/classes/java/beans/EventHandler.java @@ -404,7 +404,7 @@ public class EventHandler implements InvocationHandler { Object newTarget = MethodUtil.invoke(getter, target, new Object[]{}); return applyGetters(newTarget, rest); } - catch (Throwable e) { + catch (Exception e) { throw new RuntimeException("Failed to call method: " + first + " on " + target, e); } diff --git a/src/share/classes/java/beans/MetaData.java b/src/share/classes/java/beans/MetaData.java index 9bcd505c215773b0f6589eb2b300055d6f522a7d..5d8fd69791854a4b8ae765b7e08c93dd73d251c4 100644 --- a/src/share/classes/java/beans/MetaData.java +++ b/src/share/classes/java/beans/MetaData.java @@ -650,7 +650,7 @@ class java_util_Map_PersistenceDelegate extends DefaultPersistenceDelegate { // Remove the new elements. // Do this first otherwise we undo the adding work. if (newMap != null) { - for ( Object newKey : newMap.keySet() ) { + for (Object newKey : newMap.keySet().toArray()) { // PENDING: This "key" is not in the right environment. if (!oldMap.containsKey(newKey)) { invokeStatement(oldInstance, "remove", new Object[]{newKey}, out); @@ -986,14 +986,20 @@ class java_awt_Component_PersistenceDelegate extends DefaultPersistenceDelegate // null to defined values after the Windows are made visible - // special case them for now. if (!(oldInstance instanceof java.awt.Window)) { - String[] fieldNames = new String[]{"background", "foreground", "font"}; - for(int i = 0; i < fieldNames.length; i++) { - String name = fieldNames[i]; - Object oldValue = ReflectionUtils.getPrivateField(oldInstance, java.awt.Component.class, name, out.getExceptionListener()); - Object newValue = (newInstance == null) ? null : ReflectionUtils.getPrivateField(newInstance, java.awt.Component.class, name, out.getExceptionListener()); - if (oldValue != null && !oldValue.equals(newValue)) { - invokeStatement(oldInstance, "set" + NameGenerator.capitalize(name), new Object[]{oldValue}, out); - } + Object oldBackground = c.isBackgroundSet() ? c.getBackground() : null; + Object newBackground = c2.isBackgroundSet() ? c2.getBackground() : null; + if (!MetaData.equals(oldBackground, newBackground)) { + invokeStatement(oldInstance, "setBackground", new Object[] { oldBackground }, out); + } + Object oldForeground = c.isForegroundSet() ? c.getForeground() : null; + Object newForeground = c2.isForegroundSet() ? c2.getForeground() : null; + if (!MetaData.equals(oldForeground, newForeground)) { + invokeStatement(oldInstance, "setForeground", new Object[] { oldForeground }, out); + } + Object oldFont = c.isFontSet() ? c.getFont() : null; + Object newFont = c2.isFontSet() ? c2.getFont() : null; + if (!MetaData.equals(oldFont, newFont)) { + invokeStatement(oldInstance, "setFont", new Object[] { oldFont }, out); } } @@ -1104,26 +1110,30 @@ class java_awt_List_PersistenceDelegate extends DefaultPersistenceDelegate { // BorderLayout class java_awt_BorderLayout_PersistenceDelegate extends DefaultPersistenceDelegate { + private static final String[] CONSTRAINTS = { + BorderLayout.NORTH, + BorderLayout.SOUTH, + BorderLayout.EAST, + BorderLayout.WEST, + BorderLayout.CENTER, + BorderLayout.PAGE_START, + BorderLayout.PAGE_END, + BorderLayout.LINE_START, + BorderLayout.LINE_END, + }; + @Override protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { super.initialize(type, oldInstance, newInstance, out); - String[] locations = {"north", "south", "east", "west", "center"}; - String[] names = {java.awt.BorderLayout.NORTH, java.awt.BorderLayout.SOUTH, - java.awt.BorderLayout.EAST, java.awt.BorderLayout.WEST, - java.awt.BorderLayout.CENTER}; - for(int i = 0; i < locations.length; i++) { - Object oldC = ReflectionUtils.getPrivateField(oldInstance, - java.awt.BorderLayout.class, - locations[i], - out.getExceptionListener()); - Object newC = ReflectionUtils.getPrivateField(newInstance, - java.awt.BorderLayout.class, - locations[i], - out.getExceptionListener()); + BorderLayout oldLayout = (BorderLayout) oldInstance; + BorderLayout newLayout = (BorderLayout) newInstance; + for (String constraints : CONSTRAINTS) { + Object oldC = oldLayout.getLayoutComponent(constraints); + Object newC = newLayout.getLayoutComponent(constraints); // Pending, assume any existing elements are OK. if (oldC != null && newC == null) { invokeStatement(oldInstance, "addLayoutComponent", - new Object[]{oldC, names[i]}, out); + new Object[] { oldC, constraints }, out); } } } diff --git a/src/share/classes/java/beans/PropertyChangeSupport.java b/src/share/classes/java/beans/PropertyChangeSupport.java index 2d4ed88fdb32cf45dda35e1d3584fabcefde2767..04b510ae2caf836c8631be530163e9684c30ca08 100644 --- a/src/share/classes/java/beans/PropertyChangeSupport.java +++ b/src/share/classes/java/beans/PropertyChangeSupport.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 @@ -34,12 +34,49 @@ import java.util.Map.Entry; /** * This is a utility class that can be used by beans that support bound - * properties. You can use an instance of this class as a member field - * of your bean and delegate various work to it. + * properties. It manages a list of listeners and dispatches + * {@link PropertyChangeEvent}s to them. You can use an instance of this class + * as a member field of your bean and delegate these types of work to it. + * The {@link PropertyChangeListener} can be registered for all properties + * or for a property specified by name. + *

    + * Here is an example of {@code PropertyChangeSupport} usage that follows + * the rules and recommendations laid out in the JavaBeans™ specification: + *

    + * public class MyBean {
    + *     private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
      *
    + *     public void addPropertyChangeListener(PropertyChangeListener listener) {
    + *         this.pcs.addPropertyChangeListener(listener);
    + *     }
    + *
    + *     public void removePropertyChangeListener(PropertyChangeListener listener) {
    + *         this.pcs.removePropertyChangeListener(listener);
    + *     }
    + *
    + *     private String value;
    + *
    + *     public String getValue() {
    + *         return this.value;
    + *     }
    + *
    + *     public void setValue(String newValue) {
    + *         String oldValue = this.value;
    + *         this.value = newValue;
    + *         this.pcs.firePropertyChange("value", oldValue, newValue);
    + *     }
    + *
    + *     [...]
    + * }
    + * 
    + *

    + * A {@code PropertyChangeSupport} instance is thread-safe. + *

    * This class is serializable. When it is serialized it will save * (and restore) any listeners that are themselves serializable. Any * non-serializable listeners will be skipped during serialization. + * + * @see VetoableChangeSupport */ public class PropertyChangeSupport implements Serializable { private PropertyChangeListenerMap map = new PropertyChangeListenerMap(); @@ -208,91 +245,91 @@ public class PropertyChangeSupport implements Serializable { } /** - * Report a bound property update to any registered listeners. - * No event is fired if old and new are equal and non-null. - * + * Reports a bound property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * No event is fired if old and new values are equal and non-null. *

    * This is merely a convenience wrapper around the more general - * firePropertyChange method that takes {@code - * PropertyChangeEvent} value. + * {@link #firePropertyChange(PropertyChangeEvent)} method. * - * @param propertyName The programmatic name of the property - * that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property */ - public void firePropertyChange(String propertyName, - Object oldValue, Object newValue) { - if (oldValue != null && newValue != null && oldValue.equals(newValue)) { - return; + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { + firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue)); } - firePropertyChange(new PropertyChangeEvent(source, propertyName, - oldValue, newValue)); } /** - * Report an int bound property update to any registered listeners. - * No event is fired if old and new are equal. + * Reports an integer bound property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * firePropertyChange method that takes Object values. + * {@link #firePropertyChange(String, Object, Object)} method. * - * @param propertyName The programmatic name of the property - * that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property */ - public void firePropertyChange(String propertyName, - int oldValue, int newValue) { - if (oldValue == newValue) { - return; + public void firePropertyChange(String propertyName, int oldValue, int newValue) { + if (oldValue != newValue) { + firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue)); } - firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue)); } /** - * Report a boolean bound property update to any registered listeners. - * No event is fired if old and new are equal. + * Reports a boolean bound property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * firePropertyChange method that takes Object values. + * {@link #firePropertyChange(String, Object, Object)} method. * - * @param propertyName The programmatic name of the property - * that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property */ - public void firePropertyChange(String propertyName, - boolean oldValue, boolean newValue) { - if (oldValue == newValue) { - return; + public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + if (oldValue != newValue) { + firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } - firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } /** - * Fire an existing PropertyChangeEvent to any registered listeners. - * No event is fired if the given event's old and new values are - * equal and non-null. - * @param evt The PropertyChangeEvent object. + * Fires a property change event to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * No event is fired if the given event's old and new values are equal and non-null. + * + * @param event the {@code PropertyChangeEvent} to be fired */ - public void firePropertyChange(PropertyChangeEvent evt) { - Object oldValue = evt.getOldValue(); - Object newValue = evt.getNewValue(); - String propertyName = evt.getPropertyName(); - if (oldValue != null && newValue != null && oldValue.equals(newValue)) { - return; - } - PropertyChangeListener[] common = this.map.get(null); - PropertyChangeListener[] named = (propertyName != null) - ? this.map.get(propertyName) - : null; + public void firePropertyChange(PropertyChangeEvent event) { + Object oldValue = event.getOldValue(); + Object newValue = event.getNewValue(); + if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { + String name = event.getPropertyName(); - fire(common, evt); - fire(named, evt); + PropertyChangeListener[] common = this.map.get(null); + PropertyChangeListener[] named = (name != null) + ? this.map.get(name) + : null; + + fire(common, event); + fire(named, event); + } } - private void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) { + private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) { if (listeners != null) { for (PropertyChangeListener listener : listeners) { listener.propertyChange(event); @@ -301,78 +338,69 @@ public class PropertyChangeSupport implements Serializable { } /** - * Report a bound indexed property update to any registered - * listeners. + * Reports a bound indexed property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. *

    - * No event is fired if old and new values are equal - * and non-null. - * + * No event is fired if old and new values are equal and non-null. *

    * This is merely a convenience wrapper around the more general - * firePropertyChange method that takes {@code PropertyChangeEvent} value. + * {@link #firePropertyChange(PropertyChangeEvent)} method. * - * @param propertyName The programmatic name of the property that - * was changed. - * @param index index of the property element that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param index the index of the property element that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property * @since 1.5 */ - public void fireIndexedPropertyChange(String propertyName, int index, - Object oldValue, Object newValue) { - firePropertyChange(new IndexedPropertyChangeEvent - (source, propertyName, oldValue, newValue, index)); + public void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue) { + if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { + firePropertyChange(new IndexedPropertyChangeEvent(source, propertyName, oldValue, newValue, index)); + } } /** - * Report an int bound indexed property update to any registered - * listeners. + * Reports an integer bound indexed property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. *

    * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * fireIndexedPropertyChange method which takes Object values. + * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method. * - * @param propertyName The programmatic name of the property that - * was changed. - * @param index index of the property element that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param index the index of the property element that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property * @since 1.5 */ - public void fireIndexedPropertyChange(String propertyName, int index, - int oldValue, int newValue) { - if (oldValue == newValue) { - return; + public void fireIndexedPropertyChange(String propertyName, int index, int oldValue, int newValue) { + if (oldValue != newValue) { + fireIndexedPropertyChange(propertyName, index, Integer.valueOf(oldValue), Integer.valueOf(newValue)); } - fireIndexedPropertyChange(propertyName, index, - Integer.valueOf(oldValue), - Integer.valueOf(newValue)); } /** - * Report a boolean bound indexed property update to any - * registered listeners. + * Reports a boolean bound indexed property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. *

    * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * fireIndexedPropertyChange method which takes Object values. + * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method. * - * @param propertyName The programmatic name of the property that - * was changed. - * @param index index of the property element that was changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that was changed + * @param index the index of the property element that was changed + * @param oldValue the old value of the property + * @param newValue the new value of the property * @since 1.5 */ - public void fireIndexedPropertyChange(String propertyName, int index, - boolean oldValue, boolean newValue) { - if (oldValue == newValue) { - return; + public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) { + if (oldValue != newValue) { + fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } - fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), - Boolean.valueOf(newValue)); } /** diff --git a/src/share/classes/java/beans/PropertyEditor.java b/src/share/classes/java/beans/PropertyEditor.java index b6ddf415354603cd69861c3732a85b57f4c1d186..965775898a84899e84254249c98d7e11bcbabdcd 100644 --- a/src/share/classes/java/beans/PropertyEditor.java +++ b/src/share/classes/java/beans/PropertyEditor.java @@ -204,20 +204,21 @@ public interface PropertyEditor { //---------------------------------------------------------------------- /** - * Register a listener for the PropertyChange event. When a - * PropertyEditor changes its value it should fire a PropertyChange - * event on all registered PropertyChangeListeners, specifying the - * null value for the property name and itself as the source. + * Adds a listener for the value change. + * When the property editor changes its value + * it should fire a {@link PropertyChangeEvent} + * on all registered {@link PropertyChangeListener}s, + * specifying the {@code null} value for the property name + * and itself as the source. * - * @param listener An object to be invoked when a PropertyChange - * event is fired. + * @param listener the {@link PropertyChangeListener} to add */ void addPropertyChangeListener(PropertyChangeListener listener); /** - * Remove a listener for the PropertyChange event. + * Removes a listener for the value change. * - * @param listener The PropertyChange listener to be removed. + * @param listener the {@link PropertyChangeListener} to remove */ void removePropertyChangeListener(PropertyChangeListener listener); diff --git a/src/share/classes/java/beans/PropertyEditorManager.java b/src/share/classes/java/beans/PropertyEditorManager.java index 055df1ad98cb2cd25d06ea2fc1dd501751d3b092..a456c2bff54fb479e2f0072ce61b4ff3b40f8264 100644 --- a/src/share/classes/java/beans/PropertyEditorManager.java +++ b/src/share/classes/java/beans/PropertyEditorManager.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 @@ -25,6 +25,7 @@ package java.beans; +import com.sun.beans.WeakCache; import sun.beans.editors.*; /** @@ -55,32 +56,30 @@ import sun.beans.editors.*; public class PropertyEditorManager { /** - * Register an editor class to be used to edit values of - * a given target class. + * Registers an editor class to edit values of the given target class. + * If the editor class is {@code null}, + * then any existing definition will be removed. + * Thus this method can be used to cancel the registration. + * The registration is canceled automatically + * if either the target or editor class is unloaded. + *

    + * If there is a security manager, its {@code checkPropertiesAccess} + * method is called. This could result in a {@linkplain SecurityException}. * - *

    First, if there is a security manager, its checkPropertiesAccess - * method is called. This could result in a SecurityException. + * @param targetType the class object of the type to be edited + * @param editorClass the class object of the editor class + * @throws SecurityException if a security manager exists and + * its {@code checkPropertiesAccess} method + * doesn't allow setting of system properties * - * @param targetType the Class object of the type to be edited - * @param editorClass the Class object of the editor class. If - * this is null, then any existing definition will be removed. - * @exception SecurityException if a security manager exists and its - * checkPropertiesAccess method doesn't allow setting - * of system properties. * @see SecurityManager#checkPropertiesAccess */ - - public static void registerEditor(Class targetType, Class editorClass) { + public static synchronized void registerEditor(Class targetType, Class editorClass) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } - initialize(); - if (editorClass == null) { - registry.remove(targetType); - } else { - registry.put(targetType, editorClass); - } + registry.put(targetType, editorClass); } /** @@ -90,10 +89,8 @@ public class PropertyEditorManager { * @return An editor object for the given target class. * The result is null if no suitable editor can be found. */ - public static synchronized PropertyEditor findEditor(Class targetType) { - initialize(); - Class editorClass = (Class)registry.get(targetType); + Class editorClass = registry.get(targetType); if (editorClass != null) { try { Object o = editorClass.newInstance(); @@ -143,10 +140,7 @@ public class PropertyEditorManager { * e.g. Sun implementation initially sets to {"sun.beans.editors"}. */ public static synchronized String[] getEditorSearchPath() { - // Return a copy of the searchPath. - String result[] = new String[searchPath.length]; - System.arraycopy(searchPath, 0, result, 0, searchPath.length); - return result; + return searchPath.clone(); } /** @@ -162,23 +156,22 @@ public class PropertyEditorManager { * of system properties. * @see SecurityManager#checkPropertiesAccess */ - - public static synchronized void setEditorSearchPath(String path[]) { + public static synchronized void setEditorSearchPath(String[] path) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } - if (path == null) { - path = new String[0]; - } - searchPath = path; + searchPath = (path != null) + ? path.clone() + : EMPTY; } - private static synchronized void initialize() { - if (registry != null) { - return; - } - registry = new java.util.Hashtable(); + private static String[] searchPath = { "sun.beans.editors" }; + private static final String[] EMPTY = {}; + private static final WeakCache, Class> registry; + + static { + registry = new WeakCache, Class>(); registry.put(Byte.TYPE, ByteEditor.class); registry.put(Short.TYPE, ShortEditor.class); registry.put(Integer.TYPE, IntegerEditor.class); @@ -187,7 +180,4 @@ public class PropertyEditorManager { registry.put(Float.TYPE, FloatEditor.class); registry.put(Double.TYPE, DoubleEditor.class); } - - private static String[] searchPath = { "sun.beans.editors" }; - private static java.util.Hashtable registry; } diff --git a/src/share/classes/java/beans/PropertyEditorSupport.java b/src/share/classes/java/beans/PropertyEditorSupport.java index 12f07c06bb187994e3d383b166fc03141fe642bc..57fddf04365bd6762ead6fd9c89307a8dab020cf 100644 --- a/src/share/classes/java/beans/PropertyEditorSupport.java +++ b/src/share/classes/java/beans/PropertyEditorSupport.java @@ -233,11 +233,20 @@ public class PropertyEditorSupport implements PropertyEditor { //---------------------------------------------------------------------- /** - * Register a listener for the PropertyChange event. The class will - * fire a PropertyChange value whenever the value is updated. + * Adds a listener for the value change. + * When the property editor changes its value + * it should fire a {@link PropertyChangeEvent} + * on all registered {@link PropertyChangeListener}s, + * specifying the {@code null} value for the property name. + * If the source property is set, + * it should be used as the source of the event. + *

    + * The same listener object may be added more than once, + * and will be called as many times as it is added. + * If {@code listener} is {@code null}, + * no exception is thrown and no action is taken. * - * @param listener An object to be invoked when a PropertyChange - * event is fired. + * @param listener the {@link PropertyChangeListener} to add */ public synchronized void addPropertyChangeListener( PropertyChangeListener listener) { @@ -248,9 +257,14 @@ public class PropertyEditorSupport implements PropertyEditor { } /** - * Remove a listener for the PropertyChange event. + * Removes a listener for the value change. + *

    + * If the same listener was added more than once, + * it will be notified one less time after being removed. + * If {@code listener} is {@code null}, or was never added, + * no exception is thrown and no action is taken. * - * @param listener The PropertyChange listener to be removed. + * @param listener the {@link PropertyChangeListener} to remove */ public synchronized void removePropertyChangeListener( PropertyChangeListener listener) { diff --git a/src/share/classes/java/beans/VetoableChangeSupport.java b/src/share/classes/java/beans/VetoableChangeSupport.java index 7d1418e17d2ab1a6713a28a4d037b410f8d293d3..addf68b36cdc101e152bb56addb65606c1bbedae 100644 --- a/src/share/classes/java/beans/VetoableChangeSupport.java +++ b/src/share/classes/java/beans/VetoableChangeSupport.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 @@ -34,12 +34,49 @@ import java.util.Map.Entry; /** * This is a utility class that can be used by beans that support constrained - * properties. You can use an instance of this class as a member field - * of your bean and delegate various work to it. + * properties. It manages a list of listeners and dispatches + * {@link PropertyChangeEvent}s to them. You can use an instance of this class + * as a member field of your bean and delegate these types of work to it. + * The {@link VetoableChangeListener} can be registered for all properties + * or for a property specified by name. + *

    + * Here is an example of {@code VetoableChangeSupport} usage that follows + * the rules and recommendations laid out in the JavaBeans™ specification: + *

    + * public class MyBean {
    + *     private final VetoableChangeSupport vcs = new VetoableChangeSupport(this);
      *
    + *     public void addVetoableChangeListener(VetoableChangeListener listener) {
    + *         this.vcs.addVetoableChangeListener(listener);
    + *     }
    + *
    + *     public void removeVetoableChangeListener(VetoableChangeListener listener) {
    + *         this.vcs.removeVetoableChangeListener(listener);
    + *     }
    + *
    + *     private String value;
    + *
    + *     public String getValue() {
    + *         return this.value;
    + *     }
    + *
    + *     public void setValue(String newValue) throws PropertyVetoException {
    + *         String oldValue = this.value;
    + *         this.vcs.fireVetoableChange("value", oldValue, newValue);
    + *         this.value = newValue;
    + *     }
    + *
    + *     [...]
    + * }
    + * 
    + *

    + * A {@code VetoableChangeSupport} instance is thread-safe. + *

    * This class is serializable. When it is serialized it will save * (and restore) any listeners that are themselves serializable. Any * non-serializable listeners will be skipped during serialization. + * + * @see PropertyChangeSupport */ public class VetoableChangeSupport implements Serializable { private VetoableChangeListenerMap map = new VetoableChangeListenerMap(); @@ -208,126 +245,149 @@ public class VetoableChangeSupport implements Serializable { } /** - * Report a vetoable property update to any registered listeners. If - * anyone vetos the change, then fire a new event reverting everyone to - * the old value and then rethrow the PropertyVetoException. + * Reports a constrained property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * Any listener can throw a {@code PropertyVetoException} to veto the update. + * If one of the listeners vetoes the update, this method passes + * a new "undo" {@code PropertyChangeEvent} that reverts to the old value + * to all listeners that already confirmed this update + * and throws the {@code PropertyVetoException} again. *

    - * No event is fired if old and new are equal and non-null. + * No event is fired if old and new values are equal and non-null. + *

    + * This is merely a convenience wrapper around the more general + * {@link #fireVetoableChange(PropertyChangeEvent)} method. * - * @param propertyName The programmatic name of the property - * that is about to change.. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. - * @exception PropertyVetoException if the recipient wishes the property - * change to be rolled back. + * @param propertyName the programmatic name of the property that is about to change + * @param oldValue the old value of the property + * @param newValue the new value of the property + * @throws PropertyVetoException if one of listeners vetoes the property update */ - public void fireVetoableChange(String propertyName, - Object oldValue, Object newValue) - throws PropertyVetoException { - if (oldValue != null && newValue != null && oldValue.equals(newValue)) { - return; + public void fireVetoableChange(String propertyName, Object oldValue, Object newValue) + throws PropertyVetoException { + if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { + fireVetoableChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue)); } - PropertyChangeEvent evt = new PropertyChangeEvent(source, propertyName, - oldValue, newValue); - fireVetoableChange(evt); } /** - * Report a int vetoable property update to any registered listeners. - * No event is fired if old and new are equal. + * Reports an integer constrained property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * Any listener can throw a {@code PropertyVetoException} to veto the update. + * If one of the listeners vetoes the update, this method passes + * a new "undo" {@code PropertyChangeEvent} that reverts to the old value + * to all listeners that already confirmed this update + * and throws the {@code PropertyVetoException} again. + *

    + * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * fireVetoableChange method that takes Object values. + * {@link #fireVetoableChange(String, Object, Object)} method. * - * @param propertyName The programmatic name of the property - * that is about to change. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that is about to change + * @param oldValue the old value of the property + * @param newValue the new value of the property + * @throws PropertyVetoException if one of listeners vetoes the property update */ - public void fireVetoableChange(String propertyName, - int oldValue, int newValue) - throws PropertyVetoException { - if (oldValue == newValue) { - return; + public void fireVetoableChange(String propertyName, int oldValue, int newValue) + throws PropertyVetoException { + if (oldValue != newValue) { + fireVetoableChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue)); } - fireVetoableChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue)); } /** - * Report a boolean vetoable property update to any registered listeners. - * No event is fired if old and new are equal. + * Reports a boolean constrained property update to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * Any listener can throw a {@code PropertyVetoException} to veto the update. + * If one of the listeners vetoes the update, this method passes + * a new "undo" {@code PropertyChangeEvent} that reverts to the old value + * to all listeners that already confirmed this update + * and throws the {@code PropertyVetoException} again. + *

    + * No event is fired if old and new values are equal. *

    * This is merely a convenience wrapper around the more general - * fireVetoableChange method that takes Object values. + * {@link #fireVetoableChange(String, Object, Object)} method. * - * @param propertyName The programmatic name of the property - * that is about to change. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the programmatic name of the property that is about to change + * @param oldValue the old value of the property + * @param newValue the new value of the property + * @throws PropertyVetoException if one of listeners vetoes the property update */ - public void fireVetoableChange(String propertyName, - boolean oldValue, boolean newValue) - throws PropertyVetoException { - if (oldValue == newValue) { - return; + public void fireVetoableChange(String propertyName, boolean oldValue, boolean newValue) + throws PropertyVetoException { + if (oldValue != newValue) { + fireVetoableChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } - fireVetoableChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } /** - * Fire a vetoable property update to any registered listeners. If - * anyone vetos the change, then fire a new event reverting everyone to - * the old value and then rethrow the PropertyVetoException. + * Fires a property change event to listeners + * that have been registered to track updates of + * all properties or a property with the specified name. + *

    + * Any listener can throw a {@code PropertyVetoException} to veto the update. + * If one of the listeners vetoes the update, this method passes + * a new "undo" {@code PropertyChangeEvent} that reverts to the old value + * to all listeners that already confirmed this update + * and throws the {@code PropertyVetoException} again. *

    - * No event is fired if old and new are equal and non-null. + * No event is fired if the given event's old and new values are equal and non-null. * - * @param evt The PropertyChangeEvent to be fired. - * @exception PropertyVetoException if the recipient wishes the property - * change to be rolled back. + * @param event the {@code PropertyChangeEvent} to be fired + * @throws PropertyVetoException if one of listeners vetoes the property update */ - public void fireVetoableChange(PropertyChangeEvent evt) - throws PropertyVetoException { + public void fireVetoableChange(PropertyChangeEvent event) + throws PropertyVetoException { + Object oldValue = event.getOldValue(); + Object newValue = event.getNewValue(); + if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { + String name = event.getPropertyName(); - Object oldValue = evt.getOldValue(); - Object newValue = evt.getNewValue(); - String propertyName = evt.getPropertyName(); - if (oldValue != null && newValue != null && oldValue.equals(newValue)) { - return; - } - VetoableChangeListener[] common = this.map.get(null); - VetoableChangeListener[] named = (propertyName != null) - ? this.map.get(propertyName) - : null; - fire(common, evt); - fire(named, evt); - } + VetoableChangeListener[] common = this.map.get(null); + VetoableChangeListener[] named = (name != null) + ? this.map.get(name) + : null; - private void fire(VetoableChangeListener[] listeners, PropertyChangeEvent event) throws PropertyVetoException { - if (listeners != null) { - VetoableChangeListener current = null; - try { - for (VetoableChangeListener listener : listeners) { - current = listener; - listener.vetoableChange(event); - } - } catch (PropertyVetoException veto) { - // Create an event to revert everyone to the old value. - event = new PropertyChangeEvent( this.source, - event.getPropertyName(), - event.getNewValue(), - event.getOldValue() ); - for (VetoableChangeListener listener : listeners) { - if (current == listener) { - break; + VetoableChangeListener[] listeners; + if (common == null) { + listeners = named; + } + else if (named == null) { + listeners = common; + } + else { + listeners = new VetoableChangeListener[common.length + named.length]; + System.arraycopy(common, 0, listeners, 0, common.length); + System.arraycopy(named, 0, listeners, common.length, named.length); + } + if (listeners != null) { + int current = 0; + try { + while (current < listeners.length) { + listeners[current].vetoableChange(event); + current++; } - try { - listener.vetoableChange(event); - } catch (PropertyVetoException ex) { - // We just ignore exceptions that occur during reversions. + } + catch (PropertyVetoException veto) { + event = new PropertyChangeEvent(this.source, name, newValue, oldValue); + for (int i = 0; i < current; i++) { + try { + listeners[i].vetoableChange(event); + } + catch (PropertyVetoException exception) { + // ignore exceptions that occur during rolling back + } } + throw veto; // rethrow the veto exception } - // And now rethrow the PropertyVetoException. - throw veto; } } } diff --git a/src/share/classes/java/io/CharConversionException.java b/src/share/classes/java/io/CharConversionException.java index 9e4b0ad0a33694a8c3edc882d7498fb3e95f412d..d3a79e80ff2cf4b4ca89b3e0d80b889ded5595d9 100644 --- a/src/share/classes/java/io/CharConversionException.java +++ b/src/share/classes/java/io/CharConversionException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1999 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 @@ -33,6 +33,8 @@ package java.io; public class CharConversionException extends java.io.IOException { + private static final long serialVersionUID = -8680016352018427031L; + /** * This provides no detailed message. */ diff --git a/src/share/classes/java/io/EOFException.java b/src/share/classes/java/io/EOFException.java index d91ecf627c3e86f70d763242ca7085106cf61f9b..6094837f599ba9882243f20183989c3e899092e9 100644 --- a/src/share/classes/java/io/EOFException.java +++ b/src/share/classes/java/io/EOFException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2000 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 @@ -41,6 +41,8 @@ package java.io; */ public class EOFException extends IOException { + private static final long serialVersionUID = 6433858223774886977L; + /** * Constructs an EOFException with null * as its error detail message. diff --git a/src/share/classes/java/io/FileNotFoundException.java b/src/share/classes/java/io/FileNotFoundException.java index 18ed3f18cb24c76c0b33f236cc8e19982967f6d7..198bbba8166ce0f26b3c11fe056d651c7da1d2ed 100644 --- a/src/share/classes/java/io/FileNotFoundException.java +++ b/src/share/classes/java/io/FileNotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1999 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 @@ -41,6 +41,7 @@ package java.io; */ public class FileNotFoundException extends IOException { + private static final long serialVersionUID = -897856973823710492L; /** * Constructs a FileNotFoundException with diff --git a/src/share/classes/java/io/InterruptedIOException.java b/src/share/classes/java/io/InterruptedIOException.java index 41cedf6b87a26407a160edd66bbbca8e94997ad7..054fe2bb1339686ec11bdac76912356cd5d5b276 100644 --- a/src/share/classes/java/io/InterruptedIOException.java +++ b/src/share/classes/java/io/InterruptedIOException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2000 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 @@ -41,6 +41,8 @@ package java.io; */ public class InterruptedIOException extends IOException { + private static final long serialVersionUID = 4020568460727500567L; + /** * Constructs an InterruptedIOException with * null as its error detail message. diff --git a/src/share/classes/java/io/SyncFailedException.java b/src/share/classes/java/io/SyncFailedException.java index b2583ad2bdc68dc19ffcfdd76a3abbd9dd6ea6ba..b08c8d97dbfae86eabc3842ca1b3efde3ecfd913 100644 --- a/src/share/classes/java/io/SyncFailedException.java +++ b/src/share/classes/java/io/SyncFailedException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1999 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 @@ -34,6 +34,8 @@ package java.io; * @since JDK1.1 */ public class SyncFailedException extends IOException { + private static final long serialVersionUID = -2353342684412443330L; + /** * Constructs an SyncFailedException with a detail message. * A detail message is a String that describes this particular exception. diff --git a/src/share/classes/java/io/UTFDataFormatException.java b/src/share/classes/java/io/UTFDataFormatException.java index bb89c16452102216c8e74e4eda067716b8d6ed34..2f789a0192fa2d2b3af26c8296d79432881a5d1b 100644 --- a/src/share/classes/java/io/UTFDataFormatException.java +++ b/src/share/classes/java/io/UTFDataFormatException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2004 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 @@ -44,6 +44,8 @@ package java.io; */ public class UTFDataFormatException extends IOException { + private static final long serialVersionUID = 420743449228280612L; + /** * Constructs a UTFDataFormatException with * null as its error detail message. diff --git a/src/share/classes/java/io/UnsupportedEncodingException.java b/src/share/classes/java/io/UnsupportedEncodingException.java index 2ee9cb647be61414006e87ba1db606c5f28bdc47..9ccdd2ee603928bcd56d283563dbfffb54ba133a 100644 --- a/src/share/classes/java/io/UnsupportedEncodingException.java +++ b/src/share/classes/java/io/UnsupportedEncodingException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1999 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 @@ -33,6 +33,8 @@ package java.io; public class UnsupportedEncodingException extends IOException { + private static final long serialVersionUID = -4274276298326136670L; + /** * Constructs an UnsupportedEncodingException without a detail message. */ diff --git a/src/share/classes/java/lang/AbstractMethodError.java b/src/share/classes/java/lang/AbstractMethodError.java index 15dcb96a78f549eebca43e1dea87db9fd532f1bb..a8f11e7abc94081d4f6e471a739afec3fcd88cf2 100644 --- a/src/share/classes/java/lang/AbstractMethodError.java +++ b/src/share/classes/java/lang/AbstractMethodError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2005 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 @@ -37,6 +37,8 @@ package java.lang; */ public class AbstractMethodError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -1654391082989018462L; + /** * Constructs an AbstractMethodError with no detail message. */ 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/ArithmeticException.java b/src/share/classes/java/lang/ArithmeticException.java index a90cda11c9e9539bb0dc4fb39f769382e06c45c5..a51d95db821f04def926adde8351a0415b49f80c 100644 --- a/src/share/classes/java/lang/ArithmeticException.java +++ b/src/share/classes/java/lang/ArithmeticException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class ArithmeticException extends RuntimeException { + private static final long serialVersionUID = 2256477558314496007L; + /** * Constructs an ArithmeticException with no detail * message. diff --git a/src/share/classes/java/lang/ArrayIndexOutOfBoundsException.java b/src/share/classes/java/lang/ArrayIndexOutOfBoundsException.java index 5c96020bf44ef0d574853add68515df956e20b05..cc51bdd043b2180264e4648c3c6f23d0f31b0e64 100644 --- a/src/share/classes/java/lang/ArrayIndexOutOfBoundsException.java +++ b/src/share/classes/java/lang/ArrayIndexOutOfBoundsException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { + private static final long serialVersionUID = -5116101128118950844L; + /** * Constructs an ArrayIndexOutOfBoundsException with no * detail message. diff --git a/src/share/classes/java/lang/ArrayStoreException.java b/src/share/classes/java/lang/ArrayStoreException.java index 9aa4f7a98741294667e6517e710e1015865b8746..af24f1ac2f62de53d95d5e80e53be95fb03eb459 100644 --- a/src/share/classes/java/lang/ArrayStoreException.java +++ b/src/share/classes/java/lang/ArrayStoreException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -39,6 +39,8 @@ package java.lang; */ public class ArrayStoreException extends RuntimeException { + private static final long serialVersionUID = -4522193890499838241L; + /** * Constructs an ArrayStoreException with no detail message. */ diff --git a/src/share/classes/java/lang/AssertionError.java b/src/share/classes/java/lang/AssertionError.java index 0e6e45c210bfcb9d16473b9579f1d8d3384cf14e..b64b7cbae3d099da7c556a6b08365f320058c177 100644 --- a/src/share/classes/java/lang/AssertionError.java +++ b/src/share/classes/java/lang/AssertionError.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 @@ -43,6 +43,8 @@ package java.lang; * @since 1.4 */ public class AssertionError extends Error { + private static final long serialVersionUID = -5013299493970297370L; + /** * Constructs an AssertionError with no detail message. */ diff --git a/src/share/classes/java/lang/ClassCastException.java b/src/share/classes/java/lang/ClassCastException.java index 057b55bb5e3d90054e286bacf092c1ea09aed1be..310c87f94d96cb0d302e03f628ac9e26d9821505 100644 --- a/src/share/classes/java/lang/ClassCastException.java +++ b/src/share/classes/java/lang/ClassCastException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -39,6 +39,8 @@ package java.lang; */ public class ClassCastException extends RuntimeException { + private static final long serialVersionUID = -9223365651070458532L; + /** * Constructs a ClassCastException with no detail message. */ diff --git a/src/share/classes/java/lang/ClassCircularityError.java b/src/share/classes/java/lang/ClassCircularityError.java index 5d522626d305efdd7bf8d684581fb91408529ede..27d5dfbf08cdd6fd4caa3b3c7ea1a54c8dde5cd2 100644 --- a/src/share/classes/java/lang/ClassCircularityError.java +++ b/src/share/classes/java/lang/ClassCircularityError.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 @@ -33,6 +33,8 @@ package java.lang; * @since JDK1.0 */ public class ClassCircularityError extends LinkageError { + private static final long serialVersionUID = 1054362542914539689L; + /** * Constructs a {@code ClassCircularityError} with no detail message. */ diff --git a/src/share/classes/java/lang/ClassFormatError.java b/src/share/classes/java/lang/ClassFormatError.java index d2e61a4e290d41a0dfe09c8ccaac7bd0b18db024..75a042118be69b5e15f96309acabe213d495d538 100644 --- a/src/share/classes/java/lang/ClassFormatError.java +++ b/src/share/classes/java/lang/ClassFormatError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class ClassFormatError extends LinkageError { + private static final long serialVersionUID = -8420114879011949195L; + /** * Constructs a ClassFormatError with no detail message. */ diff --git a/src/share/classes/java/lang/CloneNotSupportedException.java b/src/share/classes/java/lang/CloneNotSupportedException.java index d3b7b3373dc424cff5ba782eb1f963df99065917..cfa643fc4757bd3f84fae7d7f90bbbd41b8ded50 100644 --- a/src/share/classes/java/lang/CloneNotSupportedException.java +++ b/src/share/classes/java/lang/CloneNotSupportedException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -43,6 +43,8 @@ package java.lang; public class CloneNotSupportedException extends Exception { + private static final long serialVersionUID = 5195511250079656443L; + /** * Constructs a CloneNotSupportedException with no * detail message. diff --git a/src/share/classes/java/lang/EnumConstantNotPresentException.java b/src/share/classes/java/lang/EnumConstantNotPresentException.java index c09a9129656643eaaa5cce3a05a93f2f469531ae..4807691b2106ede61d0e0403e9213d6aed944cee 100644 --- a/src/share/classes/java/lang/EnumConstantNotPresentException.java +++ b/src/share/classes/java/lang/EnumConstantNotPresentException.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,6 +33,8 @@ package java.lang; * @since 1.5 */ public class EnumConstantNotPresentException extends RuntimeException { + private static final long serialVersionUID = -6046998521960521108L; + /** * The type of the missing enum constant. */ diff --git a/src/share/classes/java/lang/IllegalAccessError.java b/src/share/classes/java/lang/IllegalAccessError.java index 58812dbffecb401b3e2ad3d379bcbf9d00fc82de..959c94219138c901c85a27255c8712d47f9bc364 100644 --- a/src/share/classes/java/lang/IllegalAccessError.java +++ b/src/share/classes/java/lang/IllegalAccessError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -37,6 +37,8 @@ package java.lang; * @since JDK1.0 */ public class IllegalAccessError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -8988904074992417891L; + /** * Constructs an IllegalAccessError with no detail message. */ diff --git a/src/share/classes/java/lang/IllegalAccessException.java b/src/share/classes/java/lang/IllegalAccessException.java index 8f3ca86772500984caf6edb7d367c2775d69a325..19b51b90fef6afff74a15cd14427d798887ce9b7 100644 --- a/src/share/classes/java/lang/IllegalAccessException.java +++ b/src/share/classes/java/lang/IllegalAccessException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2000 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 @@ -57,6 +57,8 @@ package java.lang; * @since JDK1.0 */ public class IllegalAccessException extends Exception { + private static final long serialVersionUID = 6616958222490762034L; + /** * Constructs an IllegalAccessException without a * detail message. diff --git a/src/share/classes/java/lang/IllegalMonitorStateException.java b/src/share/classes/java/lang/IllegalMonitorStateException.java index b719afa0fce6733f90fa302dad801b3bdaf71ca5..6375a10b2c617e09e6ab214c1a50ad21f8667acd 100644 --- a/src/share/classes/java/lang/IllegalMonitorStateException.java +++ b/src/share/classes/java/lang/IllegalMonitorStateException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -40,6 +40,8 @@ package java.lang; */ public class IllegalMonitorStateException extends RuntimeException { + private static final long serialVersionUID = 3713306369498869069L; + /** * Constructs an IllegalMonitorStateException with no * detail message. diff --git a/src/share/classes/java/lang/IllegalThreadStateException.java b/src/share/classes/java/lang/IllegalThreadStateException.java index 7f76da0dd0b2c194352e2093df08b03ae551b7ef..56ced227adb3bc043dfd0344639e2233004af778 100644 --- a/src/share/classes/java/lang/IllegalThreadStateException.java +++ b/src/share/classes/java/lang/IllegalThreadStateException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -37,6 +37,8 @@ package java.lang; * @since JDK1.0 */ public class IllegalThreadStateException extends IllegalArgumentException { + private static final long serialVersionUID = -7626246362397460174L; + /** * Constructs an IllegalThreadStateException with no * detail message. diff --git a/src/share/classes/java/lang/IncompatibleClassChangeError.java b/src/share/classes/java/lang/IncompatibleClassChangeError.java index a2688c0c10174222c45e95408d3e2ec322ab79f3..a92a18b7a79c16c6fcb77b4ddcbf3c42fab23e4b 100644 --- a/src/share/classes/java/lang/IncompatibleClassChangeError.java +++ b/src/share/classes/java/lang/IncompatibleClassChangeError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class IncompatibleClassChangeError extends LinkageError { + private static final long serialVersionUID = -4914975503642802119L; + /** * Constructs an IncompatibleClassChangeError with no * detail message. diff --git a/src/share/classes/java/lang/IndexOutOfBoundsException.java b/src/share/classes/java/lang/IndexOutOfBoundsException.java index 72a8b67f0e0580ee6c4e0c1b71b41a96c6b0da6e..1375204df70e81cda6e5f9195310369b89b9e311 100644 --- a/src/share/classes/java/lang/IndexOutOfBoundsException.java +++ b/src/share/classes/java/lang/IndexOutOfBoundsException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -36,6 +36,8 @@ package java.lang; */ public class IndexOutOfBoundsException extends RuntimeException { + private static final long serialVersionUID = 234122996006267687L; + /** * Constructs an IndexOutOfBoundsException with no * detail message. diff --git a/src/share/classes/java/lang/InstantiationError.java b/src/share/classes/java/lang/InstantiationError.java index 4824b3d43478af949af48ff509df1e3a06ee72ed..9724fc487221191bb6ea7800c283609732bd0926 100644 --- a/src/share/classes/java/lang/InstantiationError.java +++ b/src/share/classes/java/lang/InstantiationError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -40,6 +40,8 @@ package java.lang; public class InstantiationError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -4885810657349421204L; + /** * Constructs an InstantiationError with no detail message. */ diff --git a/src/share/classes/java/lang/InstantiationException.java b/src/share/classes/java/lang/InstantiationException.java index ab008ab6b9e1788d01e61fa65dfc0a1ce7a644e5..ace382ae437a03ef9affeca21f007d9c11b8c5f8 100644 --- a/src/share/classes/java/lang/InstantiationException.java +++ b/src/share/classes/java/lang/InstantiationException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 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 @@ -44,6 +44,8 @@ package java.lang; */ public class InstantiationException extends Exception { + private static final long serialVersionUID = -8441929162975509110L; + /** * Constructs an {@code InstantiationException} with no detail message. */ diff --git a/src/share/classes/java/lang/InternalError.java b/src/share/classes/java/lang/InternalError.java index d712af5e2bf2f4fd6c192f2011539b9ab20ec679..b49f7d755f4f3baedeba5e6f53aa76a59d43a70f 100644 --- a/src/share/classes/java/lang/InternalError.java +++ b/src/share/classes/java/lang/InternalError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -34,6 +34,8 @@ package java.lang; */ public class InternalError extends VirtualMachineError { + private static final long serialVersionUID = -9062593416125562365L; + /** * Constructs an InternalError with no detail message. */ diff --git a/src/share/classes/java/lang/InterruptedException.java b/src/share/classes/java/lang/InterruptedException.java index d57bb62d52329e4ba2a23a7af58bb5edfdcbcb6b..d8ddd36547ec2617e04214eb7b37e7cf2cab041c 100644 --- a/src/share/classes/java/lang/InterruptedException.java +++ b/src/share/classes/java/lang/InterruptedException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 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 @@ -48,6 +48,8 @@ package java.lang; */ public class InterruptedException extends Exception { + private static final long serialVersionUID = 6700697376100628473L; + /** * Constructs an InterruptedException with no detail message. */ diff --git a/src/share/classes/java/lang/LinkageError.java b/src/share/classes/java/lang/LinkageError.java index 237188f3662f555143bf1c6e8c0c317a688c9820..39d09467814b5b1a1a8690a2b53c8c3281cb49be 100644 --- a/src/share/classes/java/lang/LinkageError.java +++ b/src/share/classes/java/lang/LinkageError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -36,6 +36,8 @@ package java.lang; */ public class LinkageError extends Error { + private static final long serialVersionUID = 3579600108157160122L; + /** * Constructs a LinkageError with no detail message. */ diff --git a/src/share/classes/java/lang/NegativeArraySizeException.java b/src/share/classes/java/lang/NegativeArraySizeException.java index 64b7635461519800c5509db986fdd5e99522cd83..903409b8248c2d3b191405f3e8523c5a8ecbb146 100644 --- a/src/share/classes/java/lang/NegativeArraySizeException.java +++ b/src/share/classes/java/lang/NegativeArraySizeException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -33,6 +33,8 @@ package java.lang; */ public class NegativeArraySizeException extends RuntimeException { + private static final long serialVersionUID = -8960118058596991861L; + /** * Constructs a NegativeArraySizeException with no * detail message. diff --git a/src/share/classes/java/lang/NoClassDefFoundError.java b/src/share/classes/java/lang/NoClassDefFoundError.java index a8a1273e1be950fec68747d47efbcf7432d3114b..c9cf976717ee01588638bfa2ada1a9795c248195 100644 --- a/src/share/classes/java/lang/NoClassDefFoundError.java +++ b/src/share/classes/java/lang/NoClassDefFoundError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2000 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 @@ -40,6 +40,8 @@ package java.lang; */ public class NoClassDefFoundError extends LinkageError { + private static final long serialVersionUID = 9095859863287012458L; + /** * Constructs a NoClassDefFoundError with no detail message. */ diff --git a/src/share/classes/java/lang/NoSuchFieldError.java b/src/share/classes/java/lang/NoSuchFieldError.java index 5dc7f9c1bc627b501d7324418b5a5e2c3acbe9b6..8b77c71b18cffa097abd41017c826cb224b7848e 100644 --- a/src/share/classes/java/lang/NoSuchFieldError.java +++ b/src/share/classes/java/lang/NoSuchFieldError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -38,6 +38,8 @@ package java.lang; */ public class NoSuchFieldError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -3456430195886129035L; + /** * Constructs a NoSuchFieldException with no detail message. */ diff --git a/src/share/classes/java/lang/NoSuchFieldException.java b/src/share/classes/java/lang/NoSuchFieldException.java index c75113a8c09cc64e096efa9d093dbca28f7b4899..b44fb173ebbc95d358798aada5ba62df4e08add1 100644 --- a/src/share/classes/java/lang/NoSuchFieldException.java +++ b/src/share/classes/java/lang/NoSuchFieldException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1999 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 @@ -32,6 +32,8 @@ package java.lang; * @since JDK1.1 */ public class NoSuchFieldException extends Exception { + private static final long serialVersionUID = -6143714805279938260L; + /** * Constructor. */ diff --git a/src/share/classes/java/lang/NoSuchMethodError.java b/src/share/classes/java/lang/NoSuchMethodError.java index 5f3a798144bf8bdf8e2d7ca51e6eeac792fcae53..74de82f3c16912c36048331cc71bf1e85568d17d 100644 --- a/src/share/classes/java/lang/NoSuchMethodError.java +++ b/src/share/classes/java/lang/NoSuchMethodError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1998 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 @@ -39,6 +39,8 @@ package java.lang; */ public class NoSuchMethodError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -3765521442372831335L; + /** * Constructs a NoSuchMethodError with no detail message. */ diff --git a/src/share/classes/java/lang/NoSuchMethodException.java b/src/share/classes/java/lang/NoSuchMethodException.java index 0fc7113ad1cbc856a83df442030437357deda0cf..720fbfcbbc64a144bb4ac4f93ab0742ff77487a3 100644 --- a/src/share/classes/java/lang/NoSuchMethodException.java +++ b/src/share/classes/java/lang/NoSuchMethodException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -33,6 +33,8 @@ package java.lang; */ public class NoSuchMethodException extends Exception { + private static final long serialVersionUID = 5034388446362600923L; + /** * Constructs a NoSuchMethodException without a detail message. */ diff --git a/src/share/classes/java/lang/NullPointerException.java b/src/share/classes/java/lang/NullPointerException.java index 68fef23ac28bf91a58af97924d2441b0b5dcbeb9..15e899cf0c93444a226b92bd77ee5fbc149f0414 100644 --- a/src/share/classes/java/lang/NullPointerException.java +++ b/src/share/classes/java/lang/NullPointerException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -46,6 +46,8 @@ package java.lang; */ public class NullPointerException extends RuntimeException { + private static final long serialVersionUID = 5162710183389028792L; + /** * Constructs a NullPointerException with no detail message. */ diff --git a/src/share/classes/java/lang/OutOfMemoryError.java b/src/share/classes/java/lang/OutOfMemoryError.java index 3ab19d24048001e7e300173a9cc4ad99787d1b47..842b5c60d3f0e15910bb5dd5b45f034c0397e499 100644 --- a/src/share/classes/java/lang/OutOfMemoryError.java +++ b/src/share/classes/java/lang/OutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class OutOfMemoryError extends VirtualMachineError { + private static final long serialVersionUID = 8228564086184010517L; + /** * Constructs an OutOfMemoryError with no detail message. */ diff --git a/src/share/classes/java/lang/StackOverflowError.java b/src/share/classes/java/lang/StackOverflowError.java index 00cd783b4403d17611c36b052c0500ba129aa9a3..992a395f2d7e63d299a9444dfb80ea439c1cfecf 100644 --- a/src/share/classes/java/lang/StackOverflowError.java +++ b/src/share/classes/java/lang/StackOverflowError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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 @@ -34,6 +34,8 @@ package java.lang; */ public class StackOverflowError extends VirtualMachineError { + private static final long serialVersionUID = 8609175038441759607L; + /** * Constructs a StackOverflowError with no detail message. */ 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/StringIndexOutOfBoundsException.java b/src/share/classes/java/lang/StringIndexOutOfBoundsException.java index 35bf7b4c64b6e5ae5a87d30b015f095149f70975..a23862056860abf116b4bd9089c53f1e5cfca49f 100644 --- a/src/share/classes/java/lang/StringIndexOutOfBoundsException.java +++ b/src/share/classes/java/lang/StringIndexOutOfBoundsException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2000 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 @@ -37,6 +37,8 @@ package java.lang; */ public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException { + private static final long serialVersionUID = -6762910422159637258L; + /** * Constructs a StringIndexOutOfBoundsException with no * detail message. 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/ThreadDeath.java b/src/share/classes/java/lang/ThreadDeath.java index 1cab266993ff0d3ed28e6d245181913910a05914..6a3460236747b5027053a09d0d7d9118b082fb0a 100644 --- a/src/share/classes/java/lang/ThreadDeath.java +++ b/src/share/classes/java/lang/ThreadDeath.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 @@ -46,4 +46,6 @@ package java.lang; * @since JDK1.0 */ -public class ThreadDeath extends Error {} +public class ThreadDeath extends Error { + private static final long serialVersionUID = -4417128565033088268L; +} diff --git a/src/share/classes/java/lang/TypeNotPresentException.java b/src/share/classes/java/lang/TypeNotPresentException.java index 445703490827806ddf0eaeb3f514e79a13c06f43..d7fa0d6bdeb7bb0a24a28608e0ea47ff82ce2bd1 100644 --- a/src/share/classes/java/lang/TypeNotPresentException.java +++ b/src/share/classes/java/lang/TypeNotPresentException.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 @@ -40,6 +40,8 @@ package java.lang; * @since 1.5 */ public class TypeNotPresentException extends RuntimeException { + private static final long serialVersionUID = -5101214195716534496L; + private String typeName; /** diff --git a/src/share/classes/java/lang/UnknownError.java b/src/share/classes/java/lang/UnknownError.java index 966b334456935ac6948319a7e6fbf79d2f2cc316..437441d46e0619051f22a43ac9ade4739d0d0850 100644 --- a/src/share/classes/java/lang/UnknownError.java +++ b/src/share/classes/java/lang/UnknownError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -34,6 +34,8 @@ package java.lang; */ public class UnknownError extends VirtualMachineError { + private static final long serialVersionUID = 2524784860676771849L; + /** * Constructs an UnknownError with no detail message. */ diff --git a/src/share/classes/java/lang/UnsatisfiedLinkError.java b/src/share/classes/java/lang/UnsatisfiedLinkError.java index 70426b4eb082ba259d9491587312184cd62eaabc..8ffe6cc73453a09b3c2bb067cb71affbb6d1c442 100644 --- a/src/share/classes/java/lang/UnsatisfiedLinkError.java +++ b/src/share/classes/java/lang/UnsatisfiedLinkError.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1997 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,6 +35,8 @@ package java.lang; */ public class UnsatisfiedLinkError extends LinkageError { + private static final long serialVersionUID = -4019343241616879428L; + /** * Constructs an UnsatisfiedLinkError with no detail message. */ diff --git a/src/share/classes/java/lang/UnsupportedClassVersionError.java b/src/share/classes/java/lang/UnsupportedClassVersionError.java index a36bdb79bfc9a9d5c1855f2c4706fcd9bd0c0132..ec846508f49f9cf6f86f5157ec8bf727c28eb7fc 100644 --- a/src/share/classes/java/lang/UnsupportedClassVersionError.java +++ b/src/share/classes/java/lang/UnsupportedClassVersionError.java @@ -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 @@ -34,6 +34,8 @@ package java.lang; */ public class UnsupportedClassVersionError extends ClassFormatError { + private static final long serialVersionUID = -7123279212883497373L; + /** * Constructs a UnsupportedClassVersionError * with no detail message. diff --git a/src/share/classes/java/lang/VerifyError.java b/src/share/classes/java/lang/VerifyError.java index 46f2b10dcc4711e8daafc8c06a12dac5a10872b1..a24d34bfcbc152ed2b56c2ed640ff28a04f8f956 100644 --- a/src/share/classes/java/lang/VerifyError.java +++ b/src/share/classes/java/lang/VerifyError.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -35,6 +35,8 @@ package java.lang; */ public class VerifyError extends LinkageError { + private static final long serialVersionUID = 7001962396098498785L; + /** * Constructs an VerifyError with no detail message. */ diff --git a/src/share/classes/java/lang/annotation/AnnotationFormatError.java b/src/share/classes/java/lang/annotation/AnnotationFormatError.java index 1ec3d457a725d9b19f5dd74846ade17f0d0830a2..0bc2fd15169b94f52bffebed8a01a8800d5baf10 100644 --- a/src/share/classes/java/lang/annotation/AnnotationFormatError.java +++ b/src/share/classes/java/lang/annotation/AnnotationFormatError.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,6 +33,8 @@ package java.lang.annotation; * @since 1.5 */ public class AnnotationFormatError extends Error { + private static final long serialVersionUID = -4256701562333669892L; + /** * Constructs a new AnnotationFormatError with the specified * detail message. diff --git a/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java b/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java index 3af297dca93b41de070fb0a127f17524080f1b81..c4cb7534c310f8ee025f853820e857df707eaa73 100644 --- a/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java +++ b/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.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 @@ -35,6 +35,8 @@ import java.lang.reflect.Method; * @since 1.5 */ public class AnnotationTypeMismatchException extends RuntimeException { + private static final long serialVersionUID = 8125925355765570191L; + /** * The Method object for the annotation element. */ diff --git a/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java b/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java index abea0ac331b075f997a0c67ff0696cbb1eab42e9..04070a1bbd4a2700522a9834ab04e45b6e187317 100644 --- a/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java +++ b/src/share/classes/java/lang/annotation/IncompleteAnnotationException.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 @@ -35,6 +35,8 @@ package java.lang.annotation; * @since 1.5 */ public class IncompleteAnnotationException extends RuntimeException { + private static final long serialVersionUID = 8445097402741811912L; + private Class annotationType; private String elementName; diff --git a/src/share/classes/java/lang/instrument/IllegalClassFormatException.java b/src/share/classes/java/lang/instrument/IllegalClassFormatException.java index 94c4933e4c0b6221f7ad2dba94c8e3fb88d447fd..5594165fb3e79bef308e08818e56b17a53deecff 100644 --- a/src/share/classes/java/lang/instrument/IllegalClassFormatException.java +++ b/src/share/classes/java/lang/instrument/IllegalClassFormatException.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,6 +40,8 @@ package java.lang.instrument; * @since 1.5 */ public class IllegalClassFormatException extends Exception { + private static final long serialVersionUID = -3841736710924794009L; + /** * Constructs an IllegalClassFormatException with no * detail message. diff --git a/src/share/classes/java/lang/instrument/UnmodifiableClassException.java b/src/share/classes/java/lang/instrument/UnmodifiableClassException.java index 418ad7b3af84eb63730e9f61d91b0e0e2df46c34..d754fb2bbf015afc8ade3b00c1c49438b8fb2ce3 100644 --- a/src/share/classes/java/lang/instrument/UnmodifiableClassException.java +++ b/src/share/classes/java/lang/instrument/UnmodifiableClassException.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 @@ -34,6 +34,8 @@ package java.lang.instrument; * @since 1.5 */ public class UnmodifiableClassException extends Exception { + private static final long serialVersionUID = 1716652643585309178L; + /** * Constructs an UnmodifiableClassException with no * detail message. diff --git a/src/share/classes/java/lang/management/ManagementPermission.java b/src/share/classes/java/lang/management/ManagementPermission.java index 5330e75399bea2797258dce2cbac4c3a63bd9851..7eeadd5c5ece7bcc2ebd80de5d55bcad1a828d10 100644 --- a/src/share/classes/java/lang/management/ManagementPermission.java +++ b/src/share/classes/java/lang/management/ManagementPermission.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 @@ -83,6 +83,7 @@ at the permission allows, and associated risks"> */ public final class ManagementPermission extends java.security.BasicPermission { + private static final long serialVersionUID = 1897496590799378737L; /** * Constructs a ManagementPermission with the specified name. 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/lang/reflect/GenericSignatureFormatError.java b/src/share/classes/java/lang/reflect/GenericSignatureFormatError.java index 6ecdd3b24fdb84ffe50c72c684500c4e0bc68d8d..717bc8bdeb01aaf7ec2b6888dbf339d6e1dfefa1 100644 --- a/src/share/classes/java/lang/reflect/GenericSignatureFormatError.java +++ b/src/share/classes/java/lang/reflect/GenericSignatureFormatError.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,4 +33,6 @@ package java.lang.reflect; * * @since 1.5 */ -public class GenericSignatureFormatError extends ClassFormatError{} +public class GenericSignatureFormatError extends ClassFormatError { + private static final long serialVersionUID = 6709919147137911034L; +} diff --git a/src/share/classes/java/lang/reflect/MalformedParameterizedTypeException.java b/src/share/classes/java/lang/reflect/MalformedParameterizedTypeException.java index 6089687ec2412eba4f711255ed3023d9e9aeca0a..0ed0b399fba1d6774fd7a88a536c110ccb2d2195 100644 --- a/src/share/classes/java/lang/reflect/MalformedParameterizedTypeException.java +++ b/src/share/classes/java/lang/reflect/MalformedParameterizedTypeException.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 @@ -34,4 +34,6 @@ package java.lang.reflect; * * @since 1.5 */ -public class MalformedParameterizedTypeException extends RuntimeException{} +public class MalformedParameterizedTypeException extends RuntimeException { + private static final long serialVersionUID = -5696557788586220964L; +} diff --git a/src/share/classes/java/net/AbstractPlainSocketImpl.java b/src/share/classes/java/net/AbstractPlainSocketImpl.java index 2e5ea31cbd57715b9007835ac66821ec1ff37f00..597783bf730628fcf39cac13680ade28120e4e82 100644 --- a/src/share/classes/java/net/AbstractPlainSocketImpl.java +++ b/src/share/classes/java/net/AbstractPlainSocketImpl.java @@ -308,6 +308,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl FileDescriptor fd = acquireFD(); try { socketConnect(address, port, timeout); + /* socket may have been closed during poll/select */ + synchronized (fdLock) { + if (closePending) { + throw new SocketException ("Socket closed"); + } + } // If we have a ref. to the Socket, then sets the flags // created, bound & connected to true. // This is normally done in Socket.connect() but some diff --git a/src/share/classes/java/net/BindException.java b/src/share/classes/java/net/BindException.java index 9ea95d6f72b95c7e7be8a62686035aec75f42bca..b2975e52d480b9f8727bf8489d902ff8418d8fb3 100644 --- a/src/share/classes/java/net/BindException.java +++ b/src/share/classes/java/net/BindException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1997 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 @@ -34,6 +34,7 @@ package java.net; */ public class BindException extends SocketException { + private static final long serialVersionUID = -5945005768251722951L; /** * Constructs a new BindException with the specified detail diff --git a/src/share/classes/java/net/ConnectException.java b/src/share/classes/java/net/ConnectException.java index 29b46ab66423d57ff8e5cd4385a2c1737f034825..ed97e6b91bbd5f75d3545cc0dfb1452fcd398d3e 100644 --- a/src/share/classes/java/net/ConnectException.java +++ b/src/share/classes/java/net/ConnectException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1997 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 @@ -34,6 +34,8 @@ package java.net; * @since JDK1.1 */ public class ConnectException extends SocketException { + private static final long serialVersionUID = 3831404271622369215L; + /** * Constructs a new ConnectException with the specified detail * message as to why the connect error occurred. 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/HttpRetryException.java b/src/share/classes/java/net/HttpRetryException.java index d6f336e3e7ca1db28779da855a709c1ec31b0a5c..5e75dc94ab786f854e324466c6b9def7cf695e10 100644 --- a/src/share/classes/java/net/HttpRetryException.java +++ b/src/share/classes/java/net/HttpRetryException.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.io.IOException; */ public class HttpRetryException extends IOException { + private static final long serialVersionUID = -9186022286469111381L; private int responseCode; private String location; 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/MalformedURLException.java b/src/share/classes/java/net/MalformedURLException.java index c38cd542cb2106d029d9400c1a13f20b2b7362c1..b8f3b6fb5ec889003f8e90d7fa8f04c675de6d55 100644 --- a/src/share/classes/java/net/MalformedURLException.java +++ b/src/share/classes/java/net/MalformedURLException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -36,6 +36,8 @@ import java.io.IOException; * @since JDK1.0 */ public class MalformedURLException extends IOException { + private static final long serialVersionUID = -182787522200415866L; + /** * Constructs a MalformedURLException with no detail message. */ 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/share/classes/java/net/NoRouteToHostException.java b/src/share/classes/java/net/NoRouteToHostException.java index 8bfc3de72adf82a2e4e8c5a1366b24c7d51ba6f7..e6db581a222ab8febb7305c27b111b8669e49267 100644 --- a/src/share/classes/java/net/NoRouteToHostException.java +++ b/src/share/classes/java/net/NoRouteToHostException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1997 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 @@ -34,6 +34,8 @@ package java.net; * @since JDK1.1 */ public class NoRouteToHostException extends SocketException { + private static final long serialVersionUID = -1897550894873493790L; + /** * Constructs a new NoRouteToHostException with the specified detail * message as to why the remote host cannot be reached. diff --git a/src/share/classes/java/net/PortUnreachableException.java b/src/share/classes/java/net/PortUnreachableException.java index cf8f24d23a9462d28aa300e1ba42e345b82ebf70..e4491d891326c41b215398c2f3975444fd4ac0f5 100644 --- a/src/share/classes/java/net/PortUnreachableException.java +++ b/src/share/classes/java/net/PortUnreachableException.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 @@ -33,6 +33,7 @@ package java.net; */ public class PortUnreachableException extends SocketException { + private static final long serialVersionUID = 8462541992376507323L; /** * Constructs a new PortUnreachableException with a diff --git a/src/share/classes/java/net/ProtocolException.java b/src/share/classes/java/net/ProtocolException.java index 3eef7d5382b7fb9607876def423f1dcb4e8aa0e6..b0567f2e573bf8aaf5b2f6d3e017e9542f51bfc6 100644 --- a/src/share/classes/java/net/ProtocolException.java +++ b/src/share/classes/java/net/ProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -36,6 +36,8 @@ import java.io.IOException; */ public class ProtocolException extends IOException { + private static final long serialVersionUID = -6098449442062388080L; + /** * Constructs a new ProtocolException with the * specified detail message. diff --git a/src/share/classes/java/net/ProtocolFamily.java b/src/share/classes/java/net/ProtocolFamily.java new file mode 100644 index 0000000000000000000000000000000000000000..b997c7bb0a69ab3fc96c2543148923a035c52ae5 --- /dev/null +++ b/src/share/classes/java/net/ProtocolFamily.java @@ -0,0 +1,39 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * Represents a family of communication protocols. + * + * @since 1.7 + */ + +public interface ProtocolFamily { + /** + * Returns the name of the protocol family. + */ + String name(); +} diff --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/share/classes/java/net/SocketException.java b/src/share/classes/java/net/SocketException.java index 6b40c3c832d50caa9d1fb3146751dd811b58c1fc..6e6f60d340e867489e74edfd0e95fa7fcd58baaf 100644 --- a/src/share/classes/java/net/SocketException.java +++ b/src/share/classes/java/net/SocketException.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 @@ -35,6 +35,8 @@ import java.io.IOException; */ public class SocketException extends IOException { + private static final long serialVersionUID = -5935874303556886934L; + /** * Constructs a new SocketException with the * specified detail message. diff --git a/src/share/classes/java/net/SocketOption.java b/src/share/classes/java/net/SocketOption.java new file mode 100644 index 0000000000000000000000000000000000000000..afc9714b5ab95f5c615820b12daa78209c959b02 --- /dev/null +++ b/src/share/classes/java/net/SocketOption.java @@ -0,0 +1,55 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * A socket option associated with a socket. + * + *

In the {@link java.nio.channels channels} package, the {@link + * java.nio.channels.NetworkChannel} interface defines the {@link + * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption} + * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption} + * methods to set and query the channel's socket options. + * + * @param The type of the socket option value. + * + * @since 1.7 + * + * @see StandardSocketOption + */ + +public interface SocketOption { + + /** + * Returns the name of the socket option. + */ + String name(); + + /** + * Returns the type of the socket option value. + */ + Class type(); +} diff --git a/src/share/classes/java/net/SocketTimeoutException.java b/src/share/classes/java/net/SocketTimeoutException.java index b44995959565989fb164d619ddda484529ba498d..fab3a5810a58786182432a7f487b326d3ced1d5b 100644 --- a/src/share/classes/java/net/SocketTimeoutException.java +++ b/src/share/classes/java/net/SocketTimeoutException.java @@ -1,5 +1,5 @@ /* - * Copyright 2000 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,6 +32,7 @@ package java.net; */ public class SocketTimeoutException extends java.io.InterruptedIOException { + private static final long serialVersionUID = -8846654841826352300L; /** * Constructs a new SocketTimeoutException with a detail diff --git a/src/share/classes/java/net/StandardProtocolFamily.java b/src/share/classes/java/net/StandardProtocolFamily.java new file mode 100644 index 0000000000000000000000000000000000000000..7c11b32f59fc61f741978eca32191a6cd1fa952b --- /dev/null +++ b/src/share/classes/java/net/StandardProtocolFamily.java @@ -0,0 +1,45 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +/** + * Defines the standard family of communication protocols. + * + * @since 1.7 + */ + +public enum StandardProtocolFamily implements ProtocolFamily { + + /** + * Internet Protocol Version 4 (IPv4) + */ + INET, + + /** + * Internet Protocol Version 6 (IPv6) + */ + INET6 +} diff --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/net/URISyntaxException.java b/src/share/classes/java/net/URISyntaxException.java index e1882be40fea3c6554579a535c2cfe715bfe92ca..17a6bbb72d01a8adf8144e4408b65e1864576ea3 100644 --- a/src/share/classes/java/net/URISyntaxException.java +++ b/src/share/classes/java/net/URISyntaxException.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 @@ -38,6 +38,8 @@ package java.net; public class URISyntaxException extends Exception { + private static final long serialVersionUID = 2137979680897488891L; + private String input; private int index; diff --git a/src/share/classes/java/net/UnknownHostException.java b/src/share/classes/java/net/UnknownHostException.java index b6df3be5d8d1861d1a71e01851d74ee05a2b1acc..860b847d6aa23b36eacde585abf9f599f3387e0c 100644 --- a/src/share/classes/java/net/UnknownHostException.java +++ b/src/share/classes/java/net/UnknownHostException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -35,6 +35,8 @@ import java.io.IOException; */ public class UnknownHostException extends IOException { + private static final long serialVersionUID = -4639126076052875403L; + /** * Constructs a new UnknownHostException with the * specified detail message. diff --git a/src/share/classes/java/net/UnknownServiceException.java b/src/share/classes/java/net/UnknownServiceException.java index 9e3e7fd3520988f96a0e0a4a49bc98d99b1ded9b..d006e3af23c2cc7dab9b5523bcb6641a077ab206 100644 --- a/src/share/classes/java/net/UnknownServiceException.java +++ b/src/share/classes/java/net/UnknownServiceException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-1997 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 @@ -37,6 +37,8 @@ import java.io.IOException; * @since JDK1.0 */ public class UnknownServiceException extends IOException { + private static final long serialVersionUID = -4169033248853639508L; + /** * Constructs a new UnknownServiceException with no * detail message. 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/text/SimpleDateFormat.java b/src/share/classes/java/text/SimpleDateFormat.java index 548ffb730f318134bddf4f4ed7c16082e0fa5be3..e543899fe95b342dcc4e0d8ac2323a3594ff77d7 100644 --- a/src/share/classes/java/text/SimpleDateFormat.java +++ b/src/share/classes/java/text/SimpleDateFormat.java @@ -373,6 +373,24 @@ public class SimpleDateFormat extends DateFormat { */ private String pattern; + /** + * Saved numberFormat and pattern. + * @see SimpleDateFormat#checkNegativeNumberExpression + */ + transient private NumberFormat originalNumberFormat; + transient private String originalNumberPattern; + + /** + * The minus sign to be used with format and parse. + */ + transient private char minusSign = '-'; + + /** + * True when a negative sign follows a number. + * (True as default in Arabic.) + */ + transient private boolean hasFollowingMinusSign = false; + /** * The compiled pattern. */ @@ -1226,6 +1244,8 @@ public class SimpleDateFormat extends DateFormat { */ public Date parse(String text, ParsePosition pos) { + checkNegativeNumberExpression(); + int start = pos.index; int oldStart = start; int textLength = text.length(); @@ -1271,14 +1291,42 @@ public class SimpleDateFormat extends DateFormat { // digit text (e.g., "20010704") with a pattern which // has no delimiters between fields, like "yyyyMMdd". boolean obeyCount = false; + + // In Arabic, a minus sign for a negative number is put after + // the number. Even in another locale, a minus sign can be + // put after a number using DateFormat.setNumberFormat(). + // If both the minus sign and the field-delimiter are '-', + // subParse() needs to determine whether a '-' after a number + // in the given text is a delimiter or is a minus sign for the + // preceding number. We give subParse() a clue based on the + // information in compiledPattern. + boolean useFollowingMinusSignAsDelimiter = false; + if (i < compiledPattern.length) { int nextTag = compiledPattern[i] >>> 8; - if (!(nextTag == TAG_QUOTE_ASCII_CHAR || nextTag == TAG_QUOTE_CHARS)) { + if (!(nextTag == TAG_QUOTE_ASCII_CHAR || + nextTag == TAG_QUOTE_CHARS)) { obeyCount = true; } + + if (hasFollowingMinusSign && + (nextTag == TAG_QUOTE_ASCII_CHAR || + nextTag == TAG_QUOTE_CHARS)) { + int c; + if (nextTag == TAG_QUOTE_ASCII_CHAR) { + c = compiledPattern[i] & 0xff; + } else { + c = compiledPattern[i+1]; + } + + if (c == minusSign) { + useFollowingMinusSignAsDelimiter = true; + } + } } start = subParse(text, start, tag, count, obeyCount, - ambiguousYear, pos); + ambiguousYear, pos, + useFollowingMinusSignAsDelimiter); if (start < 0) { pos.index = oldStart; return null; @@ -1482,10 +1530,13 @@ public class SimpleDateFormat extends DateFormat { // If the time zone matched uses the same name // (abbreviation) for both standard and daylight time, // let the time zone in the Calendar decide which one. - if (!useSameName) { + // + // Also if tz.getDSTSaving() returns 0 for DST, use tz to + // determine the local time. (6645292) + int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0; + if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) { calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); - calendar.set(Calendar.DST_OFFSET, - nameIndex >= 3 ? tz.getDSTSavings() : 0); + calendar.set(Calendar.DST_OFFSET, dstAmount); } return (start + zoneNames[nameIndex].length()); } @@ -1511,8 +1562,8 @@ public class SimpleDateFormat extends DateFormat { */ private int subParse(String text, int start, int patternCharIndex, int count, boolean obeyCount, boolean[] ambiguousYear, - ParsePosition origPos) - { + ParsePosition origPos, + boolean useFollowingMinusSignAsDelimiter) { Number number = null; int value = 0; ParsePosition pos = new ParsePosition(0); @@ -1537,10 +1588,10 @@ public class SimpleDateFormat extends DateFormat { // a number value. We handle further, more generic cases below. We need // to handle some of them here because some fields require extra processing on // the parsed value. - if (patternCharIndex == 4 /*HOUR_OF_DAY1_FIELD*/ || - patternCharIndex == 15 /*HOUR1_FIELD*/ || - (patternCharIndex == 2 /*MONTH_FIELD*/ && count <= 2) || - patternCharIndex == 1) { + if (patternCharIndex == 4 /* HOUR_OF_DAY1_FIELD */ || + patternCharIndex == 15 /* HOUR1_FIELD */ || + (patternCharIndex == 2 /* MONTH_FIELD */ && count <= 2) || + patternCharIndex == 1 /* YEAR_FIELD */) { // It would be good to unify this with the obeyCount logic below, // but that's going to be difficult. if (obeyCount) { @@ -1557,6 +1608,15 @@ public class SimpleDateFormat extends DateFormat { } } else { value = number.intValue(); + + if (useFollowingMinusSignAsDelimiter && (value < 0) && + (((pos.index < text.length()) && + (text.charAt(pos.index) != minusSign)) || + ((pos.index == text.length()) && + (text.charAt(pos.index-1) == minusSign)))) { + value = -value; + pos.index--; + } } } @@ -1888,7 +1948,18 @@ public class SimpleDateFormat extends DateFormat { number = numberFormat.parse(text, pos); } if (number != null) { - calendar.set(field, number.intValue()); + value = number.intValue(); + + if (useFollowingMinusSignAsDelimiter && (value < 0) && + (((pos.index < text.length()) && + (text.charAt(pos.index) != minusSign)) || + ((pos.index == text.length()) && + (text.charAt(pos.index-1) == minusSign)))) { + value = -value; + pos.index--; + } + + calendar.set(field, value); return pos.index; } break parsing; @@ -2099,4 +2170,33 @@ public class SimpleDateFormat extends DateFormat { } } } + + /** + * Analyze the negative subpattern of DecimalFormat and set/update values + * as necessary. + */ + private void checkNegativeNumberExpression() { + if ((numberFormat instanceof DecimalFormat) && + !numberFormat.equals(originalNumberFormat)) { + String numberPattern = ((DecimalFormat)numberFormat).toPattern(); + if (!numberPattern.equals(originalNumberPattern)) { + hasFollowingMinusSign = false; + + int separatorIndex = numberPattern.indexOf(';'); + // If the negative subpattern is not absent, we have to analayze + // it in order to check if it has a following minus sign. + if (separatorIndex > -1) { + int minusIndex = numberPattern.indexOf('-', separatorIndex); + if ((minusIndex > numberPattern.lastIndexOf('0')) && + (minusIndex > numberPattern.lastIndexOf('#'))) { + hasFollowingMinusSign = true; + minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign(); + } + } + originalNumberPattern = numberPattern; + } + originalNumberFormat = numberFormat; + } + } + } diff --git a/src/share/classes/java/util/ConcurrentModificationException.java b/src/share/classes/java/util/ConcurrentModificationException.java index 19a30286538425904c6c9eb9534c8f6b68856520..fbe9282dc5988fcfa99c986176e2efb6ec990277 100644 --- a/src/share/classes/java/util/ConcurrentModificationException.java +++ b/src/share/classes/java/util/ConcurrentModificationException.java @@ -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 @@ -67,6 +67,8 @@ package java.util; * @since 1.2 */ public class ConcurrentModificationException extends RuntimeException { + private static final long serialVersionUID = -3666751008965953603L; + /** * Constructs a ConcurrentModificationException with no * detail message. 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/EmptyStackException.java b/src/share/classes/java/util/EmptyStackException.java index 0bdaa2ee2e532c54757075c8a8827b656eb07d2c..09ba39b0ec5c3caa32940e2bac1b66d5208fe306 100644 --- a/src/share/classes/java/util/EmptyStackException.java +++ b/src/share/classes/java/util/EmptyStackException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1998 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,6 +35,8 @@ package java.util; */ public class EmptyStackException extends RuntimeException { + private static final long serialVersionUID = 5084686378493302095L; + /** * Constructs a new EmptyStackException with null * as its error message string. 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/InputMismatchException.java b/src/share/classes/java/util/InputMismatchException.java index 87b0c60bfe1d3003cb398b2ec1ebc285904fd3a3..ff1729c2133c9f23a884b04abc595f3d0b4a90d9 100644 --- a/src/share/classes/java/util/InputMismatchException.java +++ b/src/share/classes/java/util/InputMismatchException.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 @@ -36,6 +36,8 @@ package java.util; */ public class InputMismatchException extends NoSuchElementException { + private static final long serialVersionUID = 8811230760997066428L; + /** * Constructs an InputMismatchException with null * as its error message string. diff --git a/src/share/classes/java/util/NoSuchElementException.java b/src/share/classes/java/util/NoSuchElementException.java index 9750122cb4a5e2fc353189b548a8322c017d57df..e4cbe8eef803f54d9fac43acb67f2e90454e3324 100644 --- a/src/share/classes/java/util/NoSuchElementException.java +++ b/src/share/classes/java/util/NoSuchElementException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1998 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 @@ -37,6 +37,8 @@ package java.util; */ public class NoSuchElementException extends RuntimeException { + private static final long serialVersionUID = 6769829250639411880L; + /** * Constructs a NoSuchElementException with null * as its error message string. 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/TooManyListenersException.java b/src/share/classes/java/util/TooManyListenersException.java index f7778a5edd1ba2be20c1e002cbc1ae7b80e50f01..c9feb95718044d207fefeffb2fed3dfdebd9068c 100644 --- a/src/share/classes/java/util/TooManyListenersException.java +++ b/src/share/classes/java/util/TooManyListenersException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-1999 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 @@ -48,6 +48,7 @@ package java.util; */ public class TooManyListenersException extends Exception { + private static final long serialVersionUID = 5074640544770687831L; /** * Constructs a TooManyListenersException with no detail message. 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/jar/JarException.java b/src/share/classes/java/util/jar/JarException.java index a8c66b692f13f3f9af77ac8398e552ed603d71ea..a28bbcc5b743dbb774b8bdaa242e51c8a5820eaf 100644 --- a/src/share/classes/java/util/jar/JarException.java +++ b/src/share/classes/java/util/jar/JarException.java @@ -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 @@ package java.util.jar; */ public class JarException extends java.util.zip.ZipException { + private static final long serialVersionUID = 7159778400963954473L; + /** * Constructs a JarException with no detail message. */ 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/regex/PatternSyntaxException.java b/src/share/classes/java/util/regex/PatternSyntaxException.java index 093b6a39816e359aa2084270e8b2a9cea65f33a5..404756ed6d56471d681c98accb9c67f05c340adb 100644 --- a/src/share/classes/java/util/regex/PatternSyntaxException.java +++ b/src/share/classes/java/util/regex/PatternSyntaxException.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 @@ -40,6 +40,7 @@ import sun.security.action.GetPropertyAction; public class PatternSyntaxException extends IllegalArgumentException { + private static final long serialVersionUID = -3864639126226059218L; private final String desc; private final String pattern; diff --git a/src/share/classes/java/util/zip/DataFormatException.java b/src/share/classes/java/util/zip/DataFormatException.java index db884f21e009ebf9432a56c8e31938113af51784..08730b875817d92bc149f96658956dba79796ae8 100644 --- a/src/share/classes/java/util/zip/DataFormatException.java +++ b/src/share/classes/java/util/zip/DataFormatException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996 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 @@ -32,6 +32,8 @@ package java.util.zip; */ public class DataFormatException extends Exception { + private static final long serialVersionUID = 2219632870893641452L; + /** * Constructs a DataFormatException with no detail message. */ 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/ZipException.java b/src/share/classes/java/util/zip/ZipException.java index 467a51c9bafb15e62b5ce2f0af7e982a0dc4d82c..a5dbc12a1538abb0e3a8bb87adb7dd0a2eaaeb48 100644 --- a/src/share/classes/java/util/zip/ZipException.java +++ b/src/share/classes/java/util/zip/ZipException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2001 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 @@ -37,6 +37,8 @@ import java.io.IOException; public class ZipException extends IOException { + private static final long serialVersionUID = 8000196834066748623L; + /** * Constructs an ZipException with null * as its error detail message. 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..f1dc6bcc08061454e9d260222b99a60a038805c8 100644 --- a/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java +++ b/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java @@ -48,7 +48,7 @@ import java.lang.reflect.Type; * effect by defining {@code MyLinkedListMappingFactory} as follows:

      * *
      - * public class MyLinkedListMappingFactory implements MXBeanMappingFactory {
      + * public class MyLinkedListMappingFactory extends MXBeanMappingFactory {
        *     public MyLinkedListMappingFactory() {}
        *
        *     public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
      @@ -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/AbstractButton.java b/src/share/classes/javax/swing/AbstractButton.java index 4248a7144e0e0a4f14ed51e94bc74f2e94b614cc..d48108101283e68fa821f870c9f353c8eb2459af 100644 --- a/src/share/classes/javax/swing/AbstractButton.java +++ b/src/share/classes/javax/swing/AbstractButton.java @@ -1315,8 +1315,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl // Make sure the change actually took effect if (!selected && isSelected()) { if (getModel() instanceof DefaultButtonModel) { - ButtonGroup group = (ButtonGroup) - ((DefaultButtonModel)getModel()).getGroup(); + ButtonGroup group = ((DefaultButtonModel)getModel()).getGroup(); if (group != null) { group.clearSelection(); } @@ -1886,8 +1885,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])(listenerList.getListeners( - ChangeListener.class)); + return listenerList.getListeners(ChangeListener.class); } /** @@ -1944,8 +1942,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * @since 1.4 */ public ActionListener[] getActionListeners() { - return (ActionListener[])(listenerList.getListeners( - ActionListener.class)); + return listenerList.getListeners(ActionListener.class); } /** @@ -2137,7 +2134,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * @since 1.4 */ public ItemListener[] getItemListeners() { - return (ItemListener[])listenerList.getListeners(ItemListener.class); + return listenerList.getListeners(ItemListener.class); } /** @@ -2981,7 +2978,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl paintViewR.height = AbstractButton.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom); String clippedText = SwingUtilities.layoutCompoundLabel( - (JComponent)AbstractButton.this, + AbstractButton.this, getFontMetrics(getFont()), text, icon, diff --git a/src/share/classes/javax/swing/AbstractCellEditor.java b/src/share/classes/javax/swing/AbstractCellEditor.java index 5ecdc439003bd88dab290a27ee94da91cab76f55..90b1c8d69b401e3208b4c802228e14a01e3527f7 100644 --- a/src/share/classes/javax/swing/AbstractCellEditor.java +++ b/src/share/classes/javax/swing/AbstractCellEditor.java @@ -118,8 +118,7 @@ public abstract class AbstractCellEditor implements CellEditor, Serializable { * @since 1.4 */ public CellEditorListener[] getCellEditorListeners() { - return (CellEditorListener[])listenerList.getListeners( - CellEditorListener.class); + return listenerList.getListeners(CellEditorListener.class); } /** diff --git a/src/share/classes/javax/swing/AbstractListModel.java b/src/share/classes/javax/swing/AbstractListModel.java index 102218bdb7c627b180478086a2b908274cb3839f..00c8841a533081caa59baa7f60e6527789e28fb4 100644 --- a/src/share/classes/javax/swing/AbstractListModel.java +++ b/src/share/classes/javax/swing/AbstractListModel.java @@ -85,8 +85,7 @@ public abstract class AbstractListModel implements ListModel, Serializable * @since 1.4 */ public ListDataListener[] getListDataListeners() { - return (ListDataListener[])listenerList.getListeners( - ListDataListener.class); + return listenerList.getListeners(ListDataListener.class); } diff --git a/src/share/classes/javax/swing/AbstractSpinnerModel.java b/src/share/classes/javax/swing/AbstractSpinnerModel.java index 2956339124c151abe0341397686bc29b4cfc8522..9cf16c6db149fdb6ff2214b0cbc29a7ed60fc03d 100644 --- a/src/share/classes/javax/swing/AbstractSpinnerModel.java +++ b/src/share/classes/javax/swing/AbstractSpinnerModel.java @@ -98,8 +98,7 @@ public abstract class AbstractSpinnerModel implements SpinnerModel, Serializable * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } diff --git a/src/share/classes/javax/swing/ActionMap.java b/src/share/classes/javax/swing/ActionMap.java index b1d4e4b20fb5124af4bd4a956cad2b5606e358b6..3858eabe43153558e37cfe60e056bcaa2295eda2 100644 --- a/src/share/classes/javax/swing/ActionMap.java +++ b/src/share/classes/javax/swing/ActionMap.java @@ -197,7 +197,7 @@ public class ActionMap implements Serializable { return pKeys; } - HashMap keyMap = new HashMap(); + HashMap keyMap = new HashMap(); int counter; for (counter = keys.length - 1; counter >= 0; counter--) { diff --git a/src/share/classes/javax/swing/AncestorNotifier.java b/src/share/classes/javax/swing/AncestorNotifier.java index 694bc5df08d9fec5430e10f1b7172640bbb78d61..eb67ed154849cd749167623fd0e659144505a7d9 100644 --- a/src/share/classes/javax/swing/AncestorNotifier.java +++ b/src/share/classes/javax/swing/AncestorNotifier.java @@ -62,7 +62,7 @@ class AncestorNotifier implements ComponentListener, PropertyChangeListener, Ser } AncestorListener[] getAncestorListeners() { - return (AncestorListener[])listenerList.getListeners(AncestorListener.class); + return listenerList.getListeners(AncestorListener.class); } /** diff --git a/src/share/classes/javax/swing/ArrayTable.java b/src/share/classes/javax/swing/ArrayTable.java index b44fc436cdc22ccc14ff28e906aeb6c4ad25cd82..1ee5f07d88c2b3a81f4a5a36e7c3ecc6ab1f8ee5 100644 --- a/src/share/classes/javax/swing/ArrayTable.java +++ b/src/share/classes/javax/swing/ArrayTable.java @@ -88,10 +88,10 @@ class ArrayTable implements Cloneable { // Write ou the Serializable key/value pairs. s.writeInt(validCount); if (validCount > 0) { - for (int counter = 0; counter < keys.length; counter++) { - if (keys[counter] != null) { - s.writeObject(keys[counter]); - s.writeObject(table.get(keys[counter])); + for (Object key : keys) { + if (key != null) { + s.writeObject(key); + s.writeObject(table.get(key)); if (--validCount == 0) { break; } @@ -315,7 +315,7 @@ class ArrayTable implements Cloneable { */ private void grow() { Object[] array = (Object[])table; - Hashtable tmp = new Hashtable(array.length/2); + Hashtable tmp = new Hashtable(array.length/2); for (int i = 0; i buttons = new Vector(); + protected Vector buttons = new Vector(); /** * The current selection. diff --git a/src/share/classes/javax/swing/DebugGraphicsInfo.java b/src/share/classes/javax/swing/DebugGraphicsInfo.java index f9e6c72a9840e9997755cac2ca2784e9509f5973..75be3e7f8000ded8fdc10c0e92dc0451866796e7 100644 --- a/src/share/classes/javax/swing/DebugGraphicsInfo.java +++ b/src/share/classes/javax/swing/DebugGraphicsInfo.java @@ -37,7 +37,7 @@ class DebugGraphicsInfo { Color flashColor = Color.red; int flashTime = 100; int flashCount = 2; - Hashtable componentToDebug; + Hashtable componentToDebug; JFrame debugFrame = null; java.io.PrintStream stream = System.out; @@ -46,7 +46,7 @@ class DebugGraphicsInfo { return; } if (componentToDebug == null) { - componentToDebug = new Hashtable(); + componentToDebug = new Hashtable(); } if (debug > 0) { componentToDebug.put(component, Integer.valueOf(debug)); @@ -59,7 +59,7 @@ class DebugGraphicsInfo { if (componentToDebug == null) { return 0; } else { - Integer integer = (Integer)componentToDebug.get(component); + Integer integer = componentToDebug.get(component); return integer == null ? 0 : integer.intValue(); } diff --git a/src/share/classes/javax/swing/DefaultBoundedRangeModel.java b/src/share/classes/javax/swing/DefaultBoundedRangeModel.java index d8e4f0f04541e1f3c5cb3c17b6ba4aa584e83215..c718ce6027fc2294ee543d78bfeec11c3b71a546 100644 --- a/src/share/classes/javax/swing/DefaultBoundedRangeModel.java +++ b/src/share/classes/javax/swing/DefaultBoundedRangeModel.java @@ -343,8 +343,7 @@ public class DefaultBoundedRangeModel implements BoundedRangeModel, Serializable * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } diff --git a/src/share/classes/javax/swing/DefaultButtonModel.java b/src/share/classes/javax/swing/DefaultButtonModel.java index b9c9438442636e444d3035c16032dcb808c38c89..8ad0acddb466d1f44f1604eedd3c4b550fee30c9 100644 --- a/src/share/classes/javax/swing/DefaultButtonModel.java +++ b/src/share/classes/javax/swing/DefaultButtonModel.java @@ -326,8 +326,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable { * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** @@ -380,8 +379,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable { * @since 1.4 */ public ActionListener[] getActionListeners() { - return (ActionListener[])listenerList.getListeners( - ActionListener.class); + return listenerList.getListeners(ActionListener.class); } /** @@ -434,7 +432,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable { * @since 1.4 */ public ItemListener[] getItemListeners() { - return (ItemListener[])listenerList.getListeners(ItemListener.class); + return listenerList.getListeners(ItemListener.class); } /** diff --git a/src/share/classes/javax/swing/DefaultFocusManager.java b/src/share/classes/javax/swing/DefaultFocusManager.java index 417b625f95ad386d180f47b479eb9149bfb176e4..021867a5ccab79b132f4fb78f865b52bcb39e880 100644 --- a/src/share/classes/javax/swing/DefaultFocusManager.java +++ b/src/share/classes/javax/swing/DefaultFocusManager.java @@ -156,18 +156,17 @@ final class LegacyLayoutFocusTraversalPolicy } } -final class CompareTabOrderComparator implements Comparator { +final class CompareTabOrderComparator implements Comparator { private final DefaultFocusManager defaultFocusManager; CompareTabOrderComparator(DefaultFocusManager defaultFocusManager) { this.defaultFocusManager = defaultFocusManager; } - public int compare(Object o1, Object o2) { + public int compare(Component o1, Component o2) { if (o1 == o2) { return 0; } - return (defaultFocusManager.compareTabOrder((Component)o1, - (Component)o2)) ? -1 : 1; + return (defaultFocusManager.compareTabOrder(o1, o2)) ? -1 : 1; } } diff --git a/src/share/classes/javax/swing/DefaultListSelectionModel.java b/src/share/classes/javax/swing/DefaultListSelectionModel.java index 329fa38b44aea52278ef7f43f0eece42bed4fdec..2ba0e7b9d25bd623c5a39f2c9600242c7ab82c8c 100644 --- a/src/share/classes/javax/swing/DefaultListSelectionModel.java +++ b/src/share/classes/javax/swing/DefaultListSelectionModel.java @@ -133,8 +133,7 @@ public class DefaultListSelectionModel implements ListSelectionModel, Cloneable, * @since 1.4 */ public ListSelectionListener[] getListSelectionListeners() { - return (ListSelectionListener[])listenerList.getListeners( - ListSelectionListener.class); + return listenerList.getListeners(ListSelectionListener.class); } /** diff --git a/src/share/classes/javax/swing/DefaultSingleSelectionModel.java b/src/share/classes/javax/swing/DefaultSingleSelectionModel.java index d0270f1c75e796ab795b6c1acea50754a01bc0e0..c03b51f16ddf054223ecdbc43c360207cc9cebdc 100644 --- a/src/share/classes/javax/swing/DefaultSingleSelectionModel.java +++ b/src/share/classes/javax/swing/DefaultSingleSelectionModel.java @@ -110,8 +110,7 @@ Serializable { * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** diff --git a/src/share/classes/javax/swing/GroupLayout.java b/src/share/classes/javax/swing/GroupLayout.java index fd1fd0c65cbd6017e9033bce697b801ceee83af2..fb59d0c85640e5b557194b9caa3bdb386e2f3514 100644 --- a/src/share/classes/javax/swing/GroupLayout.java +++ b/src/share/classes/javax/swing/GroupLayout.java @@ -1119,7 +1119,7 @@ public class GroupLayout implements LayoutManager2 { * creating one if necessary. */ private ComponentInfo getComponentInfo(Component component) { - ComponentInfo info = (ComponentInfo)componentInfos.get(component); + ComponentInfo info = componentInfos.get(component); if (info == null) { info = new ComponentInfo(component); componentInfos.put(component, info); @@ -1698,7 +1698,7 @@ public class GroupLayout implements LayoutManager2 { for (int counter = springs.size() - 1; counter >= 0; counter--) { Spring spring = springs.get(counter); if (spring instanceof AutoPreferredGapSpring) { - ((AutoPreferredGapSpring)spring).unset(); + spring.unset(); } else if (spring instanceof Group) { ((Group)spring).unsetAutopadding(); } diff --git a/src/share/classes/javax/swing/InputMap.java b/src/share/classes/javax/swing/InputMap.java index cba5a5d8bb3838d6981d5810319087dd47dbdda7..0992b1188f8e8871f5c91b6ad5ddaf4e74ad6995 100644 --- a/src/share/classes/javax/swing/InputMap.java +++ b/src/share/classes/javax/swing/InputMap.java @@ -200,7 +200,7 @@ public class InputMap implements Serializable { return pKeys; } - HashMap keyMap = new HashMap(); + HashMap keyMap = new HashMap(); int counter; for (counter = keys.length - 1; counter >= 0; counter--) { @@ -212,7 +212,7 @@ public class InputMap implements Serializable { KeyStroke[] allKeys = new KeyStroke[keyMap.size()]; - return (KeyStroke[])keyMap.keySet().toArray(allKeys); + return keyMap.keySet().toArray(allKeys); } private void writeObject(ObjectOutputStream s) throws IOException { diff --git a/src/share/classes/javax/swing/JApplet.java b/src/share/classes/javax/swing/JApplet.java index b9b5b2506b9115ef58712cfd623ffd14c8129134..47f792a942d33a67cf754fc3a30c410da4541abd 100644 --- a/src/share/classes/javax/swing/JApplet.java +++ b/src/share/classes/javax/swing/JApplet.java @@ -131,10 +131,7 @@ public class JApplet extends Applet implements Accessible, // Check the timerQ and restart if necessary. TimerQueue q = TimerQueue.sharedInstance(); if(q != null) { - synchronized(q) { - if(!q.running) - q.start(); - } + q.startIfNeeded(); } /* Workaround for bug 4155072. The shared double buffer image diff --git a/src/share/classes/javax/swing/JComboBox.java b/src/share/classes/javax/swing/JComboBox.java index 2230147f4a97c1b111eaa0d58499fa760f082929..42ef6466979461e08bb6e5fdd26bfee63f8fcf1c 100644 --- a/src/share/classes/javax/swing/JComboBox.java +++ b/src/share/classes/javax/swing/JComboBox.java @@ -859,7 +859,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { * @since 1.4 */ public ItemListener[] getItemListeners() { - return (ItemListener[])listenerList.getListeners(ItemListener.class); + return listenerList.getListeners(ItemListener.class); } /** @@ -897,8 +897,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { * @since 1.4 */ public ActionListener[] getActionListeners() { - return (ActionListener[])listenerList.getListeners( - ActionListener.class); + return listenerList.getListeners(ActionListener.class); } /** @@ -937,8 +936,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { * @since 1.4 */ public PopupMenuListener[] getPopupMenuListeners() { - return (PopupMenuListener[])listenerList.getListeners( - PopupMenuListener.class); + return listenerList.getListeners(PopupMenuListener.class); } /** @@ -1668,7 +1666,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { if (editor != null) { Component comp = editor.getEditorComponent(); if (comp instanceof Accessible) { - AccessibleContext ac = ((Accessible)comp).getAccessibleContext(); + AccessibleContext ac = comp.getAccessibleContext(); if (ac != null) { // may be null ac.setAccessibleName(getAccessibleName()); ac.setAccessibleDescription(getAccessibleDescription()); @@ -1741,7 +1739,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { // Fire a FOCUSED lost PropertyChangeEvent for the // previously selected list item. - PropertyChangeEvent pce = null; + PropertyChangeEvent pce; if (previousSelectedAccessible != null) { pce = new PropertyChangeEvent(previousSelectedAccessible, diff --git a/src/share/classes/javax/swing/JComponent.java b/src/share/classes/javax/swing/JComponent.java index 7d3881a1c0589a19178a546db765c49c6bcb5da9..831dc717a072bf37ea30fc5d7cb52bc0a57ea09d 100644 --- a/src/share/classes/javax/swing/JComponent.java +++ b/src/share/classes/javax/swing/JComponent.java @@ -192,7 +192,8 @@ public abstract class JComponent extends Container implements Serializable, /** * @see #readObject */ - private static final Hashtable readObjectCallbacks = new Hashtable(1); + private static final Hashtable readObjectCallbacks = + new Hashtable(1); /** * Keys to use for forward focus traversal when the JComponent is @@ -356,7 +357,7 @@ public abstract class JComponent extends Container implements Serializable, /** * Temporary rectangles. */ - private static java.util.List tempRectangles = new java.util.ArrayList(11); + private static java.util.List tempRectangles = new java.util.ArrayList(11); /** Used for WHEN_FOCUSED bindings. */ private InputMap focusInputMap; @@ -451,7 +452,7 @@ public abstract class JComponent extends Container implements Serializable, Rectangle rect; int size = tempRectangles.size(); if (size > 0) { - rect = (Rectangle)tempRectangles.remove(size - 1); + rect = tempRectangles.remove(size - 1); } else { rect = new Rectangle(0, 0, 0, 0); @@ -806,7 +807,7 @@ public abstract class JComponent extends Container implements Serializable, // its index. if (paintingChild != null && (paintingChild instanceof JComponent) && - ((JComponent)paintingChild).isOpaque()) { + paintingChild.isOpaque()) { for (; i >= 0; i--) { if (getComponent(i) == paintingChild){ break; @@ -875,7 +876,7 @@ public abstract class JComponent extends Container implements Serializable, shouldSetFlagBack = true; } if(!printing) { - ((JComponent)comp).paint(cg); + comp.paint(cg); } else { if (!getFlag(IS_PRINTING_ALL)) { @@ -1098,7 +1099,7 @@ public abstract class JComponent extends Container implements Serializable, } private void adjustPaintFlags() { - JComponent jparent = null; + JComponent jparent; Container parent; for(parent = getParent() ; parent != null ; parent = parent.getParent()) { @@ -2096,7 +2097,7 @@ public abstract class JComponent extends Container implements Serializable, private void registerWithKeyboardManager(boolean onlyIfNew) { InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW, false); KeyStroke[] strokes; - Hashtable registered = (Hashtable)getClientProperty + Hashtable registered = (Hashtable)getClientProperty (WHEN_IN_FOCUSED_WINDOW_BINDINGS); if (inputMap != null) { @@ -2120,10 +2121,10 @@ public abstract class JComponent extends Container implements Serializable, } // Remove any old ones. if (registered != null && registered.size() > 0) { - Enumeration keys = registered.keys(); + Enumeration keys = registered.keys(); while (keys.hasMoreElements()) { - KeyStroke ks = (KeyStroke)keys.nextElement(); + KeyStroke ks = keys.nextElement(); unregisterWithKeyboardManager(ks); } registered.clear(); @@ -2131,7 +2132,7 @@ public abstract class JComponent extends Container implements Serializable, // Updated the registered Hashtable. if (strokes != null && strokes.length > 0) { if (registered == null) { - registered = new Hashtable(strokes.length); + registered = new Hashtable(strokes.length); putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, registered); } for (int counter = strokes.length - 1; counter >= 0; counter--) { @@ -2174,7 +2175,7 @@ public abstract class JComponent extends Container implements Serializable, InputMap km = getInputMap(WHEN_IN_FOCUSED_WINDOW, false); while (km != inputMap && km != null) { - km = (ComponentInputMap)km.getParent(); + km = km.getParent(); } if (km != null) { registerWithKeyboardManager(false); @@ -3673,7 +3674,7 @@ public abstract class JComponent extends Container implements Serializable, if (c != null && c instanceof Accessible) { AccessibleJComponent.this.firePropertyChange( AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, - null, ((Accessible) c).getAccessibleContext()); + null, c.getAccessibleContext()); } } public void componentRemoved(ContainerEvent e) { @@ -3681,7 +3682,7 @@ public abstract class JComponent extends Container implements Serializable, if (c != null && c instanceof Accessible) { AccessibleJComponent.this.firePropertyChange( AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, - ((Accessible) c).getAccessibleContext(), null); + c.getAccessibleContext(), null); } } } @@ -4377,7 +4378,7 @@ public abstract class JComponent extends Container implements Serializable, // System.out.println("A) checking opaque: " + ((JComponent)child).isOpaque() + " " + child); // System.out.print("B) "); // Thread.dumpStack(); - return ((JComponent)child).isOpaque(); + return child.isOpaque(); } else { /** Sometimes a heavy weight can have a bound larger than its peer size * so we should always draw under heavy weights @@ -4693,7 +4694,7 @@ public abstract class JComponent extends Container implements Serializable, result = (T[])getPropertyChangeListeners(); } else { - result = (T[])listenerList.getListeners(listenerType); + result = listenerList.getListeners(listenerType); } if (result.length == 0) { @@ -4904,7 +4905,7 @@ public abstract class JComponent extends Container implements Serializable, if(!isShowing()) { return; } - while(!((JComponent)c).isOpaque()) { + while(!c.isOpaque()) { parent = c.getParent(); if(parent != null) { x += c.getX(); @@ -5198,7 +5199,7 @@ public abstract class JComponent extends Container implements Serializable, Rectangle siblingRect; boolean opaque; if (sibling instanceof JComponent) { - opaque = ((JComponent)sibling).isOpaque(); + opaque = sibling.isOpaque(); if (!opaque) { if (retValue == PARTIALLY_OBSCURED) { continue; @@ -5345,7 +5346,7 @@ public abstract class JComponent extends Container implements Serializable, */ private class ReadObjectCallback implements ObjectInputValidation { - private final Vector roots = new Vector(1); + private final Vector roots = new Vector(1); private final ObjectInputStream inputStream; ReadObjectCallback(ObjectInputStream s) throws Exception { @@ -5361,8 +5362,7 @@ public abstract class JComponent extends Container implements Serializable, */ public void validateObject() throws InvalidObjectException { try { - for(int i = 0; i < roots.size(); i++) { - JComponent root = (JComponent)(roots.elementAt(i)); + for (JComponent root : roots) { SwingUtilities.updateComponentTreeUI(root); } } @@ -5382,8 +5382,7 @@ public abstract class JComponent extends Container implements Serializable, /* If the Component c is a descendant of one of the * existing roots (or it IS an existing root), we're done. */ - for(int i = 0; i < roots.size(); i++) { - JComponent root = (JComponent)roots.elementAt(i); + for (JComponent root : roots) { for(Component p = c; p != null; p = p.getParent()) { if (p == root) { return; @@ -5396,7 +5395,7 @@ public abstract class JComponent extends Container implements Serializable, * to the roots vector. */ for(int i = 0; i < roots.size(); i++) { - JComponent root = (JComponent)roots.elementAt(i); + JComponent root = roots.elementAt(i); for(Component p = root.getParent(); p != null; p = p.getParent()) { if (p == c) { roots.removeElementAt(i--); // !! @@ -5428,7 +5427,7 @@ public abstract class JComponent extends Container implements Serializable, * in the readObjectCallbacks table. Note that the ReadObjectCallback * constructor takes care of calling s.registerValidation(). */ - ReadObjectCallback cb = (ReadObjectCallback)(readObjectCallbacks.get(s)); + ReadObjectCallback cb = readObjectCallbacks.get(s); if (cb == null) { try { readObjectCallbacks.put(s, cb = new ReadObjectCallback(s)); diff --git a/src/share/classes/javax/swing/JDesktopPane.java b/src/share/classes/javax/swing/JDesktopPane.java index 2c0ab31202f9e4060b3484fcc40bd9cf4e024dd7..19cfefd65f9a53f98a79a141936fab3f961abaa4 100644 --- a/src/share/classes/javax/swing/JDesktopPane.java +++ b/src/share/classes/javax/swing/JDesktopPane.java @@ -133,8 +133,8 @@ public class JDesktopPane extends JLayeredPane implements Accessible public Component getDefaultComponent(Container c) { JInternalFrame jifArray[] = getAllFrames(); Component comp = null; - for (int i = 0; i < jifArray.length; i++) { - comp = jifArray[i].getFocusTraversalPolicy().getDefaultComponent(jifArray[i]); + for (JInternalFrame jif : jifArray) { + comp = jif.getFocusTraversalPolicy().getDefaultComponent(jif); if (comp != null) { break; } @@ -262,16 +262,15 @@ public class JDesktopPane extends JLayeredPane implements Accessible public JInternalFrame[] getAllFrames() { int i, count; JInternalFrame[] results; - Vector vResults = new Vector(10); - Object next, tmp; + Vector vResults = new Vector(10); count = getComponentCount(); for(i = 0; i < count; i++) { - next = getComponent(i); + Component next = getComponent(i); if(next instanceof JInternalFrame) - vResults.addElement(next); + vResults.addElement((JInternalFrame) next); else if(next instanceof JInternalFrame.JDesktopIcon) { - tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame(); + JInternalFrame tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame(); if(tmp != null) vResults.addElement(tmp); } @@ -324,18 +323,17 @@ public class JDesktopPane extends JLayeredPane implements Accessible public JInternalFrame[] getAllFramesInLayer(int layer) { int i, count; JInternalFrame[] results; - Vector vResults = new Vector(10); - Object next, tmp; + Vector vResults = new Vector(10); count = getComponentCount(); for(i = 0; i < count; i++) { - next = getComponent(i); + Component next = getComponent(i); if(next instanceof JInternalFrame) { if(((JInternalFrame)next).getLayer() == layer) - vResults.addElement(next); + vResults.addElement((JInternalFrame) next); } else if(next instanceof JInternalFrame.JDesktopIcon) { - tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame(); - if(tmp != null && ((JInternalFrame)tmp).getLayer() == layer) + JInternalFrame tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame(); + if(tmp != null && tmp.getLayer() == layer) vResults.addElement(tmp); } } diff --git a/src/share/classes/javax/swing/JDialog.java b/src/share/classes/javax/swing/JDialog.java index ac2a24ecc0636f721da64d14b8a7475cca5a82a0..7964094908402159ae16d136b654999e2ab61319 100644 --- a/src/share/classes/javax/swing/JDialog.java +++ b/src/share/classes/javax/swing/JDialog.java @@ -277,7 +277,7 @@ public class JDialog extends Dialog implements WindowConstants, title, modal); if (owner == null) { WindowListener ownerShutdownListener = - (WindowListener)SwingUtilities.getSharedOwnerFrameShutdownListener(); + SwingUtilities.getSharedOwnerFrameShutdownListener(); addWindowListener(ownerShutdownListener); } dialogInit(); @@ -329,7 +329,7 @@ public class JDialog extends Dialog implements WindowConstants, title, modal, gc); if (owner == null) { WindowListener ownerShutdownListener = - (WindowListener)SwingUtilities.getSharedOwnerFrameShutdownListener(); + SwingUtilities.getSharedOwnerFrameShutdownListener(); addWindowListener(ownerShutdownListener); } dialogInit(); diff --git a/src/share/classes/javax/swing/JEditorPane.java b/src/share/classes/javax/swing/JEditorPane.java index 4d70cacb7b245b5bf99d0fd2d2354cd44687b21b..21528752fd5f1c5c5f9ff9503443aacb9c4c05f5 100644 --- a/src/share/classes/javax/swing/JEditorPane.java +++ b/src/share/classes/javax/swing/JEditorPane.java @@ -319,8 +319,7 @@ public class JEditorPane extends JTextComponent { * @since 1.4 */ public synchronized HyperlinkListener[] getHyperlinkListeners() { - return (HyperlinkListener[])listenerList.getListeners( - HyperlinkListener.class); + return listenerList.getListeners(javax.swing.event.HyperlinkListener.class); } /** @@ -492,8 +491,8 @@ public class JEditorPane extends JTextComponent { if (pageProperties != null) { // transfer properties discovered in stream to the // document property collection. - for (Enumeration e = pageProperties.keys(); e.hasMoreElements() ;) { - Object key = e.nextElement(); + for (Enumeration e = pageProperties.keys(); e.hasMoreElements() ;) { + String key = e.nextElement(); doc.putProperty(key, pageProperties.get(key)); } pageProperties.clear(); @@ -775,7 +774,7 @@ public class JEditorPane extends JTextComponent { */ private void handleConnectionProperties(URLConnection conn) { if (pageProperties == null) { - pageProperties = new Hashtable(); + pageProperties = new Hashtable(); } String type = conn.getContentType(); if (type != null) { @@ -989,7 +988,7 @@ public class JEditorPane extends JTextComponent { * of the content type in the http header information. */ private void setCharsetFromContentTypeParameters(String paramlist) { - String charset = null; + String charset; try { // paramlist is handed to us with a leading ';', strip it. int semi = paramlist.indexOf(';'); @@ -1080,9 +1079,9 @@ public class JEditorPane extends JTextComponent { */ public EditorKit getEditorKitForContentType(String type) { if (typeHandlers == null) { - typeHandlers = new Hashtable(3); + typeHandlers = new Hashtable(3); } - EditorKit k = (EditorKit) typeHandlers.get(type); + EditorKit k = typeHandlers.get(type); if (k == null) { k = createEditorKitForContentType(type); if (k != null) { @@ -1106,7 +1105,7 @@ public class JEditorPane extends JTextComponent { */ public void setEditorKitForContentType(String type, EditorKit k) { if (typeHandlers == null) { - typeHandlers = new Hashtable(3); + typeHandlers = new Hashtable(3); } typeHandlers.put(type, k); } @@ -1176,13 +1175,12 @@ public class JEditorPane extends JTextComponent { * registered for the given type */ public static EditorKit createEditorKitForContentType(String type) { - EditorKit k = null; - Hashtable kitRegistry = getKitRegisty(); - k = (EditorKit) kitRegistry.get(type); + Hashtable kitRegistry = getKitRegisty(); + EditorKit k = kitRegistry.get(type); if (k == null) { // try to dynamically load the support - String classname = (String) getKitTypeRegistry().get(type); - ClassLoader loader = (ClassLoader) getKitLoaderRegistry().get(type); + String classname = getKitTypeRegistry().get(type); + ClassLoader loader = getKitLoaderRegistry().get(type); try { Class c; if (loader != null) { @@ -1252,20 +1250,20 @@ public class JEditorPane extends JTextComponent { * @since 1.3 */ public static String getEditorKitClassNameForContentType(String type) { - return (String)getKitTypeRegistry().get(type); + return getKitTypeRegistry().get(type); } - private static Hashtable getKitTypeRegistry() { + private static Hashtable getKitTypeRegistry() { loadDefaultKitsIfNecessary(); return (Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey); } - private static Hashtable getKitLoaderRegistry() { + private static Hashtable getKitLoaderRegistry() { loadDefaultKitsIfNecessary(); return (Hashtable)SwingUtilities.appContextGet(kitLoaderRegistryKey); } - private static Hashtable getKitRegisty() { + private static Hashtable getKitRegisty() { Hashtable ht = (Hashtable)SwingUtilities.appContextGet(kitRegistryKey); if (ht == null) { ht = new Hashtable(3); @@ -1512,7 +1510,7 @@ public class JEditorPane extends JTextComponent { private EditorKit kit; private boolean isUserSetEditorKit; - private Hashtable pageProperties; + private Hashtable pageProperties; /** Should be kept in sync with javax.swing.text.html.FormView counterpart. */ final static String PostDataProperty = "javax.swing.JEditorPane.postdata"; @@ -1520,7 +1518,7 @@ public class JEditorPane extends JTextComponent { /** * Table of registered type handlers for this editor. */ - private Hashtable typeHandlers; + private Hashtable typeHandlers; /* * Private AppContext keys for this class's static variables. @@ -1913,11 +1911,11 @@ public class JEditorPane extends JTextComponent { } } - private class LinkVector extends Vector { + private class LinkVector extends Vector { public int baseElementIndex(Element e) { HTMLLink l; for (int i = 0; i < elementCount; i++) { - l = (HTMLLink) elementAt(i); + l = elementAt(i); if (l.element == e) { return i; } @@ -2029,7 +2027,7 @@ public class JEditorPane extends JTextComponent { buildLinkTable(); } if (linkIndex >= 0 && linkIndex < hyperlinks.size()) { - return (AccessibleHyperlink) hyperlinks.elementAt(linkIndex); + return hyperlinks.elementAt(linkIndex); } else { return null; } diff --git a/src/share/classes/javax/swing/JFileChooser.java b/src/share/classes/javax/swing/JFileChooser.java index 4a213df6273c850ed926a9240f8c6e9afce66571..82c85fe9faa00f6f9c78c4e38aca4717cc2494d4 100644 --- a/src/share/classes/javax/swing/JFileChooser.java +++ b/src/share/classes/javax/swing/JFileChooser.java @@ -248,7 +248,7 @@ public class JFileChooser extends JComponent implements Accessible { private String approveButtonToolTipText = null; private int approveButtonMnemonic = 0; - private Vector filters = new Vector(5); + private Vector filters = new Vector(5); private JDialog dialog = null; private int dialogType = OPEN_DIALOG; private int returnValue = ERROR_OPTION; @@ -503,7 +503,7 @@ public class JFileChooser extends JComponent implements Accessible { if(selectedFiles == null) { return new File[0]; } else { - return (File[]) selectedFiles.clone(); + return selectedFiles.clone(); } } @@ -1415,17 +1415,17 @@ public class JFileChooser extends JComponent implements Accessible { fileFilter = filter; if (filter != null) { if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) { - Vector fList = new Vector(); + Vector fList = new Vector(); boolean failed = false; - for (int i = 0; i < selectedFiles.length; i++) { - if (filter.accept(selectedFiles[i])) { - fList.add(selectedFiles[i]); + for (File file : selectedFiles) { + if (filter.accept(file)) { + fList.add(file); } else { failed = true; } } if (failed) { - setSelectedFiles((fList.size() == 0) ? null : (File[])fList.toArray(new File[fList.size()])); + setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()])); } } else if (selectedFile != null && !filter.accept(selectedFile)) { setSelectedFile(null); @@ -1702,8 +1702,7 @@ public class JFileChooser extends JComponent implements Accessible { * @since 1.4 */ public ActionListener[] getActionListeners() { - return (ActionListener[])listenerList.getListeners( - ActionListener.class); + return listenerList.getListeners(ActionListener.class); } /** @@ -1744,7 +1743,7 @@ public class JFileChooser extends JComponent implements Accessible { WeakReference jfcRef; public WeakPCL(JFileChooser jfc) { - jfcRef = new WeakReference(jfc); + jfcRef = new WeakReference(jfc); } public void propertyChange(PropertyChangeEvent ev) { assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP); diff --git a/src/share/classes/javax/swing/JInternalFrame.java b/src/share/classes/javax/swing/JInternalFrame.java index c3e3cad1c1195f5bdbb0faddc967971e5c2daa72..837ffe49e4f4768359eccc6de58d4b70eba6a3d9 100644 --- a/src/share/classes/javax/swing/JInternalFrame.java +++ b/src/share/classes/javax/swing/JInternalFrame.java @@ -421,8 +421,8 @@ public class JInternalFrame extends JComponent implements invalidate(); Component[] children = getComponents(); if (children != null) { - for(int i = 0; i < children.length; i++) { - SwingUtilities.updateComponentTreeUI(children[i]); + for (Component child : children) { + SwingUtilities.updateComponentTreeUI(child); } } } @@ -1535,8 +1535,7 @@ public class JInternalFrame extends JComponent implements * @see #addInternalFrameListener */ public InternalFrameListener[] getInternalFrameListeners() { - return (InternalFrameListener[])listenerList.getListeners( - InternalFrameListener.class); + return listenerList.getListeners(InternalFrameListener.class); } // remind: name ok? all one method ok? need to be synchronized? @@ -2258,8 +2257,8 @@ public class JInternalFrame extends JComponent implements invalidate(); Component[] children = getComponents(); if (children != null) { - for(int i = 0; i < children.length; i++) { - SwingUtilities.updateComponentTreeUI(children[i]); + for (Component child : children) { + SwingUtilities.updateComponentTreeUI(child); } } } diff --git a/src/share/classes/javax/swing/JLayeredPane.java b/src/share/classes/javax/swing/JLayeredPane.java index b3cedb2d37e8793fed6ec3bc15d4709e05024f8b..e971fe1d8efe214df6d8c776ae665eb372d6e0de 100644 --- a/src/share/classes/javax/swing/JLayeredPane.java +++ b/src/share/classes/javax/swing/JLayeredPane.java @@ -191,7 +191,7 @@ public class JLayeredPane extends JComponent implements Accessible { private void validateOptimizedDrawing() { boolean layeredComponentFound = false; synchronized(getTreeLock()) { - Integer layer = null; + Integer layer; for (Component c : getComponents()) { layer = null; @@ -213,7 +213,7 @@ public class JLayeredPane extends JComponent implements Accessible { } protected void addImpl(Component comp, Object constraints, int index) { - int layer = DEFAULT_LAYER.intValue(); + int layer; int pos; if(constraints instanceof Integer) { @@ -364,7 +364,7 @@ public class JLayeredPane extends JComponent implements Accessible { if(c instanceof JComponent) ((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj); else - getComponentToLayer().put((Component)c, layerObj); + getComponentToLayer().put(c, layerObj); if(c.getParent() == null || c.getParent() != this) { repaint(c.getBounds()); @@ -388,7 +388,7 @@ public class JLayeredPane extends JComponent implements Accessible { if(c instanceof JComponent) i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY); else - i = (Integer)getComponentToLayer().get((Component)c); + i = getComponentToLayer().get(c); if(i == null) return DEFAULT_LAYER.intValue(); @@ -465,9 +465,9 @@ public class JLayeredPane extends JComponent implements Accessible { * @see #getComponentCountInLayer */ public int getPosition(Component c) { - int i, count, startLayer, curLayer, startLocation, pos = 0; + int i, startLayer, curLayer, startLocation, pos = 0; - count = getComponentCount(); + getComponentCount(); startLocation = getIndexOf(c); if(startLocation == -1) diff --git a/src/share/classes/javax/swing/JList.java b/src/share/classes/javax/swing/JList.java index a83a4c94e4c560cef9b819d4d79a3d5858cdba35..772c7554056dd27892f44f76fa5b2f664e858a09 100644 --- a/src/share/classes/javax/swing/JList.java +++ b/src/share/classes/javax/swing/JList.java @@ -1848,8 +1848,7 @@ public class JList extends JComponent implements Scrollable, Accessible * @since 1.4 */ public ListSelectionListener[] getListSelectionListeners() { - return (ListSelectionListener[])listenerList.getListeners( - ListSelectionListener.class); + return listenerList.getListeners(ListSelectionListener.class); } @@ -2220,9 +2219,9 @@ public class JList extends JComponent implements Scrollable, Accessible ListSelectionModel sm = getSelectionModel(); sm.clearSelection(); int size = getModel().getSize(); - for(int i = 0; i < indices.length; i++) { - if (indices[i] < size) { - sm.addSelectionInterval(indices[i], indices[i]); + for (int i : indices) { + if (i < size) { + sm.addSelectionInterval(i, i); } } } @@ -2724,7 +2723,7 @@ public class JList extends JComponent implements Scrollable, Accessible return true; } if (getParent() instanceof JViewport) { - return (((JViewport)getParent()).getWidth() > getPreferredSize().width); + return (getParent().getWidth() > getPreferredSize().width); } return false; } @@ -2749,7 +2748,7 @@ public class JList extends JComponent implements Scrollable, Accessible return true; } if (getParent() instanceof JViewport) { - return (((JViewport)getParent()).getHeight() > getPreferredSize().height); + return (getParent().getHeight() > getPreferredSize().height); } return false; } @@ -3161,7 +3160,7 @@ public class JList extends JComponent implements Scrollable, Accessible private AccessibleContext getCurrentAccessibleContext() { Component c = getComponentAtIndex(indexInParent); if (c instanceof Accessible) { - return ((Accessible) c).getAccessibleContext(); + return c.getAccessibleContext(); } else { return null; } diff --git a/src/share/classes/javax/swing/JMenu.java b/src/share/classes/javax/swing/JMenu.java index ed90cb73eecf16f199ccb8ae799ebc0ebad99e1d..cf069116c2163f0b5ed43b7068c8314e724543eb 100644 --- a/src/share/classes/javax/swing/JMenu.java +++ b/src/share/classes/javax/swing/JMenu.java @@ -371,8 +371,8 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @since 1.3 */ protected Point getPopupMenuOrigin() { - int x = 0; - int y = 0; + int x; + int y; JPopupMenu pm = getPopupMenu(); // Figure out the sizes needed to caclulate the menu position Dimension s = getSize(); @@ -900,10 +900,8 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * on another menu */ public boolean isTopLevelMenu() { - if (getParent() instanceof JMenuBar) - return true; + return getParent() instanceof JMenuBar; - return false; } /** @@ -1015,7 +1013,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @since 1.4 */ public MenuListener[] getMenuListeners() { - return (MenuListener[])listenerList.getListeners(MenuListener.class); + return listenerList.getListeners(MenuListener.class); } /** @@ -1305,7 +1303,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @return the array of menu items */ private MenuElement[] buildMenuElementArray(JMenu leaf) { - Vector elements = new Vector(); + Vector elements = new Vector(); Component current = leaf.getPopupMenu(); JPopupMenu pop; JMenu menu; @@ -1409,8 +1407,8 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement public int getAccessibleChildrenCount() { Component[] children = getMenuComponents(); int count = 0; - for (int j = 0; j < children.length; j++) { - if (children[j] instanceof Accessible) { + for (Component child : children) { + if (child instanceof Accessible) { count++; } } @@ -1426,18 +1424,18 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement public Accessible getAccessibleChild(int i) { Component[] children = getMenuComponents(); int count = 0; - for (int j = 0; j < children.length; j++) { - if (children[j] instanceof Accessible) { + for (Component child : children) { + if (child instanceof Accessible) { if (count == i) { - if (children[j] instanceof JComponent) { + if (child instanceof JComponent) { // FIXME: [[[WDW - probably should set this when // the component is added to the menu. I tried // to do this in most cases, but the separators // added by addSeparator are hard to get to.]]] - AccessibleContext ac = ((Accessible) children[j]).getAccessibleContext(); + AccessibleContext ac = child.getAccessibleContext(); ac.setAccessibleParent(JMenu.this); } - return (Accessible) children[j]; + return (Accessible) child; } else { count++; } @@ -1581,7 +1579,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement } JMenuItem mi = getItem(i); if (mi != null && mi instanceof JMenu) { - if (((JMenu) mi).isSelected()) { + if (mi.isSelected()) { MenuElement old[] = MenuSelectionManager.defaultManager().getSelectedPath(); MenuElement me[] = new MenuElement[old.length-2]; diff --git a/src/share/classes/javax/swing/JMenuBar.java b/src/share/classes/javax/swing/JMenuBar.java index d6f04fbb42755dee5eb5331c2085219ea4ff40c6..724eba6b8ff788ce48940af6c3bb43780fa55fdc 100644 --- a/src/share/classes/javax/swing/JMenuBar.java +++ b/src/share/classes/javax/swing/JMenuBar.java @@ -414,7 +414,7 @@ public class JMenuBar extends JComponent implements Accessible,MenuElement */ public MenuElement[] getSubElements() { MenuElement result[]; - Vector tmp = new Vector(); + Vector tmp = new Vector(); int c = getComponentCount(); int i; Component m; @@ -422,12 +422,12 @@ public class JMenuBar extends JComponent implements Accessible,MenuElement for(i=0 ; i < c ; i++) { m = getComponent(i); if(m instanceof MenuElement) - tmp.addElement(m); + tmp.addElement((MenuElement) m); } result = new MenuElement[tmp.size()]; for(i=0,c=tmp.size() ; i < c ; i++) - result[i] = (MenuElement) tmp.elementAt(i); + result[i] = tmp.elementAt(i); return result; } @@ -664,9 +664,9 @@ public class JMenuBar extends JComponent implements Accessible,MenuElement boolean retValue = super.processKeyBinding(ks, e, condition, pressed); if (!retValue) { MenuElement[] subElements = getSubElements(); - for (int i=0; i values = new Vector(); s.defaultWriteObject(); // Save the icon, if its Serializable. @@ -2342,7 +2339,7 @@ public class JOptionPane extends JComponent implements Accessible } // Save the treeModel, if its Serializable. if(options != null) { - Vector serOptions = new Vector(); + Vector serOptions = new Vector(); for(int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) @@ -2510,16 +2507,16 @@ public class JOptionPane extends JComponent implements Accessible /** * Retrieves a method from the provided class and makes it accessible. */ - private static class ModalPrivilegedAction implements PrivilegedAction { - private Class clazz; + private static class ModalPrivilegedAction implements PrivilegedAction { + private Class clazz; private String methodName; - public ModalPrivilegedAction(Class clazz, String methodName) { + public ModalPrivilegedAction(Class clazz, String methodName) { this.clazz = clazz; this.methodName = methodName; } - public Object run() { + public Method run() { Method method = null; try { method = clazz.getDeclaredMethod(methodName, (Class[])null); diff --git a/src/share/classes/javax/swing/JPopupMenu.java b/src/share/classes/javax/swing/JPopupMenu.java index 83aec9a17b363783209e2c994b3dfa8a28910018..8f90a02a2a9670157c51d98fe92d20cb36db1938 100644 --- a/src/share/classes/javax/swing/JPopupMenu.java +++ b/src/share/classes/javax/swing/JPopupMenu.java @@ -584,7 +584,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { int nitems = getComponentCount(); // PENDING(ges): Why not use an array? - Vector tempItems = new Vector(); + Vector tempItems = new Vector(); /* Remove the item at index, nitems-index times storing them in a temporary vector in the @@ -600,8 +600,8 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { /* Add the removed items back to the menu, they are already in the correct order in the temp vector. */ - for (int i = 0; i < tempItems.size() ; i++) { - add((Component)tempItems.elementAt(i)); + for (Component tempItem : tempItems) { + add(tempItem); } } @@ -632,8 +632,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * @since 1.4 */ public PopupMenuListener[] getPopupMenuListeners() { - return (PopupMenuListener[])listenerList.getListeners( - PopupMenuListener.class); + return listenerList.getListeners(PopupMenuListener.class); } /** @@ -665,8 +664,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * @since 1.5 */ public MenuKeyListener[] getMenuKeyListeners() { - return (MenuKeyListener[])listenerList.getListeners( - MenuKeyListener.class); + return listenerList.getListeners(MenuKeyListener.class); } /** @@ -781,7 +779,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { // set selection path before popping up! if (isPopupMenu()) { MenuElement me[] = new MenuElement[1]; - me[0] = (MenuElement) this; + me[0] = this; MenuSelectionManager.defaultManager().setSelectedPath(me); } } @@ -848,10 +846,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * being displayed). */ public boolean isVisible() { - if(popup != null) - return true; - else - return false; + return popup != null; } /** @@ -1311,7 +1306,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { // Serialization support. //////////// private void writeObject(ObjectOutputStream s) throws IOException { - Vector values = new Vector(); + Vector values = new Vector(); s.defaultWriteObject(); // Save the invoker, if its Serializable. @@ -1494,7 +1489,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { */ public MenuElement[] getSubElements() { MenuElement result[]; - Vector tmp = new Vector(); + Vector tmp = new Vector(); int c = getComponentCount(); int i; Component m; @@ -1502,12 +1497,12 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { for(i=0 ; i < c ; i++) { m = getComponent(i); if(m instanceof MenuElement) - tmp.addElement(m); + tmp.addElement((MenuElement) m); } result = new MenuElement[tmp.size()]; for(i=0,c=tmp.size() ; i < c ; i++) - result[i] = (MenuElement) tmp.elementAt(i); + result[i] = tmp.elementAt(i); return result; } diff --git a/src/share/classes/javax/swing/JProgressBar.java b/src/share/classes/javax/swing/JProgressBar.java index b1d27c8cd0299118379e5141c03a520d8148e9cf..9ba25d96cea41492f9c05fcfb5b4b01b8e8b9eb4 100644 --- a/src/share/classes/javax/swing/JProgressBar.java +++ b/src/share/classes/javax/swing/JProgressBar.java @@ -699,8 +699,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** diff --git a/src/share/classes/javax/swing/JScrollBar.java b/src/share/classes/javax/swing/JScrollBar.java index 5897fd6fad8f3e6a23362df89007b59d8e779929..90e2cc7595f29af24bc28a3a83b6ae690cf43062 100644 --- a/src/share/classes/javax/swing/JScrollBar.java +++ b/src/share/classes/javax/swing/JScrollBar.java @@ -659,8 +659,7 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible * @since 1.4 */ public AdjustmentListener[] getAdjustmentListeners() { - return (AdjustmentListener[])listenerList.getListeners( - AdjustmentListener.class); + return listenerList.getListeners(AdjustmentListener.class); } @@ -754,8 +753,8 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible public void setEnabled(boolean x) { super.setEnabled(x); Component[] children = getComponents(); - for(int i = 0; i < children.length; i++) { - children[i].setEnabled(x); + for (Component child : children) { + child.setEnabled(x); } } diff --git a/src/share/classes/javax/swing/JSlider.java b/src/share/classes/javax/swing/JSlider.java index ea2b510be1d3c55d3eaba303a9fdc759e9152004..c014f170b3594c6a509477740635167ee470badb 100644 --- a/src/share/classes/javax/swing/JSlider.java +++ b/src/share/classes/javax/swing/JSlider.java @@ -270,8 +270,7 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { { checkOrientation(orientation); this.orientation = orientation; - sliderModel = new DefaultBoundedRangeModel(value, 0, min, max); - sliderModel.addChangeListener(changeListener); + setModel(new DefaultBoundedRangeModel(value, 0, min, max)); updateUI(); } @@ -284,7 +283,6 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { { this.orientation = JSlider.HORIZONTAL; setModel(brm); - sliderModel.addChangeListener(changeListener); updateUI(); } @@ -476,15 +474,15 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { if (newModel != null) { newModel.addChangeListener(changeListener); + } - if (accessibleContext != null) { - accessibleContext.firePropertyChange( - AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, - (oldModel == null - ? null : Integer.valueOf(oldModel.getValue())), - (newModel == null - ? null : Integer.valueOf(newModel.getValue()))); - } + if (accessibleContext != null) { + accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, + (oldModel == null + ? null : Integer.valueOf(oldModel.getValue())), + (newModel == null + ? null : Integer.valueOf(newModel.getValue()))); } firePropertyChange("model", oldModel, sliderModel); @@ -930,7 +928,7 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { throw new IllegalArgumentException( "Label incremement must be > 0" ); } - class SmartHashtable extends Hashtable implements PropertyChangeListener { + class SmartHashtable extends Hashtable implements PropertyChangeListener { int increment = 0; int start = 0; boolean startAtMin = false; @@ -977,9 +975,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { if ( e.getPropertyName().equals( "minimum" ) || e.getPropertyName().equals( "maximum" ) ) { - Dictionary labelTable = getLabelTable(); - Enumeration keys = labelTable.keys(); - Hashtable hashtable = new Hashtable(); + Enumeration keys = getLabelTable().keys(); + Hashtable hashtable = new Hashtable(); // Save the labels that were added by the developer while ( keys.hasMoreElements() ) { diff --git a/src/share/classes/javax/swing/JSpinner.java b/src/share/classes/javax/swing/JSpinner.java index dd573e104572d5c9dcaecb07e8616af54246c5cb..c5cebda03f7cd153498476eb0d825bffbb99b8ce 100644 --- a/src/share/classes/javax/swing/JSpinner.java +++ b/src/share/classes/javax/swing/JSpinner.java @@ -433,8 +433,7 @@ public class JSpinner extends JComponent implements Accessible * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } @@ -1536,7 +1535,7 @@ public class JSpinner extends JComponent implements Accessible return textField.getAccessibleContext(); } } else if (editor instanceof Accessible) { - return ((Accessible)editor).getAccessibleContext(); + return editor.getAccessibleContext(); } return null; } @@ -1693,7 +1692,7 @@ public class JSpinner extends JComponent implements Accessible if (i < 0 || i > 1) { return false; } - Object o = null; + Object o; if (i == 0) { o = getNextValue(); // AccessibleAction.INCREMENT } else { diff --git a/src/share/classes/javax/swing/JTabbedPane.java b/src/share/classes/javax/swing/JTabbedPane.java index 9bcafb1ab328b5fe8f86980edda0e29eea9fb6c5..2c74189fd33e1eaa141d56dade872ea2d9aed23d 100644 --- a/src/share/classes/javax/swing/JTabbedPane.java +++ b/src/share/classes/javax/swing/JTabbedPane.java @@ -313,8 +313,7 @@ public class JTabbedPane extends JComponent * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** @@ -2062,7 +2061,7 @@ public class JTabbedPane extends JComponent * Accessibility classes unnecessarily. */ AccessibleContext ac; - ac = ((Accessible) component).getAccessibleContext(); + ac = component.getAccessibleContext(); if (ac != null) { ac.setAccessibleParent(this); } diff --git a/src/share/classes/javax/swing/JTable.java b/src/share/classes/javax/swing/JTable.java index 976cb8130936c41c7ec4df6d77b9bf9d5705a00d..1b770d89153affe5ed6ca4b75cef929b0596bbbc 100644 --- a/src/share/classes/javax/swing/JTable.java +++ b/src/share/classes/javax/swing/JTable.java @@ -1677,16 +1677,16 @@ public class JTable extends JComponent implements TableModelListener, Scrollable if (!forDrop && state != null) { clearSelection(); - int[] rows = (int[])((int[][])state)[0]; - int[] cols = (int[])((int[][])state)[1]; - int[] anchleads = (int[])((int[][])state)[2]; + int[] rows = ((int[][])state)[0]; + int[] cols = ((int[][])state)[1]; + int[] anchleads = ((int[][])state)[2]; - for (int i = 0; i < rows.length; i++) { - addRowSelectionInterval(rows[i], rows[i]); + for (int row : rows) { + addRowSelectionInterval(row, row); } - for (int i = 0; i < cols.length; i++) { - addColumnSelectionInterval(cols[i], cols[i]); + for (int col : cols) { + addColumnSelectionInterval(col, col); } SwingUtilities2.setLeadAnchorWithoutSelection( @@ -1776,7 +1776,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable boolean oldValue = this.autoCreateRowSorter; this.autoCreateRowSorter = autoCreateRowSorter; if (autoCreateRowSorter) { - setRowSorter(new TableRowSorter(getModel())); + setRowSorter(new TableRowSorter(getModel())); } firePropertyChange("autoCreateRowSorter", oldValue, autoCreateRowSorter); @@ -3198,7 +3198,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable private void accommodateDelta(int resizingColumnIndex, int delta) { int columnCount = getColumnCount(); int from = resizingColumnIndex; - int to = columnCount; + int to; // Use the mode to determine how to absorb the changes. switch(autoResizeMode) { @@ -3237,8 +3237,6 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } adjustSizes(totalWidth + delta, r, false); - - return; } private interface Resizable2 { @@ -3492,7 +3490,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #editingRow */ public boolean isEditing() { - return (cellEditor == null)? false : true; + return cellEditor != null; } /** @@ -3642,7 +3640,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable firePropertyChange("model", old, dataModel); if (getAutoCreateRowSorter()) { - setRowSorter(new TableRowSorter(dataModel)); + setRowSorter(new TableRowSorter(dataModel)); } } } @@ -5160,7 +5158,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable public boolean getScrollableTracksViewportHeight() { return getFillsViewportHeight() && getParent() instanceof JViewport - && (((JViewport)getParent()).getHeight() > getPreferredSize().height); + && (getParent().getHeight() > getPreferredSize().height); } /** @@ -5214,7 +5212,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // by setting the client property JTable.autoStartsEdit to Boolean.FALSE. if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT && isFocusOwner() && - !Boolean.FALSE.equals((Boolean)getClientProperty("JTable.autoStartsEdit"))) { + !Boolean.FALSE.equals(getClientProperty("JTable.autoStartsEdit"))) { // We do not have a binding for the event. Component editorComponent = getEditorComponent(); if (editorComponent == null) { @@ -5436,7 +5434,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable this.value = null; ((JComponent)getComponent()).setBorder(new LineBorder(Color.black)); try { - Class type = table.getColumnClass(column); + Class type = table.getColumnClass(column); // Since our obligation is to produce a value which is // assignable for the required type it is OK to use the // String constructor for columns which are declared @@ -6627,10 +6625,10 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } else if (name.compareTo("tableCellEditor") == 0) { if (oldValue != null && oldValue instanceof TableCellEditor) { - ((TableCellEditor) oldValue).removeCellEditorListener((CellEditorListener) this); + ((TableCellEditor) oldValue).removeCellEditorListener(this); } if (newValue != null && newValue instanceof TableCellEditor) { - ((TableCellEditor) newValue).addCellEditorListener((CellEditorListener) this); + ((TableCellEditor) newValue).addCellEditorListener(this); } } } @@ -7045,7 +7043,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable */ public Accessible getAccessibleSelection(int i) { if (i < 0 || i > getAccessibleSelectionCount()) { - return (Accessible) null; + return null; } int rowsSel = JTable.this.getSelectedRowCount(); @@ -7158,7 +7156,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable return getAccessibleChild((r * ttlCols) + c); } } - return (Accessible) null; + return null; } /** @@ -7906,7 +7904,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable JTable.this, getValueAt(row, column), false, false, row, column); if (component instanceof Accessible) { - return ((Accessible) component).getAccessibleContext(); + return component.getAccessibleContext(); } else { return null; } diff --git a/src/share/classes/javax/swing/JTextField.java b/src/share/classes/javax/swing/JTextField.java index b6d3b47f2851e35329985e86e94ec08229b420c0..56ca320a746ebe6f3835ddf1456c6af49e529a65 100644 --- a/src/share/classes/javax/swing/JTextField.java +++ b/src/share/classes/javax/swing/JTextField.java @@ -475,8 +475,7 @@ public class JTextField extends JTextComponent implements SwingConstants { * @since 1.4 */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[])listenerList.getListeners( - ActionListener.class); + return listenerList.getListeners(ActionListener.class); } /** diff --git a/src/share/classes/javax/swing/JTree.java b/src/share/classes/javax/swing/JTree.java index e6aa08c054eb01663e5aebdfc0dfb6587aa21137..012db5063dc5463b3bce56b58ca559262cc1ecc6 100644 --- a/src/share/classes/javax/swing/JTree.java +++ b/src/share/classes/javax/swing/JTree.java @@ -187,7 +187,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * information must be determined by visiting all the parent * paths and seeing if they are visible. */ - transient private Hashtable expandedState; + transient private Hashtable expandedState; /** @@ -281,7 +281,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * Used when setExpandedState is invoked, * will be a Stack of Stacks. */ - transient private Stack expandedStack; + transient private Stack> expandedStack; /** * Lead selection path, may not be null. @@ -652,9 +652,9 @@ public class JTree extends JComponent implements Scrollable, Accessible @ConstructorProperties({"model"}) public JTree(TreeModel newModel) { super(); - expandedStack = new Stack(); + expandedStack = new Stack>(); toggleClickCount = 2; - expandedState = new Hashtable(); + expandedState = new Hashtable(); setLayout(null); rowHeight = 16; visibleRowCount = 20; @@ -691,7 +691,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * description: The UI object that implements the Component's LookAndFeel. */ public void setUI(TreeUI ui) { - if ((TreeUI)this.ui != ui) { + if (this.ui != ui) { settingUI = true; uiTreeExpansionListener = null; try { @@ -1298,8 +1298,8 @@ public class JTree extends JComponent implements Scrollable, Accessible Object root = (model == null) ? null : model.getRoot(); TreePath rootPath = (root == null) ? null : new TreePath(root); - TreePath child = null; - TreePath parent = null; + TreePath child; + TreePath parent; boolean outside = row == -1 || p.y < bounds.y || p.y >= bounds.y + bounds.height; @@ -1940,14 +1940,14 @@ public class JTree extends JComponent implements Scrollable, Accessible if(!isExpanded(parent)) return null; - Enumeration toggledPaths = expandedState.keys(); - Vector elements = null; + Enumeration toggledPaths = expandedState.keys(); + Vector elements = null; TreePath path; Object value; if(toggledPaths != null) { while(toggledPaths.hasMoreElements()) { - path = (TreePath)toggledPaths.nextElement(); + path = toggledPaths.nextElement(); value = expandedState.get(path); // Add the path if it is expanded, a descendant of parent, // and it is visible (all parents expanded). This is rather @@ -1956,7 +1956,7 @@ public class JTree extends JComponent implements Scrollable, Accessible ((Boolean)value).booleanValue() && parent.isDescendant(path) && isVisible(path)) { if (elements == null) { - elements = new Vector(); + elements = new Vector(); } elements.addElement(path); } @@ -1990,9 +1990,9 @@ public class JTree extends JComponent implements Scrollable, Accessible return false; // Is this node expanded? - Object value = expandedState.get(path); + Boolean value = expandedState.get(path); - if(value == null || !((Boolean)value).booleanValue()) + if(value == null || !value.booleanValue()) return false; // It is, make sure its parent is also expanded. @@ -2018,7 +2018,7 @@ public class JTree extends JComponent implements Scrollable, Accessible TreePath path = tree.getPathForRow(this, row); if(path != null) { - Boolean value = (Boolean)expandedState.get(path); + Boolean value = expandedState.get(path); return (value != null && value.booleanValue()); } @@ -2704,8 +2704,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * @since 1.4 */ public TreeExpansionListener[] getTreeExpansionListeners() { - return (TreeExpansionListener[])listenerList.getListeners( - TreeExpansionListener.class); + return listenerList.getListeners(TreeExpansionListener.class); } /** @@ -2737,8 +2736,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * @since 1.4 */ public TreeWillExpandListener[] getTreeWillExpandListeners() { - return (TreeWillExpandListener[])listenerList.getListeners( - TreeWillExpandListener.class); + return listenerList.getListeners(TreeWillExpandListener.class); } /** @@ -2895,8 +2893,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * @since 1.4 */ public TreeSelectionListener[] getTreeSelectionListeners() { - return (TreeSelectionListener[])listenerList.getListeners( - TreeSelectionListener.class); + return listenerList.getListeners(TreeSelectionListener.class); } /** @@ -3030,7 +3027,7 @@ public class JTree extends JComponent implements Scrollable, Accessible // Serialization support. private void writeObject(ObjectOutputStream s) throws IOException { - Vector values = new Vector(); + Vector values = new Vector(); s.defaultWriteObject(); // Save the cellRenderer, if its Serializable. @@ -3077,9 +3074,9 @@ public class JTree extends JComponent implements Scrollable, Accessible // Create an instance of expanded state. - expandedState = new Hashtable(); + expandedState = new Hashtable(); - expandedStack = new Stack(); + expandedStack = new Stack>(); Vector values = (Vector)s.readObject(); int indexCounter = 0; @@ -3132,13 +3129,13 @@ public class JTree extends JComponent implements Scrollable, Accessible TreeModel model = getModel(); if(model != null) { - Enumeration paths = expandedState.keys(); + Enumeration paths = expandedState.keys(); if(paths != null) { - Vector state = new Vector(); + Vector state = new Vector(); while(paths.hasMoreElements()) { - TreePath path = (TreePath)paths.nextElement(); + TreePath path = paths.nextElement(); Object archivePath; try { @@ -3502,7 +3499,7 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public boolean getScrollableTracksViewportWidth() { if (getParent() instanceof JViewport) { - return (((JViewport)getParent()).getWidth() > getPreferredSize().width); + return getParent().getWidth() > getPreferredSize().width; } return false; } @@ -3518,7 +3515,7 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public boolean getScrollableTracksViewportHeight() { if (getParent() instanceof JViewport) { - return (((JViewport)getParent()).getHeight() > getPreferredSize().height); + return getParent().getHeight() > getPreferredSize().height; } return false; } @@ -3535,14 +3532,14 @@ public class JTree extends JComponent implements Scrollable, Accessible protected void setExpandedState(TreePath path, boolean state) { if(path != null) { // Make sure all parents of path are expanded. - Stack stack; - TreePath parentPath = path.getParentPath(); + Stack stack; + TreePath parentPath = path.getParentPath(); if (expandedStack.size() == 0) { - stack = new Stack(); + stack = new Stack(); } else { - stack = (Stack)expandedStack.pop(); + stack = expandedStack.pop(); } try { @@ -3556,7 +3553,7 @@ public class JTree extends JComponent implements Scrollable, Accessible } } for(int counter = stack.size() - 1; counter >= 0; counter--) { - parentPath = (TreePath)stack.pop(); + parentPath = stack.pop(); if(!isExpanded(parentPath)) { try { fireTreeWillExpand(parentPath); @@ -3636,12 +3633,11 @@ public class JTree extends JComponent implements Scrollable, Accessible if(parent == null) return null; - Vector descendants = new Vector(); - Enumeration nodes = expandedState.keys(); - TreePath path; + Vector descendants = new Vector(); + Enumeration nodes = expandedState.keys(); while(nodes.hasMoreElements()) { - path = (TreePath)nodes.nextElement(); + TreePath path = nodes.nextElement(); if(parent.isDescendant(path)) descendants.addElement(path); } @@ -3664,8 +3660,8 @@ public class JTree extends JComponent implements Scrollable, Accessible { if(toRemove != null) { while(toRemove.hasMoreElements()) { - Enumeration descendants = getDescendantToggledPaths - ((TreePath)toRemove.nextElement()); + Enumeration descendants = getDescendantToggledPaths + (toRemove.nextElement()); if(descendants != null) { while(descendants.hasMoreElements()) { @@ -4250,7 +4246,7 @@ public class JTree extends JComponent implements Scrollable, Accessible private AccessibleContext getCurrentAccessibleContext() { Component c = getCurrentComponent(); if (c instanceof Accessible) { - return (((Accessible) c).getAccessibleContext()); + return c.getAccessibleContext(); } else { return null; } @@ -4573,7 +4569,7 @@ public class JTree extends JComponent implements Scrollable, Accessible private AccessibleContext getCurrentAccessibleContext() { Component c = getCurrentComponent(); if (c instanceof Accessible) { - return (((Accessible) c).getAccessibleContext()); + return c.getAccessibleContext(); } else { return null; } @@ -5117,12 +5113,8 @@ public class JTree extends JComponent implements Scrollable, Accessible public boolean isVisible() { Rectangle pathBounds = tree.getPathBounds(path); Rectangle parentBounds = tree.getVisibleRect(); - if (pathBounds != null && parentBounds != null && - parentBounds.intersects(pathBounds)) { - return true; - } else { - return false; - } + return pathBounds != null && parentBounds != null && + parentBounds.intersects(pathBounds); } public void setVisible(boolean b) { diff --git a/src/share/classes/javax/swing/JViewport.java b/src/share/classes/javax/swing/JViewport.java index f5a16bbd2c6c0022343c8c884344934f94a44707..734e80a05570d03e004aad8a37ee557811b592d0 100644 --- a/src/share/classes/javax/swing/JViewport.java +++ b/src/share/classes/javax/swing/JViewport.java @@ -389,7 +389,7 @@ public class JViewport extends JComponent implements Accessible // could be bigger than invalid size. validateView(); } - int dx = 0, dy = 0; + int dx, dy; dx = positionAdjustment(getWidth(), contentRect.width, contentRect.x); dy = positionAdjustment(getHeight(), contentRect.height, contentRect.y); @@ -682,10 +682,7 @@ public class JViewport extends JComponent implements Accessible * @see JComponent#isPaintingOrigin() */ boolean isPaintingOrigin() { - if (scrollMode == BACKINGSTORE_SCROLL_MODE) { - return true; - } - return false; + return scrollMode == BACKINGSTORE_SCROLL_MODE; } @@ -903,11 +900,7 @@ public class JViewport extends JComponent implements Accessible */ public void setScrollMode(int mode) { scrollMode = mode; - if (mode == BACKINGSTORE_SCROLL_MODE) { - backingStore = true; - } else { - backingStore = false; - } + backingStore = mode == BACKINGSTORE_SCROLL_MODE; } /** @@ -958,10 +951,10 @@ public class JViewport extends JComponent implements Accessible } } - private final boolean isBlitting() { + private boolean isBlitting() { Component view = getView(); return (scrollMode == BLIT_SCROLL_MODE) && - (view instanceof JComponent) && ((JComponent)view).isOpaque(); + (view instanceof JComponent) && view.isOpaque(); } @@ -1380,8 +1373,7 @@ public class JViewport extends JComponent implements Accessible * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** diff --git a/src/share/classes/javax/swing/JWindow.java b/src/share/classes/javax/swing/JWindow.java index c94803c4c4dfc2d26297e24b809fb37352b317e5..d805838b0e034c7eeaba1007b1ceff1a40e9d031 100644 --- a/src/share/classes/javax/swing/JWindow.java +++ b/src/share/classes/javax/swing/JWindow.java @@ -185,7 +185,7 @@ public class JWindow extends Window implements Accessible, super(owner == null? SwingUtilities.getSharedOwnerFrame() : owner); if (owner == null) { WindowListener ownerShutdownListener = - (WindowListener)SwingUtilities.getSharedOwnerFrameShutdownListener(); + SwingUtilities.getSharedOwnerFrameShutdownListener(); addWindowListener(ownerShutdownListener); } windowInit(); @@ -212,7 +212,7 @@ public class JWindow extends Window implements Accessible, owner); if (owner == null) { WindowListener ownerShutdownListener = - (WindowListener)SwingUtilities.getSharedOwnerFrameShutdownListener(); + SwingUtilities.getSharedOwnerFrameShutdownListener(); addWindowListener(ownerShutdownListener); } windowInit(); @@ -250,7 +250,7 @@ public class JWindow extends Window implements Accessible, owner, gc); if (owner == null) { WindowListener ownerShutdownListener = - (WindowListener)SwingUtilities.getSharedOwnerFrameShutdownListener(); + SwingUtilities.getSharedOwnerFrameShutdownListener(); addWindowListener(ownerShutdownListener); } windowInit(); diff --git a/src/share/classes/javax/swing/KeyboardManager.java b/src/share/classes/javax/swing/KeyboardManager.java index e27a72f3d320b2e0622d34c51f0638b280658cbd..d5ed58ba003d9380cd26c95b8b7af0a304e5dcef 100644 --- a/src/share/classes/javax/swing/KeyboardManager.java +++ b/src/share/classes/javax/swing/KeyboardManager.java @@ -68,13 +68,13 @@ class KeyboardManager { /** * maps top-level containers to a sub-hashtable full of keystrokes */ - Hashtable containerMap = new Hashtable(); + Hashtable containerMap = new Hashtable(); /** * Maps component/keystroke pairs to a topLevel container * This is mainly used for fast unregister operations */ - Hashtable componentKeyStrokeMap = new Hashtable(); + Hashtable componentKeyStrokeMap = new Hashtable(); public static KeyboardManager getCurrentManager() { return currentManager; @@ -95,7 +95,7 @@ class KeyboardManager { if (topContainer == null) { return; } - Hashtable keyMap = (Hashtable)containerMap.get(topContainer); + Hashtable keyMap = containerMap.get(topContainer); if (keyMap == null) { // lazy evaluate one keyMap = registerNewTopContainer(topContainer); @@ -114,8 +114,8 @@ class KeyboardManager { // Then add the old compoennt and the new compoent to the vector // then insert the vector in the table if (tmp != c) { // this means this is already registered for this component, no need to dup - Vector v = new Vector(); - v.addElement(tmp); + Vector v = new Vector(); + v.addElement((JComponent) tmp); v.addElement(c); keyMap.put(k, v); } @@ -154,13 +154,13 @@ class KeyboardManager { ComponentKeyStrokePair ckp = new ComponentKeyStrokePair(c,ks); - Object topContainer = componentKeyStrokeMap.get(ckp); + Container topContainer = componentKeyStrokeMap.get(ckp); if (topContainer == null) { // never heard of this pairing, so bail return; } - Hashtable keyMap = (Hashtable)containerMap.get(topContainer); + Hashtable keyMap = containerMap.get(topContainer); if (keyMap == null) { // this should never happen, but I'm being safe Thread.dumpStack(); return; @@ -221,7 +221,7 @@ class KeyboardManager { ks=KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers(), !pressed); } - Hashtable keyMap = (Hashtable)containerMap.get(topAncestor); + Hashtable keyMap = containerMap.get(topAncestor); if (keyMap != null) { // this container isn't registered, so bail Object tmp = keyMap.get(ks); @@ -293,7 +293,7 @@ class KeyboardManager { if (top == null) { return; } - Hashtable keyMap = (Hashtable)containerMap.get(top); + Hashtable keyMap = containerMap.get(top); if (keyMap == null) { // lazy evaluate one keyMap = registerNewTopContainer(top); @@ -314,11 +314,11 @@ class KeyboardManager { public void unregisterMenuBar(JMenuBar mb) { - Object topContainer = getTopAncestor(mb); + Container topContainer = getTopAncestor(mb); if (topContainer == null) { return; } - Hashtable keyMap = (Hashtable)containerMap.get(topContainer); + Hashtable keyMap = containerMap.get(topContainer); if (keyMap!=null) { Vector v = (Vector)keyMap.get(JMenuBar.class); if (v != null) { diff --git a/src/share/classes/javax/swing/LayoutComparator.java b/src/share/classes/javax/swing/LayoutComparator.java index 42d85c70cb5220f6b4383e1cc9b637f01f9afa6c..01ba6e54df04a0572b4f49f2b5247436656c4c1b 100644 --- a/src/share/classes/javax/swing/LayoutComparator.java +++ b/src/share/classes/javax/swing/LayoutComparator.java @@ -39,7 +39,7 @@ import java.awt.Window; * * @author David Mendenhall */ -final class LayoutComparator implements Comparator, java.io.Serializable { +final class LayoutComparator implements Comparator, java.io.Serializable { private static final int ROW_TOLERANCE = 10; @@ -51,10 +51,7 @@ final class LayoutComparator implements Comparator, java.io.Serializable { leftToRight = orientation.isLeftToRight(); } - public int compare(Object o1, Object o2) { - Component a = (Component)o1; - Component b = (Component)o2; - + public int compare(Component a, Component b) { if (a == b) { return 0; } @@ -65,9 +62,9 @@ final class LayoutComparator implements Comparator, java.io.Serializable { // each Component and then search from the Window down until the // hierarchy branches. if (a.getParent() != b.getParent()) { - LinkedList aAncestory, bAncestory; + LinkedList aAncestory = new LinkedList(); - for(aAncestory = new LinkedList(); a != null; a = a.getParent()) { + for(; a != null; a = a.getParent()) { aAncestory.add(a); if (a instanceof Window) { break; @@ -78,7 +75,9 @@ final class LayoutComparator implements Comparator, java.io.Serializable { throw new ClassCastException(); } - for(bAncestory = new LinkedList(); b != null; b = b.getParent()) { + LinkedList bAncestory = new LinkedList(); + + for(; b != null; b = b.getParent()) { bAncestory.add(b); if (b instanceof Window) { break; @@ -89,18 +88,18 @@ final class LayoutComparator implements Comparator, java.io.Serializable { throw new ClassCastException(); } - for (ListIterator + for (ListIterator aIter = aAncestory.listIterator(aAncestory.size()), bIter = bAncestory.listIterator(bAncestory.size()); ;) { if (aIter.hasPrevious()) { - a = (Component)aIter.previous(); + a = aIter.previous(); } else { // a is an ancestor of b return -1; } if (bIter.hasPrevious()) { - b = (Component)bIter.previous(); + b = bIter.previous(); } else { // b is an ancestor of a return 1; diff --git a/src/share/classes/javax/swing/LayoutFocusTraversalPolicy.java b/src/share/classes/javax/swing/LayoutFocusTraversalPolicy.java index 7e200e02eaf12d1f5c343db298e8142f8be79f5f..33d81a91a4892b2608a3422a73118e950642c7be 100644 --- a/src/share/classes/javax/swing/LayoutFocusTraversalPolicy.java +++ b/src/share/classes/javax/swing/LayoutFocusTraversalPolicy.java @@ -65,7 +65,7 @@ public class LayoutFocusTraversalPolicy extends SortingFocusTraversalPolicy * Constructs a LayoutFocusTraversalPolicy with the passed in * Comparator. */ - LayoutFocusTraversalPolicy(Comparator c) { + LayoutFocusTraversalPolicy(Comparator c) { super(c); } diff --git a/src/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java b/src/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java index f8a37fe7a2bee4b900033578eb2d7f3385c0e360..fe73a08957ff3bd1f7144e38c594cbb4451a2d9d 100644 --- a/src/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java +++ b/src/share/classes/javax/swing/LegacyGlueFocusTraversalPolicy.java @@ -48,8 +48,8 @@ final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy private transient FocusTraversalPolicy delegatePolicy; private transient DefaultFocusManager delegateManager; - private HashMap forwardMap = new HashMap(), - backwardMap = new HashMap(); + private HashMap forwardMap = new HashMap(), + backwardMap = new HashMap(); LegacyGlueFocusTraversalPolicy(FocusTraversalPolicy delegatePolicy) { this.delegatePolicy = delegatePolicy; @@ -70,11 +70,11 @@ final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy public Component getComponentAfter(Container focusCycleRoot, Component aComponent) { Component hardCoded = aComponent, prevHardCoded; - HashSet sanity = new HashSet(); + HashSet sanity = new HashSet(); do { prevHardCoded = hardCoded; - hardCoded = (Component)forwardMap.get(hardCoded); + hardCoded = forwardMap.get(hardCoded); if (hardCoded == null) { if (delegatePolicy != null && prevHardCoded.isFocusCycleRoot(focusCycleRoot)) { @@ -99,11 +99,11 @@ final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy public Component getComponentBefore(Container focusCycleRoot, Component aComponent) { Component hardCoded = aComponent, prevHardCoded; - HashSet sanity = new HashSet(); + HashSet sanity = new HashSet(); do { prevHardCoded = hardCoded; - hardCoded = (Component)backwardMap.get(hardCoded); + hardCoded = backwardMap.get(hardCoded); if (hardCoded == null) { if (delegatePolicy != null && prevHardCoded.isFocusCycleRoot(focusCycleRoot)) { diff --git a/src/share/classes/javax/swing/MenuSelectionManager.java b/src/share/classes/javax/swing/MenuSelectionManager.java index 8e1f36a3aa0dcf3d6abbdec8f3fab301eb1876ff..e1234c69aa6a63b112482646ec361237404da804 100644 --- a/src/share/classes/javax/swing/MenuSelectionManager.java +++ b/src/share/classes/javax/swing/MenuSelectionManager.java @@ -37,7 +37,7 @@ import sun.awt.AppContext; * @author Arnaud Weber */ public class MenuSelectionManager { - private Vector selection = new Vector(); + private Vector selection = new Vector(); /* diagnostic aids -- should be false for production builds. */ private static final boolean TRACE = false; // trace creates and disposes @@ -100,14 +100,14 @@ public class MenuSelectionManager { } for(i=0,c=path.length;i= firstDifference ; i--) { - MenuElement me = (MenuElement)selection.elementAt(i); + MenuElement me = selection.elementAt(i); selection.removeElementAt(i); me.menuSelectionChanged(false); } @@ -131,7 +131,7 @@ public class MenuSelectionManager { MenuElement res[] = new MenuElement[selection.size()]; int i,c; for(i=0,c=selection.size();i 0) { - MenuElement me = (MenuElement)selection.elementAt(0); + MenuElement me = selection.elementAt(0); return isComponentPartOfCurrentMenu(me,c); } else return false; diff --git a/src/share/classes/javax/swing/MultiUIDefaults.java b/src/share/classes/javax/swing/MultiUIDefaults.java index 30867e228044e33d6f2127127084ecb415ba843d..d7d435ef15f8a2e5ba3863084ca0adf86137368e 100644 --- a/src/share/classes/javax/swing/MultiUIDefaults.java +++ b/src/share/classes/javax/swing/MultiUIDefaults.java @@ -56,8 +56,7 @@ class MultiUIDefaults extends UIDefaults return value; } - for(int i = 0; i < tables.length; i++) { - UIDefaults table = tables[i]; + for (UIDefaults table : tables) { value = (table != null) ? table.get(key) : null; if (value != null) { return value; @@ -75,8 +74,7 @@ class MultiUIDefaults extends UIDefaults return value; } - for(int i = 0; i < tables.length; i++) { - UIDefaults table = tables[i]; + for (UIDefaults table : tables) { value = (table != null) ? table.get(key,l) : null; if (value != null) { return value; @@ -89,8 +87,7 @@ class MultiUIDefaults extends UIDefaults public int size() { int n = super.size(); - for(int i = 0; i < tables.length; i++) { - UIDefaults table = tables[i]; + for (UIDefaults table : tables) { n += (table != null) ? table.size() : 0; } return n; @@ -102,7 +99,7 @@ class MultiUIDefaults extends UIDefaults } - public Enumeration keys() + public Enumeration keys() { Enumeration[] enums = new Enumeration[1 + tables.length]; enums[0] = super.keys(); @@ -116,7 +113,7 @@ class MultiUIDefaults extends UIDefaults } - public Enumeration elements() + public Enumeration elements() { Enumeration[] enums = new Enumeration[1 + tables.length]; enums[0] = super.elements(); @@ -137,7 +134,7 @@ class MultiUIDefaults extends UIDefaults } } - private static class MultiUIDefaultsEnumerator implements Enumeration + private static class MultiUIDefaultsEnumerator implements Enumeration { Enumeration[] enums; int n = 0; @@ -175,8 +172,7 @@ class MultiUIDefaults extends UIDefaults return value; } - for(int i = 0; i < tables.length; i++) { - UIDefaults table = tables[i]; + for (UIDefaults table : tables) { value = (table != null) ? table.remove(key) : null; if (value != null) { return value; @@ -189,8 +185,7 @@ class MultiUIDefaults extends UIDefaults public void clear() { super.clear(); - for(int i = 0; i < tables.length; i++) { - UIDefaults table = tables[i]; + for (UIDefaults table : tables) { if (table != null) { table.clear(); } diff --git a/src/share/classes/javax/swing/PopupFactory.java b/src/share/classes/javax/swing/PopupFactory.java index f9c3c0dd5d710cd2a208da4a8cc77ae3a6a5cf18..753959cea1fa61bed0ad12aaf4eac0fd9ae504ec 100644 --- a/src/share/classes/javax/swing/PopupFactory.java +++ b/src/share/classes/javax/swing/PopupFactory.java @@ -313,9 +313,9 @@ public class PopupFactory { if(contents instanceof JPopupMenu) { JPopupMenu jpm = (JPopupMenu) contents; Component popComps[] = jpm.getComponents(); - for(int i=0;i cache; + Map> heavyPopupCache = getHeavyWeightPopupCache(); if (heavyPopupCache.containsKey(w)) { - cache = (List)heavyPopupCache.get(w); + cache = heavyPopupCache.get(w); } else { return null; } - int c; - if ((c = cache.size()) > 0) { - HeavyWeightPopup r = (HeavyWeightPopup)cache.get(0); + if (cache.size() > 0) { + HeavyWeightPopup r = cache.get(0); cache.remove(0); return r; } @@ -380,13 +379,13 @@ public class PopupFactory { * Window to a List of * HeavyWeightPopups. */ - private static Map getHeavyWeightPopupCache() { + private static Map> getHeavyWeightPopupCache() { synchronized (HeavyWeightPopup.class) { - Map cache = (Map)SwingUtilities.appContextGet( + Map> cache = (Map>)SwingUtilities.appContextGet( heavyWeightPopupCacheKey); if (cache == null) { - cache = new HashMap(2); + cache = new HashMap>(2); SwingUtilities.appContextPut(heavyWeightPopupCacheKey, cache); } @@ -399,13 +398,13 @@ public class PopupFactory { */ private static void recycleHeavyWeightPopup(HeavyWeightPopup popup) { synchronized (HeavyWeightPopup.class) { - List cache; - Object window = SwingUtilities.getWindowAncestor( + List cache; + Window window = SwingUtilities.getWindowAncestor( popup.getComponent()); - Map heavyPopupCache = getHeavyWeightPopupCache(); + Map> heavyPopupCache = getHeavyWeightPopupCache(); if (window instanceof Popup.DefaultFrame || - !((Window)window).isVisible()) { + !window.isVisible()) { // If the Window isn't visible, we don't cache it as we // likely won't ever get a windowClosed event to clean up. // We also don't cache DefaultFrames as this indicates @@ -414,28 +413,27 @@ public class PopupFactory { popup._dispose(); return; } else if (heavyPopupCache.containsKey(window)) { - cache = (List)heavyPopupCache.get(window); + cache = heavyPopupCache.get(window); } else { - cache = new ArrayList(); + cache = new ArrayList(); heavyPopupCache.put(window, cache); // Clean up if the Window is closed - final Window w = (Window)window; + final Window w = window; w.addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent e) { - List popups; + List popups; synchronized(HeavyWeightPopup.class) { - Map heavyPopupCache2 = + Map> heavyPopupCache2 = getHeavyWeightPopupCache(); - popups = (List)heavyPopupCache2.remove(w); + popups = heavyPopupCache2.remove(w); } if (popups != null) { for (int counter = popups.size() - 1; counter >= 0; counter--) { - ((HeavyWeightPopup)popups.get(counter)). - _dispose(); + popups.get(counter)._dispose(); } } } @@ -534,10 +532,9 @@ public class PopupFactory { Window[] ownedWindows = w.getOwnedWindows(); if(ownedWindows != null) { Rectangle bnd = component.getBounds(); - for(int i=0; i getLightWeightPopupCache() { + List cache = (List)SwingUtilities.appContextGet( lightWeightPopupCacheKey); if (cache == null) { - cache = new ArrayList(); + cache = new ArrayList(); SwingUtilities.appContextPut(lightWeightPopupCacheKey, cache); } return cache; @@ -682,7 +679,7 @@ public class PopupFactory { */ private static void recycleLightWeightPopup(LightWeightPopup popup) { synchronized (LightWeightPopup.class) { - List lightPopupCache = getLightWeightPopupCache(); + List lightPopupCache = getLightWeightPopupCache(); if (lightPopupCache.size() < MAX_CACHE_SIZE) { lightPopupCache.add(popup); } @@ -695,11 +692,9 @@ public class PopupFactory { */ private static LightWeightPopup getRecycledLightWeightPopup() { synchronized (LightWeightPopup.class) { - List lightPopupCache = getLightWeightPopupCache(); - int c; - if((c = lightPopupCache.size()) > 0) { - LightWeightPopup r = (LightWeightPopup)lightPopupCache. - get(0); + List lightPopupCache = getLightWeightPopupCache(); + if (lightPopupCache.size() > 0) { + LightWeightPopup r = lightPopupCache.get(0); lightPopupCache.remove(0); return r; } @@ -755,8 +750,7 @@ public class PopupFactory { component.setLocation(p.x, p.y); if (parent instanceof JLayeredPane) { - ((JLayeredPane)parent).add(component, - JLayeredPane.POPUP_LAYER, 0); + parent.add(component, JLayeredPane.POPUP_LAYER, 0); } else { parent.add(component); } @@ -826,12 +820,12 @@ public class PopupFactory { /** * Returns the cache to use for medium weight popups. */ - private static List getMediumWeightPopupCache() { - List cache = (List)SwingUtilities.appContextGet( + private static List getMediumWeightPopupCache() { + List cache = (List)SwingUtilities.appContextGet( mediumWeightPopupCacheKey); if (cache == null) { - cache = new ArrayList(); + cache = new ArrayList(); SwingUtilities.appContextPut(mediumWeightPopupCacheKey, cache); } return cache; @@ -842,7 +836,7 @@ public class PopupFactory { */ private static void recycleMediumWeightPopup(MediumWeightPopup popup) { synchronized (MediumWeightPopup.class) { - List mediumPopupCache = getMediumWeightPopupCache(); + List mediumPopupCache = getMediumWeightPopupCache(); if (mediumPopupCache.size() < MAX_CACHE_SIZE) { mediumPopupCache.add(popup); } @@ -855,12 +849,9 @@ public class PopupFactory { */ private static MediumWeightPopup getRecycledMediumWeightPopup() { synchronized (MediumWeightPopup.class) { - java.util.List mediumPopupCache = - getMediumWeightPopupCache(); - int c; - if ((c=mediumPopupCache.size()) > 0) { - MediumWeightPopup r = (MediumWeightPopup)mediumPopupCache. - get(0); + List mediumPopupCache = getMediumWeightPopupCache(); + if (mediumPopupCache.size() > 0) { + MediumWeightPopup r = mediumPopupCache.get(0); mediumPopupCache.remove(0); return r; } @@ -904,7 +895,7 @@ public class PopupFactory { x, y); component.setVisible(false); component.setLocation(p.x, p.y); - ((JLayeredPane)parent).add(component, JLayeredPane.POPUP_LAYER, + parent.add(component, JLayeredPane.POPUP_LAYER, 0); } else { Point p = SwingUtilities.convertScreenLocationToParent(parent, diff --git a/src/share/classes/javax/swing/RepaintManager.java b/src/share/classes/javax/swing/RepaintManager.java index 91034dbf8f28eda6cfb9bc0f43049bc2ffaa33d5..b0e6c048f620198a0a81acc9e7f3a45553fa2a7f 100644 --- a/src/share/classes/javax/swing/RepaintManager.java +++ b/src/share/classes/javax/swing/RepaintManager.java @@ -40,6 +40,8 @@ import sun.awt.SunToolkit; import sun.java2d.SunGraphicsEnvironment; import sun.security.action.GetPropertyAction; +import com.sun.java.swing.SwingUtilities3; + /** * This class manages repaint requests, allowing the number @@ -303,6 +305,11 @@ public class RepaintManager */ public synchronized void addInvalidComponent(JComponent invalidComponent) { + RepaintManager delegate = getDelegate(invalidComponent); + if (delegate != null) { + delegate.addInvalidComponent(invalidComponent); + return; + } Component validateRoot = null; /* Find the first JComponent ancestor of this component whose @@ -373,6 +380,11 @@ public class RepaintManager * @see #addInvalidComponent */ public synchronized void removeInvalidComponent(JComponent component) { + RepaintManager delegate = getDelegate(component); + if (delegate != null) { + delegate.removeInvalidComponent(component); + return; + } if(invalidComponents != null) { int index = invalidComponents.indexOf(component); if(index != -1) { @@ -464,6 +476,11 @@ public class RepaintManager */ public void addDirtyRegion(JComponent c, int x, int y, int w, int h) { + RepaintManager delegate = getDelegate(c); + if (delegate != null) { + delegate.addDirtyRegion(c, x, y, w, h); + return; + } addDirtyRegion0(c, x, y, w, h); } @@ -572,7 +589,7 @@ public class RepaintManager */ private synchronized boolean extendDirtyRegion( Component c, int x, int y, int w, int h) { - Rectangle r = (Rectangle)dirtyComponents.get(c); + Rectangle r = dirtyComponents.get(c); if (r != null) { // A non-null r implies c is already marked as dirty, // and that the parent is valid. Therefore we can @@ -588,9 +605,13 @@ public class RepaintManager * dirty. */ public Rectangle getDirtyRegion(JComponent aComponent) { - Rectangle r = null; + RepaintManager delegate = getDelegate(aComponent); + if (delegate != null) { + return delegate.getDirtyRegion(aComponent); + } + Rectangle r; synchronized(this) { - r = (Rectangle)dirtyComponents.get(aComponent); + r = dirtyComponents.get(aComponent); } if(r == null) return new Rectangle(0,0,0,0); @@ -603,6 +624,11 @@ public class RepaintManager * completely painted during the next paintDirtyRegions() call. */ public void markCompletelyDirty(JComponent aComponent) { + RepaintManager delegate = getDelegate(aComponent); + if (delegate != null) { + delegate.markCompletelyDirty(aComponent); + return; + } addDirtyRegion(aComponent,0,0,Integer.MAX_VALUE,Integer.MAX_VALUE); } @@ -611,6 +637,11 @@ public class RepaintManager * get painted during the next paintDirtyRegions() call. */ public void markCompletelyClean(JComponent aComponent) { + RepaintManager delegate = getDelegate(aComponent); + if (delegate != null) { + delegate.markCompletelyClean(aComponent); + return; + } synchronized(this) { dirtyComponents.remove(aComponent); } @@ -623,6 +654,10 @@ public class RepaintManager * if it return true. */ public boolean isCompletelyDirty(JComponent aComponent) { + RepaintManager delegate = getDelegate(aComponent); + if (delegate != null) { + return delegate.isCompletelyDirty(aComponent); + } Rectangle r; r = getDirtyRegion(aComponent); @@ -710,8 +745,8 @@ public class RepaintManager Rectangle rect; int localBoundsX = 0; int localBoundsY = 0; - int localBoundsH = 0; - int localBoundsW = 0; + int localBoundsH; + int localBoundsW; Enumeration keys; roots = new ArrayList(count); @@ -818,7 +853,7 @@ public class RepaintManager dx = rootDx = 0; dy = rootDy = 0; - tmp.setBounds((Rectangle) dirtyComponents.get(dirtyComponent)); + tmp.setBounds(dirtyComponents.get(dirtyComponent)); // System.out.println("Collect dirty component for bound " + tmp + // "component bounds is " + cBounds);; @@ -865,7 +900,7 @@ public class RepaintManager Rectangle r; tmp.setLocation(tmp.x + rootDx - dx, tmp.y + rootDy - dy); - r = (Rectangle)dirtyComponents.get(rootDirtyComponent); + r = dirtyComponents.get(rootDirtyComponent); SwingUtilities.computeUnion(tmp.x,tmp.y,tmp.width,tmp.height,r); } @@ -900,6 +935,10 @@ public class RepaintManager * repaint manager. */ public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) { + RepaintManager delegate = getDelegate(c); + if (delegate != null) { + return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight); + } return _getOffscreenBuffer(c, proposedWidth, proposedHeight); } @@ -917,6 +956,11 @@ public class RepaintManager */ public Image getVolatileOffscreenBuffer(Component c, int proposedWidth,int proposedHeight) { + RepaintManager delegate = getDelegate(c); + if (delegate != null) { + return delegate.getVolatileOffscreenBuffer(c, proposedWidth, + proposedHeight); + } GraphicsConfiguration config = c.getGraphicsConfiguration(); if (config == null) { config = GraphicsEnvironment.getLocalGraphicsEnvironment(). @@ -941,7 +985,7 @@ public class RepaintManager private Image _getOffscreenBuffer(Component c, int proposedWidth, int proposedHeight) { Dimension maxSize = getDoubleBufferMaximumSize(); - DoubleBufferInfo doubleBuffer = null; + DoubleBufferInfo doubleBuffer; int width, height; if (standardDoubleBuffer == null) { @@ -1010,7 +1054,7 @@ public class RepaintManager Iterator gcs = volatileMap.keySet().iterator(); while (gcs.hasNext()) { GraphicsConfiguration gc = (GraphicsConfiguration)gcs.next(); - VolatileImage image = (VolatileImage)volatileMap.get(gc); + VolatileImage image = volatileMap.get(gc); if (image.getWidth() > width || image.getHeight() > height) { image.flush(); gcs.remove(); @@ -1178,7 +1222,7 @@ public class RepaintManager */ void beginPaint() { boolean multiThreadedPaint = false; - int paintDepth = 0; + int paintDepth; Thread currentThread = Thread.currentThread(); synchronized(this) { paintDepth = this.paintDepth; @@ -1550,4 +1594,11 @@ public class RepaintManager prePaintDirtyRegions(); } } + private RepaintManager getDelegate(Component c) { + RepaintManager delegate = SwingUtilities3.getDelegateRepaintManager(c); + if (this == delegate) { + delegate = null; + } + return delegate; + } } diff --git a/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java b/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java index e920acccba2d0f33af0e3956dbccef10f6fa91cd..85a2bb96a25a76ad3af8905abb337c8917f0b662 100644 --- a/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java +++ b/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java @@ -79,7 +79,7 @@ public class SortingFocusTraversalPolicy * sorted list should be reused if possible. */ transient private Container cachedRoot; - transient private List cachedCycle; + transient private List cachedCycle; // Delegate our fitness test to ContainerOrder so that we only have to // code the algorithm once. @@ -111,7 +111,7 @@ public class SortingFocusTraversalPolicy return cycle; } private int getComponentIndex(List cycle, Component aComponent) { - int index = 0; + int index; try { index = Collections.binarySearch(cycle, aComponent, comparator); } catch (ClassCastException e) { @@ -130,14 +130,14 @@ public class SortingFocusTraversalPolicy return index; } - private void enumerateAndSortCycle(Container focusCycleRoot, List cycle) { + private void enumerateAndSortCycle(Container focusCycleRoot, List cycle) { if (focusCycleRoot.isShowing()) { enumerateCycle(focusCycleRoot, cycle); Collections.sort(cycle, comparator); } } - private void enumerateCycle(Container container, List cycle) { + private void enumerateCycle(Container container, List cycle) { if (!(container.isVisible() && container.isDisplayable())) { return; } @@ -145,8 +145,7 @@ public class SortingFocusTraversalPolicy cycle.add(container); Component[] components = container.getComponents(); - for (int i = 0; i < components.length; i++) { - Component comp = components[i]; + for (Component comp : components) { if (comp instanceof Container) { Container cont = (Container)comp; @@ -385,8 +384,8 @@ public class SortingFocusTraversalPolicy return getLastComponent(aContainer); } - Component comp = null; - Component tryComp = null; + Component comp; + Component tryComp; for (index--; index>=0; index--) { comp = cycle.get(index); @@ -442,8 +441,7 @@ public class SortingFocusTraversalPolicy } if (log.isLoggable(Level.FINE)) log.fine("### Cycle is " + cycle); - for (int i = 0; i < cycle.size(); i++) { - Component comp = cycle.get(i); + for (Component comp : cycle) { if (accept(comp)) { return comp; } else if (comp instanceof Container && comp != aContainer) { diff --git a/src/share/classes/javax/swing/SpringLayout.java b/src/share/classes/javax/swing/SpringLayout.java index 34847944219296e601e9eda2c18b38e86325cd54..e825f4c6104cfa7756b8e6fcecbacd62ea6ac089 100644 --- a/src/share/classes/javax/swing/SpringLayout.java +++ b/src/share/classes/javax/swing/SpringLayout.java @@ -185,11 +185,11 @@ import java.util.*; * @since 1.4 */ public class SpringLayout implements LayoutManager2 { - private Map componentConstraints = new HashMap(); + private Map componentConstraints = new HashMap(); private Spring cyclicReference = Spring.constant(Spring.UNSET); - private Set cyclicSprings; - private Set acyclicSprings; + private Set cyclicSprings; + private Set acyclicSprings; /** @@ -415,8 +415,7 @@ public class SpringLayout implements LayoutManager2 { } if (!valid) { String[] all = horizontal ? ALL_HORIZONTAL : ALL_VERTICAL; - for (int i = 0; i < all.length; i++) { - String s = all[i]; + for (String s : all) { if (!history.contains(s)) { setConstraint(s, null); } @@ -822,8 +821,7 @@ public class SpringLayout implements LayoutManager2 { /*pp*/ void reset() { Spring[] allSprings = {x, y, width, height, east, south, horizontalCenter, verticalCenter, baseline}; - for (int i = 0; i < allSprings.length; i++) { - Spring s = allSprings[i]; + for (Spring s : allSprings) { if (s != null) { s.setValue(Spring.UNSET); } @@ -881,8 +879,8 @@ public class SpringLayout implements LayoutManager2 { public SpringLayout() {} private void resetCyclicStatuses() { - cyclicSprings = new HashSet(); - acyclicSprings = new HashSet(); + cyclicSprings = new HashSet(); + acyclicSprings = new HashSet(); } private void setParent(Container p) { @@ -1145,7 +1143,7 @@ public class SpringLayout implements LayoutManager2 { * @return the constraints for the specified component */ public Constraints getConstraints(Component c) { - Constraints result = (Constraints)componentConstraints.get(c); + Constraints result = componentConstraints.get(c); if (result == null) { if (c instanceof javax.swing.JComponent) { Object cp = ((javax.swing.JComponent)c).getClientProperty(SpringLayout.class); diff --git a/src/share/classes/javax/swing/SwingUtilities.java b/src/share/classes/javax/swing/SwingUtilities.java index d8f29e5288ca9d4c9c56e0b4817f412048b44863..0493510a7bb44bf22d2e205b84aab6c45867def4 100644 --- a/src/share/classes/javax/swing/SwingUtilities.java +++ b/src/share/classes/javax/swing/SwingUtilities.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,11 +108,8 @@ public class SwingUtilities implements SwingConstants * Return true if a contains b */ public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) { - if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width) && - b.y >= a.y && (b.y + b.height) <= (a.y + a.height)) { - return true; - } - return false; + return b.x >= a.x && (b.x + b.width) <= (a.x + a.width) && + b.y >= a.y && (b.y + b.height) <= (a.y + a.height); } /** @@ -272,8 +269,7 @@ public class SwingUtilities implements SwingConstants } if (parent instanceof Container) { Component components[] = ((Container)parent).getComponents(); - for (int i = 0 ; i < components.length ; i++) { - Component comp = components[i]; + for (Component comp : components) { if (comp != null && comp.isVisible()) { Point loc = comp.getLocation(); if (comp instanceof Container) { @@ -376,8 +372,8 @@ public class SwingUtilities implements SwingConstants do { if(c instanceof JComponent) { - x = ((JComponent)c).getX(); - y = ((JComponent)c).getY(); + x = c.getX(); + y = c.getY(); } else if(c instanceof java.applet.Applet || c instanceof java.awt.Window) { try { @@ -415,8 +411,8 @@ public class SwingUtilities implements SwingConstants do { if(c instanceof JComponent) { - x = ((JComponent)c).getX(); - y = ((JComponent)c).getY(); + x = c.getX(); + y = c.getY(); } else if(c instanceof java.applet.Applet || c instanceof java.awt.Window) { try { @@ -974,12 +970,13 @@ public class SwingUtilities implements SwingConstants boolean textIsEmpty = (text == null) || text.equals(""); int lsb = 0; + int rsb = 0; /* Unless both text and icon are non-null, we effectively ignore * the value of textIconGap. */ int gap; - View v = null; + View v; if (textIsEmpty) { textR.width = textR.height = 0; text = ""; @@ -1015,7 +1012,7 @@ public class SwingUtilities implements SwingConstants if (lsb < 0) { textR.width -= lsb; } - int rsb = SwingUtilities2.getRightSideBearing(c, fm, text); + rsb = SwingUtilities2.getRightSideBearing(c, fm, text); if (rsb > 0) { textR.width += rsb; } @@ -1118,6 +1115,11 @@ public class SwingUtilities implements SwingConstants // lsb is negative. Shift the x location so that the text is // visually drawn at the right location. textR.x -= lsb; + + textR.width += lsb; + } + if (rsb > 0) { + textR.width -= rsb; } return text; @@ -1242,8 +1244,8 @@ public class SwingUtilities implements SwingConstants children = ((Container)c).getComponents(); } if (children != null) { - for(int i = 0; i < children.length; i++) { - updateComponentTreeUI0(children[i]); + for (Component child : children) { + updateComponentTreeUI0(child); } } } @@ -1696,7 +1698,7 @@ public class SwingUtilities implements SwingConstants */ public static void replaceUIActionMap(JComponent component, ActionMap uiActionMap) { - ActionMap map = component.getActionMap((uiActionMap != null));; + ActionMap map = component.getActionMap((uiActionMap != null)); while (map != null) { ActionMap parent = map.getParent(); @@ -1764,8 +1766,7 @@ public class SwingUtilities implements SwingConstants */ void installListeners() { Window[] windows = getOwnedWindows(); - for (int ind = 0; ind < windows.length; ind++){ - Window window = windows[ind]; + for (Window window : windows) { if (window != null) { window.removeWindowListener(this); window.addWindowListener(this); @@ -1780,8 +1781,7 @@ public class SwingUtilities implements SwingConstants public void windowClosed(WindowEvent e) { synchronized(getTreeLock()) { Window[] windows = getOwnedWindows(); - for (int ind = 0; ind < windows.length; ind++) { - Window window = windows[ind]; + for (Window window : windows) { if (window != null) { if (window.isDisplayable()) { return; @@ -1869,7 +1869,7 @@ public class SwingUtilities implements SwingConstants } - static Class loadSystemClass(String className) throws ClassNotFoundException { + static Class loadSystemClass(String className) throws ClassNotFoundException { return Class.forName(className, true, Thread.currentThread(). getContextClassLoader()); } diff --git a/src/share/classes/javax/swing/Timer.java b/src/share/classes/javax/swing/Timer.java index a96d2ce8dc9f5b888024c0a816d11d6d84a64420..4f339158efca2c76e6d6cb29e2252c94305cb78e 100644 --- a/src/share/classes/javax/swing/Timer.java +++ b/src/share/classes/javax/swing/Timer.java @@ -270,8 +270,7 @@ public class Timer implements Serializable * @since 1.4 */ public ActionListener[] getActionListeners() { - return (ActionListener[])listenerList.getListeners( - ActionListener.class); + return listenerList.getListeners(ActionListener.class); } diff --git a/src/share/classes/javax/swing/TimerQueue.java b/src/share/classes/javax/swing/TimerQueue.java index 2121939011f88fdddcbf6b8a826abf6553d1d900..f68f4e9968870d933914ae8fe39e35f76afa37b3 100644 --- a/src/share/classes/javax/swing/TimerQueue.java +++ b/src/share/classes/javax/swing/TimerQueue.java @@ -31,6 +31,7 @@ package javax.swing; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicLong; import sun.awt.AppContext; @@ -52,7 +53,8 @@ class TimerQueue implements Runnable new StringBuffer("TimerQueue.expiredTimersKey"); private final DelayQueue queue; - volatile boolean running; + private volatile boolean running; + private final Lock runningLock; /* Lock object used in place of class object for synchronization. * (4187686) @@ -69,7 +71,8 @@ class TimerQueue implements Runnable super(); queue = new DelayQueue(); // Now start the TimerQueue thread. - start(); + runningLock = new ReentrantLock(); + startIfNeeded(); } @@ -87,33 +90,30 @@ class TimerQueue implements Runnable } - synchronized void start() { - if (running) { - throw new RuntimeException("Can't start a TimerQueue " + - "that is already running"); - } - else { - final ThreadGroup threadGroup = - AppContext.getAppContext().getThreadGroup(); - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - Thread timerThread = new Thread(threadGroup, TimerQueue.this, - "TimerQueue"); - timerThread.setDaemon(true); - timerThread.setPriority(Thread.NORM_PRIORITY); - timerThread.start(); - return null; - } - }); - running = true; + void startIfNeeded() { + if (! running) { + runningLock.lock(); + try { + final ThreadGroup threadGroup = + AppContext.getAppContext().getThreadGroup(); + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + Thread timerThread = new Thread(threadGroup, TimerQueue.this, + "TimerQueue"); + timerThread.setDaemon(true); + timerThread.setPriority(Thread.NORM_PRIORITY); + timerThread.start(); + return null; + } + }); + running = true; + } finally { + runningLock.unlock(); + } } } - synchronized void stop() { - running = false; - } - void addTimer(Timer timer, long delayMillis) { timer.getLock().lock(); try { @@ -164,6 +164,7 @@ class TimerQueue implements Runnable public void run() { + runningLock.lock(); try { while (running) { try { @@ -195,14 +196,14 @@ class TimerQueue implements Runnable } } catch (ThreadDeath td) { - synchronized (this) { - running = false; - // Mark all the timers we contain as not being queued. - for (DelayedTimer delayedTimer : queue) { - delayedTimer.getTimer().cancelEvent(); - } - throw td; + // Mark all the timers we contain as not being queued. + for (DelayedTimer delayedTimer : queue) { + delayedTimer.getTimer().cancelEvent(); } + throw td; + } finally { + running = false; + runningLock.unlock(); } } @@ -225,7 +226,7 @@ class TimerQueue implements Runnable /** * Returns nanosecond time offset by origin */ - private final static long now() { + private static long now() { return System.nanoTime() - NANO_ORIGIN; } diff --git a/src/share/classes/javax/swing/UIDefaults.java b/src/share/classes/javax/swing/UIDefaults.java index 302dc00b0dda2a64a5d2a1bead989b0d58191d43..7a372e79753d60afc806a6bacfc427b9e43308d3 100644 --- a/src/share/classes/javax/swing/UIDefaults.java +++ b/src/share/classes/javax/swing/UIDefaults.java @@ -72,11 +72,11 @@ import sun.util.CoreResourceBundleControl; */ public class UIDefaults extends Hashtable { - private static final Object PENDING = new String("Pending"); + private static final Object PENDING = "Pending"; private SwingPropertyChangeSupport changeSupport; - private Vector resourceBundles; + private Vector resourceBundles; private Locale defaultLocale = Locale.getDefault(); @@ -86,7 +86,7 @@ public class UIDefaults extends Hashtable * Access to this should be done while holding a lock on the * UIDefaults, eg synchronized(this). */ - private Map resourceCache; + private Map> resourceCache; /** * Creates an empty defaults table. @@ -106,7 +106,7 @@ public class UIDefaults extends Hashtable */ public UIDefaults(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); - resourceCache = new HashMap(); + resourceCache = new HashMap>(); } @@ -281,24 +281,24 @@ public class UIDefaults extends Hashtable if( defaultLocale == null ) return null; else - l = (Locale)defaultLocale; + l = defaultLocale; } synchronized(this) { - return getResourceCache(l).get((String)key); + return getResourceCache(l).get(key); } } /** * Returns a Map of the known resources for the given locale. */ - private Map getResourceCache(Locale l) { - Map values = (Map)resourceCache.get(l); + private Map getResourceCache(Locale l) { + Map values = resourceCache.get(l); if (values == null) { - values = new HashMap(); + values = new HashMap(); for (int i=resourceBundles.size()-1; i >= 0; i--) { - String bundleName = (String)resourceBundles.get(i); + String bundleName = resourceBundles.get(i); try { Control c = CoreResourceBundleControl.getRBControlInstance(bundleName); ResourceBundle b; @@ -751,7 +751,7 @@ public class UIDefaults extends Hashtable Object cl = get("ClassLoader"); ClassLoader uiClassLoader = (cl != null) ? (ClassLoader)cl : target.getClass().getClassLoader(); - Class uiClass = getUIClass(target.getUIClassID(), uiClassLoader); + Class uiClass = getUIClass(target.getUIClassID(), uiClassLoader); Object uiObject = null; if (uiClass == null) { @@ -761,8 +761,7 @@ public class UIDefaults extends Hashtable try { Method m = (Method)get(uiClass); if (m == null) { - Class acClass = javax.swing.JComponent.class; - m = uiClass.getMethod("createUI", new Class[]{acClass}); + m = uiClass.getMethod("createUI", new Class[]{JComponent.class}); put(uiClass, m); } uiObject = MethodUtil.invoke(m, null, new Object[]{target}); @@ -862,7 +861,7 @@ public class UIDefaults extends Hashtable return; } if( resourceBundles == null ) { - resourceBundles = new Vector(5); + resourceBundles = new Vector(5); } if (!resourceBundles.contains(bundleName)) { resourceBundles.add( bundleName ); @@ -1064,7 +1063,7 @@ public class UIDefaults extends Hashtable className = c; methodName = m; if (o != null) { - args = (Object[])o.clone(); + args = o.clone(); } } @@ -1079,10 +1078,10 @@ public class UIDefaults extends Hashtable // In order to pick up the security policy in effect at the // time of creation we use a doPrivileged with the // AccessControlContext that was in place when this was created. - return AccessController.doPrivileged(new PrivilegedAction() { + return AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { - Class c; + Class c; Object cl; // See if we should use a separate ClassLoader if (table == null || !((cl = table.get("ClassLoader")) diff --git a/src/share/classes/javax/swing/UIManager.java b/src/share/classes/javax/swing/UIManager.java index 6fb543d337455bbfd7d07d0ef419eb45ab6222af..a4a62f0096caa92ba4e63297080dc0f73260adbd 100644 --- a/src/share/classes/javax/swing/UIManager.java +++ b/src/share/classes/javax/swing/UIManager.java @@ -191,7 +191,7 @@ public class UIManager implements Serializable MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables); LookAndFeel lookAndFeel; LookAndFeel multiLookAndFeel = null; - Vector auxLookAndFeels = null; + Vector auxLookAndFeels = null; SwingPropertyChangeSupport changeSupport; UIDefaults getLookAndFeelDefaults() { return tables[0]; } @@ -378,7 +378,7 @@ public class UIManager implements Serializable private static LookAndFeelInfo[] installedLAFs; static { - ArrayList iLAFs = new ArrayList(4); + ArrayList iLAFs = new ArrayList(4); iLAFs.add(new LookAndFeelInfo( "Metal", "javax.swing.plaf.metal.MetalLookAndFeel")); iLAFs.add(new LookAndFeelInfo("CDE/Motif", @@ -400,8 +400,7 @@ public class UIManager implements Serializable iLAFs.add(new LookAndFeelInfo("GTK+", "com.sun.java.swing.plaf.gtk.GTKLookAndFeel")); } - installedLAFs = (LookAndFeelInfo[])iLAFs.toArray( - new LookAndFeelInfo[iLAFs.size()]); + installedLAFs = iLAFs.toArray(new LookAndFeelInfo[iLAFs.size()]); } @@ -640,7 +639,7 @@ public class UIManager implements Serializable * @see #getSystemLookAndFeelClassName */ public static String getCrossPlatformLookAndFeelClassName() { - String laf = (String)AccessController.doPrivileged( + String laf = AccessController.doPrivileged( new GetPropertyAction("swing.crossplatformlaf")); if (laf != null) { return laf; @@ -1079,9 +1078,9 @@ public class UIManager implements Serializable // for that. return; } - Vector v = getLAFState().auxLookAndFeels; + Vector v = getLAFState().auxLookAndFeels; if (v == null) { - v = new Vector(); + v = new Vector(); } if (!v.contains(laf)) { @@ -1115,7 +1114,7 @@ public class UIManager implements Serializable boolean result; - Vector v = getLAFState().auxLookAndFeels; + Vector v = getLAFState().auxLookAndFeels; if ((v == null) || (v.size() == 0)) { return false; } @@ -1151,14 +1150,14 @@ public class UIManager implements Serializable static public LookAndFeel[] getAuxiliaryLookAndFeels() { maybeInitialize(); - Vector v = getLAFState().auxLookAndFeels; + Vector v = getLAFState().auxLookAndFeels; if ((v == null) || (v.size() == 0)) { return null; } else { LookAndFeel[] rv = new LookAndFeel[v.size()]; for (int i = 0; i < rv.length; i++) { - rv[i] = (LookAndFeel)v.elementAt(i); + rv[i] = v.elementAt(i); } return rv; } @@ -1225,7 +1224,7 @@ public class UIManager implements Serializable final Properties props = new Properties(); java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction() { public Object run() { try { File file = new File(makeSwingPropertiesFilename()); @@ -1284,7 +1283,7 @@ public class UIManager implements Serializable * property. For example given "swing.installedlafs=motif,windows" * lafs = {"motif", "windows"}. */ - Vector lafs = new Vector(); + Vector lafs = new Vector(); StringTokenizer st = new StringTokenizer(ilafsString, ",", false); while (st.hasMoreTokens()) { lafs.addElement(st.nextToken()); @@ -1294,9 +1293,8 @@ public class UIManager implements Serializable * list. If they both exist then add a LookAndFeelInfo to * the installedLafs array. */ - Vector ilafs = new Vector(lafs.size()); - for(int i = 0; i < lafs.size(); i++) { - String laf = (String)lafs.elementAt(i); + Vector ilafs = new Vector(lafs.size()); + for (String laf : lafs) { String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf); String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class")); if (cls != null) { @@ -1306,7 +1304,7 @@ public class UIManager implements Serializable installedLAFs = new LookAndFeelInfo[ilafs.size()]; for(int i = 0; i < ilafs.size(); i++) { - installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i)); + installedLAFs[i] = ilafs.elementAt(i); } } @@ -1350,7 +1348,7 @@ public class UIManager implements Serializable return; } - Vector auxLookAndFeels = new Vector(); + Vector auxLookAndFeels = new Vector(); StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,","); String factoryName; @@ -1451,7 +1449,7 @@ public class UIManager implements Serializable Component c = e.getComponent(); if ((!(c instanceof JComponent) || - (c != null && !((JComponent)c).isEnabled())) && + (c != null && !c.isEnabled())) && JComponent.KeyboardState.shouldProcess(e) && SwingUtilities.processKeyBindings(e)) { e.consume(); diff --git a/src/share/classes/javax/swing/border/CompoundBorder.java b/src/share/classes/javax/swing/border/CompoundBorder.java index f736cf90278f44397b839248130d06ad4a09946b..46ac44e50c02553c33123e7d967dcba33d82a9eb 100644 --- a/src/share/classes/javax/swing/border/CompoundBorder.java +++ b/src/share/classes/javax/swing/border/CompoundBorder.java @@ -79,10 +79,13 @@ public class CompoundBorder extends AbstractBorder { } /** - * Returns whether or not this compound border is opaque. - * Returns true if both the inside and outside borders are - * non-null and opaque; returns false otherwise. + * Returns whether or not the compound border is opaque. + * + * @return {@code true} if the inside and outside borders + * are each either {@code null} or opaque; + * or {@code false} otherwise */ + @Override public boolean isBorderOpaque() { return (outsideBorder == null || outsideBorder.isBorderOpaque()) && (insideBorder == null || insideBorder.isBorderOpaque()); diff --git a/src/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java b/src/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java index 9fa819ba9350259818bc26f6875c47b978300271..c9ea9d77494f57d6e16f8bd95b174a2734ec10c9 100644 --- a/src/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java +++ b/src/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java @@ -160,7 +160,9 @@ public abstract class AbstractColorChooserPanel extends JPanel { * is editing */ public ColorSelectionModel getColorSelectionModel() { - return chooser.getSelectionModel(); + return (this.chooser != null) + ? this.chooser.getSelectionModel() + : null; } /** @@ -168,7 +170,17 @@ public abstract class AbstractColorChooserPanel extends JPanel { * @return the Color that is selected */ protected Color getColorFromModel() { - return getColorSelectionModel().getSelectedColor(); + ColorSelectionModel model = getColorSelectionModel(); + return (model != null) + ? model.getSelectedColor() + : null; + } + + void setSelectedColor(Color color) { + ColorSelectionModel model = getColorSelectionModel(); + if (model != null) { + model.setSelectedColor(color); + } } /** diff --git a/src/share/classes/javax/swing/colorchooser/ColorChooserComponentFactory.java b/src/share/classes/javax/swing/colorchooser/ColorChooserComponentFactory.java index b36c6524d8a127d10ee625ba3cb5d718e32a1673..0ee01e6cb5ac2c6b365a8d2db86b7619ffb011e0 100644 --- a/src/share/classes/javax/swing/colorchooser/ColorChooserComponentFactory.java +++ b/src/share/classes/javax/swing/colorchooser/ColorChooserComponentFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2001 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 @@ -25,9 +25,7 @@ package javax.swing.colorchooser; -import javax.swing.*; - - +import javax.swing.JComponent; /** * A class designed to produce preconfigured "accessory" objects to @@ -49,16 +47,17 @@ public class ColorChooserComponentFactory { private ColorChooserComponentFactory() { } // can't instantiate - public static AbstractColorChooserPanel[] getDefaultChooserPanels() { - AbstractColorChooserPanel[] choosers = { new DefaultSwatchChooserPanel(), - new DefaultHSBChooserPanel(), - new DefaultRGBChooserPanel() }; - return choosers; + return new AbstractColorChooserPanel[] { + new DefaultSwatchChooserPanel(), + new ColorChooserPanel(new ColorModelHSV()), + new ColorChooserPanel(new ColorModelHSL()), + new ColorChooserPanel(new ColorModel()), + new ColorChooserPanel(new ColorModelCMYK()), + }; } public static JComponent getPreviewPanel() { return new DefaultPreviewPanel(); } - } diff --git a/src/share/classes/javax/swing/colorchooser/ColorChooserPanel.java b/src/share/classes/javax/swing/colorchooser/ColorChooserPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..acd6cdcc3fcfd8865ddec1dd9ae06f7de8c2c1d8 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorChooserPanel.java @@ -0,0 +1,187 @@ +/* + * 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.swing.colorchooser; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JFormattedTextField; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +final class ColorChooserPanel extends AbstractColorChooserPanel implements PropertyChangeListener { + + private static final int MASK = 0xFF000000; + private final ColorModel model; + private final ColorPanel panel; + private final DiagramComponent slider; + private final DiagramComponent diagram; + private final JFormattedTextField text; + private final JLabel label; + + ColorChooserPanel(ColorModel model) { + this.model = model; + this.panel = new ColorPanel(this.model); + this.slider = new DiagramComponent(this.panel, false); + this.diagram = new DiagramComponent(this.panel, true); + this.text = new JFormattedTextField(); + this.label = new JLabel(null, null, SwingConstants.RIGHT); + ValueFormatter.init(6, true, this.text); + } + + @Override + public void updateChooser() { + Color color = getColorFromModel(); + if (color != null) { + this.panel.setColor(color); + this.text.setValue(Integer.valueOf(color.getRGB())); + this.slider.repaint(); + this.diagram.repaint(); + } + } + + @Override + protected void buildChooser() { + if (0 == getComponentCount()) { + setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridx = 3; + gbc.gridwidth = 2; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.NORTH; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets.top = 10; + gbc.insets.right = 10; + add(this.panel, gbc); + + gbc.gridwidth = 1; + gbc.weightx = 1.0; + gbc.weighty = 0.0; + gbc.anchor = GridBagConstraints.CENTER; + gbc.insets.right = 5; + gbc.insets.bottom = 10; + add(this.label, gbc); + + gbc.gridx = 4; + gbc.weightx = 0.0; + gbc.insets.right = 10; + add(this.text, gbc); + + gbc.gridx = 2; + gbc.gridheight = 2; + gbc.anchor = GridBagConstraints.NORTH; + gbc.ipadx = this.text.getPreferredSize().height; + gbc.ipady = getPreferredSize().height; + add(this.slider, gbc); + + gbc.gridx = 1; + gbc.insets.left = 10; + gbc.ipadx = gbc.ipady; + add(this.diagram, gbc); + + this.label.setLabelFor(this.text); + this.text.addPropertyChangeListener("value", this); // NON-NLS: the property name + this.slider.setBorder(this.text.getBorder()); + this.diagram.setBorder(this.text.getBorder()); + + setInheritsPopupMenu(this, true); // CR:4966112 + } + String label = this.model.getText(this, "HexCode"); // NON-NLS: suffix + boolean visible = label != null; + this.text.setVisible(visible); + this.label.setVisible(visible); + if (visible) { + this.label.setText(label); + int mnemonic = this.model.getInteger(this, "HexCodeMnemonic"); // NON-NLS: suffix + if (mnemonic > 0) { + this.label.setDisplayedMnemonic(mnemonic); + mnemonic = this.model.getInteger(this, "HexCodeMnemonicIndex"); // NON-NLS: suffix + if (mnemonic >= 0) { + this.label.setDisplayedMnemonicIndex(mnemonic); + } + } + } + this.panel.buildPanel(); + } + + @Override + public String getDisplayName() { + return this.model.getText(this, "Name"); // NON-NLS: suffix + } + + @Override + public int getMnemonic() { + return this.model.getInteger(this, "Mnemonic"); // NON-NLS: suffix + } + + @Override + public int getDisplayedMnemonicIndex() { + return this.model.getInteger(this, "DisplayedMnemonicIndex"); // NON-NLS: suffix + } + + @Override + public Icon getSmallDisplayIcon() { + return null; + } + + @Override + public Icon getLargeDisplayIcon() { + return null; + } + + public void propertyChange(PropertyChangeEvent event) { + ColorSelectionModel model = getColorSelectionModel(); + if (model != null) { + Object object = event.getNewValue(); + if (object instanceof Integer) { + int value = MASK & model.getSelectedColor().getRGB() | (Integer) object; + model.setSelectedColor(new Color(value, true)); + } + } + this.text.selectAll(); + } + + /** + * Allows to show context popup for all components recursively. + * + * @param component the root component of the tree + * @param value whether or not the popup menu is inherited + */ + private static void setInheritsPopupMenu(JComponent component, boolean value) { + component.setInheritsPopupMenu(value); + for (Object object : component.getComponents()) { + if (object instanceof JComponent) { + setInheritsPopupMenu((JComponent) object, value); + } + } + } +} diff --git a/src/share/classes/javax/swing/colorchooser/ColorModel.java b/src/share/classes/javax/swing/colorchooser/ColorModel.java new file mode 100644 index 0000000000000000000000000000000000000000..955ed162663d6f34434b91f6c2b499590c37c0d6 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorModel.java @@ -0,0 +1,102 @@ +/* + * 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.swing.colorchooser; + +import java.awt.Component; +import javax.swing.UIManager; + +class ColorModel { + + private final String prefix; + private final String[] labels; + + ColorModel(String name, String... labels) { + this.prefix = "ColorChooser." + name; // NON-NLS: default prefix + this.labels = labels; + } + + ColorModel() { + this("rgb", "Red", "Green", "Blue", "Alpha"); // NON-NLS: components + } + + void setColor(int color, float[] model) { + model[0] = normalize(color >> 16); + model[1] = normalize(color >> 8); + model[2] = normalize(color); + model[3] = normalize(color >> 24); + } + + int getColor(float[] model) { + return to8bit(model[2]) | (to8bit(model[1]) << 8) | (to8bit(model[0]) << 16) | (to8bit(model[3]) << 24); + } + + int getCount() { + return this.labels.length; + } + + int getMinimum(int index) { + return 0; + } + + int getMaximum(int index) { + return 255; + } + + float getDefault(int index) { + return 0.0f; + } + + final String getLabel(Component component, int index) { + return getText(component, this.labels[index]); + } + + private static float normalize(int value) { + return (float) (value & 0xFF) / 255.0f; + } + + private static int to8bit(float value) { + return (int) (255.0f * value); + } + + final String getText(Component component, String suffix) { + return UIManager.getString(this.prefix + suffix + "Text", component.getLocale()); // NON-NLS: default postfix + } + + final int getInteger(Component component, String suffix) { + Object value = UIManager.get(this.prefix + suffix, component.getLocale()); + if (value instanceof Integer) { + return (Integer) value; + } + if (value instanceof String) { + try { + return Integer.parseInt((String) value); + } + catch (NumberFormatException exception) { + } + } + return -1; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/ColorModelCMYK.java b/src/share/classes/javax/swing/colorchooser/ColorModelCMYK.java new file mode 100644 index 0000000000000000000000000000000000000000..77a7ca555941f6887945351eeb6a1dc01e7eb938 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorModelCMYK.java @@ -0,0 +1,94 @@ +/* + * 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.swing.colorchooser; + +final class ColorModelCMYK extends ColorModel { + + ColorModelCMYK() { + super("cmyk", "Cyan", "Magenta", "Yellow", "Black", "Alpha"); // NON-NLS: components + } + + @Override + void setColor(int color, float[] space) { + super.setColor(color, space); + space[4] = space[3]; + RGBtoCMYK(space, space); + } + + @Override + int getColor(float[] space) { + CMYKtoRGB(space, space); + space[3] = space[4]; + return super.getColor(space); + } + + /** + * Converts CMYK components of a color to a set of RGB components. + * + * @param cmyk a float array with length equal to + * the number of CMYK components + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @return a float array that contains RGB components + */ + private static float[] CMYKtoRGB(float[] cmyk, float[] rgb) { + if (rgb == null) { + rgb = new float[3]; + } + rgb[0] = 1.0f + cmyk[0] * cmyk[3] - cmyk[3] - cmyk[0]; + rgb[1] = 1.0f + cmyk[1] * cmyk[3] - cmyk[3] - cmyk[1]; + rgb[2] = 1.0f + cmyk[2] * cmyk[3] - cmyk[3] - cmyk[2]; + return rgb; + } + + /** + * Converts RGB components of a color to a set of CMYK components. + * + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @param cmyk a float array with length equal to + * the number of CMYK components + * @return a float array that contains CMYK components + */ + private static float[] RGBtoCMYK(float[] rgb, float[] cmyk) { + if (cmyk == null) { + cmyk = new float[4]; + } + float max = ColorModelHSL.max(rgb[0], rgb[1], rgb[2]); + if (max > 0.0f) { + cmyk[0] = 1.0f - rgb[0] / max; + cmyk[1] = 1.0f - rgb[1] / max; + cmyk[2] = 1.0f - rgb[2] / max; + } + else { + cmyk[0] = 0.0f; + cmyk[1] = 0.0f; + cmyk[2] = 0.0f; + } + cmyk[3] = 1.0f - max; + return cmyk; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/ColorModelHSL.java b/src/share/classes/javax/swing/colorchooser/ColorModelHSL.java new file mode 100644 index 0000000000000000000000000000000000000000..85b0c8e5da4d3b7b129f3498c97875341b799f18 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorModelHSL.java @@ -0,0 +1,188 @@ +/* + * 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.swing.colorchooser; + +final class ColorModelHSL extends ColorModel { + + ColorModelHSL() { + super("hsl", "Hue", "Saturation", "Lightness", "Transparency"); // NON-NLS: components + } + + @Override + void setColor(int color, float[] space) { + super.setColor(color, space); + RGBtoHSL(space, space); + space[3] = 1.0f - space[3]; + } + + @Override + int getColor(float[] space) { + space[3] = 1.0f - space[3]; + HSLtoRGB(space, space); + return super.getColor(space); + } + + @Override + int getMaximum(int index) { + return (index == 0) ? 360 : 100; + } + + @Override + float getDefault(int index) { + return (index == 0) ? -1.0f : (index == 2) ? 0.5f : 1.0f; + } + + /** + * Converts HSL components of a color to a set of RGB components. + * + * @param hsl a float array with length equal to + * the number of HSL components + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @return a float array that contains RGB components + */ + private static float[] HSLtoRGB(float[] hsl, float[] rgb) { + if (rgb == null) { + rgb = new float[3]; + } + float hue = hsl[0]; + float saturation = hsl[1]; + float lightness = hsl[2]; + + if (saturation > 0.0f) { + hue = (hue < 1.0f) ? hue * 6.0f : 0.0f; + float q = lightness + saturation * ((lightness > 0.5f) ? 1.0f - lightness : lightness); + float p = 2.0f * lightness - q; + rgb[0]= normalize(q, p, (hue < 4.0f) ? (hue + 2.0f) : (hue - 4.0f)); + rgb[1]= normalize(q, p, hue); + rgb[2]= normalize(q, p, (hue < 2.0f) ? (hue + 4.0f) : (hue - 2.0f)); + } + else { + rgb[0] = lightness; + rgb[1] = lightness; + rgb[2] = lightness; + } + return rgb; + } + + /** + * Converts RGB components of a color to a set of HSL components. + * + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @param hsl a float array with length equal to + * the number of HSL components + * @return a float array that contains HSL components + */ + private static float[] RGBtoHSL(float[] rgb, float[] hsl) { + if (hsl == null) { + hsl = new float[3]; + } + float max = max(rgb[0], rgb[1], rgb[2]); + float min = min(rgb[0], rgb[1], rgb[2]); + + float summa = max + min; + float saturation = max - min; + if (saturation > 0.0f) { + saturation /= (summa > 1.0f) + ? 2.0f - summa + : summa; + } + hsl[0] = getHue(rgb[0], rgb[1], rgb[2], max, min); + hsl[1] = saturation; + hsl[2] = summa / 2.0f; + return hsl; + } + + /** + * Returns the smaller of three color components. + * + * @param red the red component of the color + * @param green the green component of the color + * @param blue the blue component of the color + * @return the smaller of {@code red}, {@code green} and {@code blue} + */ + static float min(float red, float green, float blue) { + float min = (red < green) ? red : green; + return (min < blue) ? min : blue; + } + + /** + * Returns the larger of three color components. + * + * @param red the red component of the color + * @param green the green component of the color + * @param blue the blue component of the color + * @return the larger of {@code red}, {@code green} and {@code blue} + */ + static float max(float red, float green, float blue) { + float max = (red > green) ? red : green; + return (max > blue) ? max : blue; + } + + /** + * Calculates the hue component for HSL and HSV color spaces. + * + * @param red the red component of the color + * @param green the green component of the color + * @param blue the blue component of the color + * @param max the larger of {@code red}, {@code green} and {@code blue} + * @param min the smaller of {@code red}, {@code green} and {@code blue} + * @return the hue component + */ + static float getHue(float red, float green, float blue, float max, float min) { + float hue = max - min; + if (hue > 0.0f) { + if (max == red) { + hue = (green - blue) / hue; + if (hue < 0.0f) { + hue += 6.0f; + } + } + else if (max == green) { + hue = 2.0f + (blue - red) / hue; + } + else /*max == blue*/ { + hue = 4.0f + (red - green) / hue; + } + hue /= 6.0f; + } + return hue; + } + + private static float normalize(float q, float p, float color) { + if (color < 1.0f) { + return p + (q - p) * color; + } + if (color < 3.0f) { + return q; + } + if (color < 4.0f) { + return p + (q - p) * (4.0f - color); + } + return p; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/ColorModelHSV.java b/src/share/classes/javax/swing/colorchooser/ColorModelHSV.java new file mode 100644 index 0000000000000000000000000000000000000000..e33eef77dfe022919846facabaf23c4deb205823 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorModelHSV.java @@ -0,0 +1,138 @@ +/* + * 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.swing.colorchooser; + +final class ColorModelHSV extends ColorModel { + + ColorModelHSV() { + super("hsv", "Hue", "Saturation", "Value", "Transparency"); // NON-NLS: components + } + + @Override + void setColor(int color, float[] space) { + super.setColor(color, space); + RGBtoHSV(space, space); + space[3] = 1.0f - space[3]; + } + + @Override + int getColor(float[] space) { + space[3] = 1.0f - space[3]; + HSVtoRGB(space, space); + return super.getColor(space); + } + + @Override + int getMaximum(int index) { + return (index == 0) ? 360 : 100; + } + + @Override + float getDefault(int index) { + return (index == 0) ? -1.0f : 1.0f; + } + + /** + * Converts HSV components of a color to a set of RGB components. + * + * @param hsv a float array with length equal to + * the number of HSV components + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @return a float array that contains RGB components + */ + private static float[] HSVtoRGB(float[] hsv, float[] rgb) { + if (rgb == null) { + rgb = new float[3]; + } + float hue = hsv[0]; + float saturation = hsv[1]; + float value = hsv[2]; + + rgb[0] = value; + rgb[1] = value; + rgb[2] = value; + + if (saturation > 0.0f) { + hue = (hue < 1.0f) ? hue * 6.0f : 0.0f; + int integer = (int) hue; + float f = hue - (float) integer; + switch (integer) { + case 0: + rgb[1] *= 1.0f - saturation * (1.0f - f); + rgb[2] *= 1.0f - saturation; + break; + case 1: + rgb[0] *= 1.0f - saturation * f; + rgb[2] *= 1.0f - saturation; + break; + case 2: + rgb[0] *= 1.0f - saturation; + rgb[2] *= 1.0f - saturation * (1.0f - f); + break; + case 3: + rgb[0] *= 1.0f - saturation; + rgb[1] *= 1.0f - saturation * f; + break; + case 4: + rgb[0] *= 1.0f - saturation * (1.0f - f); + rgb[1] *= 1.0f - saturation; + break; + case 5: + rgb[1] *= 1.0f - saturation; + rgb[2] *= 1.0f - saturation * f; + break; + } + } + return rgb; + } + + /** + * Converts RGB components of a color to a set of HSV components. + * + * @param rgb a float array with length of at least 3 + * that contains RGB components of a color + * @param hsv a float array with length equal to + * the number of HSV components + * @return a float array that contains HSV components + */ + private static float[] RGBtoHSV(float[] rgb, float[] hsv) { + if (hsv == null) { + hsv = new float[3]; + } + float max = ColorModelHSL.max(rgb[0], rgb[1], rgb[2]); + float min = ColorModelHSL.min(rgb[0], rgb[1], rgb[2]); + + float saturation = max - min; + if (saturation > 0.0f) { + saturation /= max; + } + hsv[0] = ColorModelHSL.getHue(rgb[0], rgb[1], rgb[2], max, min); + hsv[1] = saturation; + hsv[2] = max; + return hsv; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/ColorPanel.java b/src/share/classes/javax/swing/colorchooser/ColorPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..7cccca630892ffef6f830afd5e3170befb137cc2 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/ColorPanel.java @@ -0,0 +1,210 @@ +/* + * 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.swing.colorchooser; + +import java.awt.Color; +import java.awt.ContainerOrderFocusTraversalPolicy; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.border.EmptyBorder; + +final class ColorPanel extends JPanel implements ActionListener { + + private final SlidingSpinner[] spinners = new SlidingSpinner[5]; + private final float[] values = new float[this.spinners.length]; + + private final ColorModel model; + private Color color; + private int x = 1; + private int y = 2; + private int z; + + ColorPanel(ColorModel model) { + super(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + + gbc.gridx = 1; + ButtonGroup group = new ButtonGroup(); + EmptyBorder border = null; + for (int i = 0; i < this.spinners.length; i++) { + if (i < 3) { + JRadioButton button = new JRadioButton(); + if (i == 0) { + Insets insets = button.getInsets(); + insets.left = button.getPreferredSize().width; + border = new EmptyBorder(insets); + button.setSelected(true); + gbc.insets.top = 5; + } + add(button, gbc); + group.add(button); + button.setActionCommand(Integer.toString(i)); + button.addActionListener(this); + this.spinners[i] = new SlidingSpinner(this, button); + } + else { + JLabel label = new JLabel(); + add(label, gbc); + label.setBorder(border); + label.setFocusable(false); + this.spinners[i] = new SlidingSpinner(this, label); + } + } + gbc.gridx = 2; + gbc.weightx = 1.0; + gbc.insets.top = 0; + gbc.insets.left = 5; + for (SlidingSpinner spinner : this.spinners) { + add(spinner.getSlider(), gbc); + gbc.insets.top = 5; + } + gbc.gridx = 3; + gbc.weightx = 0.0; + gbc.insets.top = 0; + for (SlidingSpinner spinner : this.spinners) { + add(spinner.getSpinner(), gbc); + gbc.insets.top = 5; + } + setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy()); + setFocusTraversalPolicyProvider(true); + setFocusable(false); + + this.model = model; + } + + public void actionPerformed(ActionEvent event) { + try { + this.z = Integer.parseInt(event.getActionCommand()); + this.y = (this.z != 2) ? 2 : 1; + this.x = (this.z != 0) ? 0 : 1; + getParent().repaint(); + } + catch (NumberFormatException exception) { + } + } + + void buildPanel() { + int count = this.model.getCount(); + this.spinners[4].setVisible(count > 4); + for (int i = 0; i < count; i++) { + Object object = this.spinners[i].getLabel(); + if (object instanceof JRadioButton) { + JRadioButton button = (JRadioButton) object; + button.setText(this.model.getLabel(this, i)); + } + else if (object instanceof JLabel) { + JLabel label = (JLabel) object; + label.setText(this.model.getLabel(this, i)); + } + this.spinners[i].setRange(this.model.getMinimum(i), this.model.getMaximum(i)); + this.spinners[i].setValue(this.values[i]); + } + } + + void colorChanged() { + this.color = new Color(getColor(0), true); + Object parent = getParent(); + if (parent instanceof ColorChooserPanel) { + ColorChooserPanel chooser = (ColorChooserPanel) parent; + chooser.setSelectedColor(this.color); + chooser.repaint(); + } + } + + float getValueX() { + return this.spinners[this.x].getValue(); + } + + float getValueY() { + return 1.0f - this.spinners[this.y].getValue(); + } + + float getValueZ() { + return 1.0f - this.spinners[this.z].getValue(); + } + + void setValue(float z) { + this.spinners[this.z].setValue(1.0f - z); + colorChanged(); + } + + void setValue(float x, float y) { + this.spinners[this.x].setValue(x); + this.spinners[this.y].setValue(1.0f - y); + colorChanged(); + } + + int getColor(float z) { + setDefaultValue(this.x); + setDefaultValue(this.y); + this.values[this.z] = 1.0f - z; + return getColor(3); + } + + int getColor(float x, float y) { + this.values[this.x] = x; + this.values[this.y] = 1.0f - y; + setValue(this.z); + return getColor(3); + } + + void setColor(Color color) { + if (!color.equals(this.color)) { + this.color = color; + this.model.setColor(color.getRGB(), this.values); + for (int i = 0; i < this.model.getCount(); i++) { + this.spinners[i].setValue(this.values[i]); + } + } + } + + private int getColor(int index) { + while (index < this.model.getCount()) { + setValue(index++); + } + return this.model.getColor(this.values); + } + + private void setValue(int index) { + this.values[index] = this.spinners[index].getValue(); + } + + private void setDefaultValue(int index) { + float value = this.model.getDefault(index); + this.values[index] = (value < 0.0f) + ? this.spinners[index].getValue() + : value; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/DefaultHSBChooserPanel.java b/src/share/classes/javax/swing/colorchooser/DefaultHSBChooserPanel.java deleted file mode 100644 index 89759e247a49c1cfdcb9247699138fe76a2cb244..0000000000000000000000000000000000000000 --- a/src/share/classes/javax/swing/colorchooser/DefaultHSBChooserPanel.java +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright 1998-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 javax.swing.colorchooser; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import javax.swing.event.*; -import javax.swing.border.*; -import java.awt.image.*; -import java.util.Locale; - -/** - * Implements the default HSB Color chooser - * - * @author Tom Santos - * @author Steve Wilson - * @author Mark Davidson - * @author Shannon Hickey - */ -class DefaultHSBChooserPanel extends AbstractColorChooserPanel implements ChangeListener, HierarchyListener { - - private transient HSBImage palette; - private transient HSBImage sliderPalette; - - private transient Image paletteImage; - private transient Image sliderPaletteImage; - - private JSlider slider; - private JSpinner hField; - private JSpinner sField; - private JSpinner bField; - - private JTextField redField; - private JTextField greenField; - private JTextField blueField; - - private boolean isAdjusting = false; // Flag which indicates that values are set internally - private Point paletteSelection = new Point(); - private JLabel paletteLabel; - private JLabel sliderPaletteLabel; - - private JRadioButton hRadio; - private JRadioButton sRadio; - private JRadioButton bRadio; - - private static final int PALETTE_DIMENSION = 200; - private static final int MAX_HUE_VALUE = 359; - private static final int MAX_SATURATION_VALUE = 100; - private static final int MAX_BRIGHTNESS_VALUE = 100; - - private int currentMode = HUE_MODE; - - private static final int HUE_MODE = 0; - private static final int SATURATION_MODE = 1; - private static final int BRIGHTNESS_MODE = 2; - - public DefaultHSBChooserPanel() { - } - - private void addPaletteListeners() { - paletteLabel.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e ) { - float[] hsb = new float[3]; - palette.getHSBForLocation( e.getX(), e.getY(), hsb ); - updateHSB( hsb[0], hsb[1], hsb[2] ); - } - }); - - paletteLabel.addMouseMotionListener(new MouseMotionAdapter() { - public void mouseDragged( MouseEvent e ){ - int labelWidth = paletteLabel.getWidth(); - - int labelHeight = paletteLabel.getHeight(); - int x = e.getX(); - int y = e.getY(); - - if ( x >= labelWidth ) { - x = labelWidth - 1; - } - - if ( y >= labelHeight ) { - y = labelHeight - 1; - } - - if ( x < 0 ) { - x = 0; - } - - if ( y < 0 ) { - y = 0; - } - - float[] hsb = new float[3]; - palette.getHSBForLocation( x, y, hsb ); - updateHSB( hsb[0], hsb[1], hsb[2] ); - } - }); - } - - private void updatePalette( float h, float s, float b ) { - int x = 0; - int y = 0; - - switch ( currentMode ) { - case HUE_MODE: - if ( h != palette.getHue() ) { - palette.setHue( h ); - palette.nextFrame(); - } - x = PALETTE_DIMENSION - (int)(s * PALETTE_DIMENSION); - y = PALETTE_DIMENSION - (int)(b * PALETTE_DIMENSION); - break; - case SATURATION_MODE: - if ( s != palette.getSaturation() ) { - palette.setSaturation( s ); - palette.nextFrame(); - } - x = (int)(h * PALETTE_DIMENSION); - y = PALETTE_DIMENSION - (int)(b * PALETTE_DIMENSION); - break; - case BRIGHTNESS_MODE: - if ( b != palette.getBrightness() ) { - palette.setBrightness( b ); - palette.nextFrame(); - } - x = (int)(h * PALETTE_DIMENSION); - y = PALETTE_DIMENSION - (int)(s * PALETTE_DIMENSION); - break; - } - - paletteSelection.setLocation( x, y ); - paletteLabel.repaint(); - } - - private void updateSlider( float h, float s, float b ) { - // Update the slider palette if necessary. - // When the slider is the hue slider or the hue hasn't changed, - // the hue of the palette will not need to be updated. - if (currentMode != HUE_MODE && h != sliderPalette.getHue() ) { - sliderPalette.setHue( h ); - sliderPalette.nextFrame(); - } - - float value = 0f; - - switch ( currentMode ) { - case HUE_MODE: - value = h; - break; - case SATURATION_MODE: - value = s; - break; - case BRIGHTNESS_MODE: - value = b; - break; - } - - slider.setValue( Math.round(value * (slider.getMaximum())) ); - } - - private void updateHSBTextFields( float hue, float saturation, float brightness ) { - int h = Math.round(hue * 359); - int s = Math.round(saturation * 100); - int b = Math.round(brightness * 100); - - if (((Integer)hField.getValue()).intValue() != h) { - hField.setValue(new Integer(h)); - } - if (((Integer)sField.getValue()).intValue() != s) { - sField.setValue(new Integer(s)); - } - if (((Integer)bField.getValue()).intValue() != b) { - bField.setValue(new Integer(b)); - } - } - - /** - * Updates the values of the RGB fields to reflect the new color change - */ - private void updateRGBTextFields( Color color ) { - redField.setText(String.valueOf(color.getRed())); - greenField.setText(String.valueOf(color.getGreen())); - blueField.setText(String.valueOf(color.getBlue())); - } - - /** - * Main internal method of updating the ui controls and the color model. - */ - private void updateHSB( float h, float s, float b ) { - if ( !isAdjusting ) { - isAdjusting = true; - - updatePalette( h, s, b ); - updateSlider( h, s, b ); - updateHSBTextFields( h, s, b ); - - Color color = Color.getHSBColor(h, s, b); - updateRGBTextFields( color ); - - getColorSelectionModel().setSelectedColor( color ); - - isAdjusting = false; - } - } - - /** - * Invoked automatically when the model's state changes. - * It is also called by installChooserPanel to allow - * you to set up the initial state of your chooser. - * Override this method to update your ChooserPanel. - */ - public void updateChooser() { - if ( !isAdjusting ) { - float[] hsb = getHSBColorFromModel(); - updateHSB( hsb[0], hsb[1], hsb[2] ); - } - } - - public void installChooserPanel(JColorChooser enclosingChooser) { - super.installChooserPanel(enclosingChooser); - setInheritsPopupMenu(true); - addHierarchyListener(this); - } - - /** - * Invoked when the panel is removed from the chooser. - */ - public void uninstallChooserPanel(JColorChooser enclosingChooser) { - super.uninstallChooserPanel(enclosingChooser); - cleanupPalettesIfNecessary(); - removeAll(); - removeHierarchyListener(this); - } - - /** - * Returns an float array containing the HSB values of the selected color from - * the ColorSelectionModel - */ - private float[] getHSBColorFromModel() { - Color color = getColorFromModel(); - float[] hsb = new float[3]; - Color.RGBtoHSB( color.getRed(), color.getGreen(), color.getBlue(), hsb ); - - return hsb; - } - - /** - * Builds a new chooser panel. - */ - protected void buildChooser() { - setLayout(new BorderLayout()); - JComponent spp = buildSliderPalettePanel(); - spp.setInheritsPopupMenu(true); - add(spp, BorderLayout.BEFORE_LINE_BEGINS); - - JPanel controlHolder = new JPanel(new SmartGridLayout(1,3)); - JComponent hsbControls = buildHSBControls(); - hsbControls.setInheritsPopupMenu(true); - controlHolder.add(hsbControls); - - controlHolder.add(new JLabel(" ")); // spacer - - JComponent rgbControls = buildRGBControls(); - rgbControls.setInheritsPopupMenu(true); - controlHolder.add(rgbControls); - controlHolder.setInheritsPopupMenu(true); - - controlHolder.setBorder(new EmptyBorder( 10, 5, 10, 5)); - add( controlHolder, BorderLayout.CENTER); - } - - /** - * Creates the panel with the uneditable RGB field - */ - private JComponent buildRGBControls() { - JPanel panel = new JPanel(new SmartGridLayout(2,3)); - panel.setInheritsPopupMenu(true); - - Color color = getColorFromModel(); - redField = new JTextField( String.valueOf(color.getRed()), 3 ); - redField.setEditable(false); - redField.setHorizontalAlignment( JTextField.RIGHT ); - redField.setInheritsPopupMenu(true); - - greenField = new JTextField(String.valueOf(color.getGreen()), 3 ); - greenField.setEditable(false); - greenField.setHorizontalAlignment( JTextField.RIGHT ); - greenField.setInheritsPopupMenu(true); - - blueField = new JTextField( String.valueOf(color.getBlue()), 3 ); - blueField.setEditable(false); - blueField.setHorizontalAlignment( JTextField.RIGHT ); - blueField.setInheritsPopupMenu(true); - - Locale locale = getLocale(); - String redString = UIManager.getString("ColorChooser.hsbRedText", locale); - String greenString = UIManager.getString("ColorChooser.hsbGreenText", locale); - String blueString = UIManager.getString("ColorChooser.hsbBlueText", locale); - - panel.add( new JLabel(redString) ); - panel.add( redField ); - panel.add( new JLabel(greenString) ); - panel.add( greenField ); - panel.add( new JLabel(blueString) ); - panel.add( blueField ); - - return panel; - } - - /** - * Creates the panel with the editable HSB fields and the radio buttons. - */ - private JComponent buildHSBControls() { - - Locale locale = getLocale(); - String hueString = UIManager.getString("ColorChooser.hsbHueText", locale); - String saturationString = UIManager.getString("ColorChooser.hsbSaturationText", locale); - String brightnessString = UIManager.getString("ColorChooser.hsbBrightnessText", locale); - - RadioButtonHandler handler = new RadioButtonHandler(); - - hRadio = new JRadioButton(hueString); - hRadio.addActionListener(handler); - hRadio.setSelected(true); - hRadio.setInheritsPopupMenu(true); - - sRadio = new JRadioButton(saturationString); - sRadio.addActionListener(handler); - sRadio.setInheritsPopupMenu(true); - - bRadio = new JRadioButton(brightnessString); - bRadio.addActionListener(handler); - bRadio.setInheritsPopupMenu(true); - - ButtonGroup group = new ButtonGroup(); - group.add(hRadio); - group.add(sRadio); - group.add(bRadio); - - float[] hsb = getHSBColorFromModel(); - - hField = new JSpinner(new SpinnerNumberModel((int)(hsb[0] * 359), 0, 359, 1)); - sField = new JSpinner(new SpinnerNumberModel((int)(hsb[1] * 100), 0, 100, 1)); - bField = new JSpinner(new SpinnerNumberModel((int)(hsb[2] * 100), 0, 100, 1)); - - hField.addChangeListener(this); - sField.addChangeListener(this); - bField.addChangeListener(this); - - hField.setInheritsPopupMenu(true); - sField.setInheritsPopupMenu(true); - bField.setInheritsPopupMenu(true); - - JPanel panel = new JPanel( new SmartGridLayout(2, 3) ); - - panel.add(hRadio); - panel.add(hField); - panel.add(sRadio); - panel.add(sField); - panel.add(bRadio); - panel.add(bField); - panel.setInheritsPopupMenu(true); - - return panel; - } - - /** - * Handler for the radio button classes. - */ - private class RadioButtonHandler implements ActionListener { - public void actionPerformed(ActionEvent evt) { - Object obj = evt.getSource(); - - if (obj instanceof JRadioButton) { - JRadioButton button = (JRadioButton)obj; - if (button == hRadio) { - setMode(HUE_MODE); - } else if (button == sRadio) { - setMode(SATURATION_MODE); - } else if (button == bRadio) { - setMode(BRIGHTNESS_MODE); - } - } - } - } - - private void setMode(int mode) { - if (currentMode == mode) { - return; - } - - isAdjusting = true; // Ensure no events propagate from changing slider value. - currentMode = mode; - - float[] hsb = getHSBColorFromModel(); - - switch (currentMode) { - case HUE_MODE: - slider.setInverted(true); - slider.setMaximum(MAX_HUE_VALUE); - palette.setValues(HSBImage.HSQUARE, hsb[0], 1.0f, 1.0f); - sliderPalette.setValues(HSBImage.HSLIDER, 0f, 1.0f, 1.0f); - break; - case SATURATION_MODE: - slider.setInverted(false); - slider.setMaximum(MAX_SATURATION_VALUE); - palette.setValues(HSBImage.SSQUARE, hsb[0], hsb[1], 1.0f); - sliderPalette.setValues(HSBImage.SSLIDER, hsb[0], 1.0f, 1.0f); - break; - case BRIGHTNESS_MODE: - slider.setInverted(false); - slider.setMaximum(MAX_BRIGHTNESS_VALUE); - palette.setValues(HSBImage.BSQUARE, hsb[0], 1.0f, hsb[2]); - sliderPalette.setValues(HSBImage.BSLIDER, hsb[0], 1.0f, 1.0f); - break; - } - - isAdjusting = false; - - palette.nextFrame(); - sliderPalette.nextFrame(); - - updateChooser(); - } - - protected JComponent buildSliderPalettePanel() { - - // This slider has to have a minimum of 0. A lot of math in this file is simplified due to this. - slider = new JSlider(JSlider.VERTICAL, 0, MAX_HUE_VALUE, 0); - slider.setInverted(true); - slider.setPaintTrack(false); - slider.setPreferredSize(new Dimension(slider.getPreferredSize().width, PALETTE_DIMENSION + 15)); - slider.addChangeListener(this); - slider.setInheritsPopupMenu(true); - // We're not painting ticks, but need to ask UI classes to - // paint arrow shape anyway, if possible. - slider.putClientProperty("Slider.paintThumbArrowShape", Boolean.TRUE); - paletteLabel = createPaletteLabel(); - addPaletteListeners(); - sliderPaletteLabel = new JLabel(); - - JPanel panel = new JPanel(); - panel.add( paletteLabel ); - panel.add( slider ); - panel.add( sliderPaletteLabel ); - - initializePalettesIfNecessary(); - - return panel; - } - - private void initializePalettesIfNecessary() { - if (palette != null) { - return; - } - - float[] hsb = getHSBColorFromModel(); - - switch(currentMode){ - case HUE_MODE: - palette = new HSBImage(HSBImage.HSQUARE, PALETTE_DIMENSION, PALETTE_DIMENSION, hsb[0], 1.0f, 1.0f); - sliderPalette = new HSBImage(HSBImage.HSLIDER, 16, PALETTE_DIMENSION, 0f, 1.0f, 1.0f); - break; - case SATURATION_MODE: - palette = new HSBImage(HSBImage.SSQUARE, PALETTE_DIMENSION, PALETTE_DIMENSION, 1.0f, hsb[1], 1.0f); - sliderPalette = new HSBImage(HSBImage.SSLIDER, 16, PALETTE_DIMENSION, 1.0f, 0f, 1.0f); - break; - case BRIGHTNESS_MODE: - palette = new HSBImage(HSBImage.BSQUARE, PALETTE_DIMENSION, PALETTE_DIMENSION, 1.0f, 1.0f, hsb[2]); - sliderPalette = new HSBImage(HSBImage.BSLIDER, 16, PALETTE_DIMENSION, 1.0f, 1.0f, 0f); - break; - } - paletteImage = Toolkit.getDefaultToolkit().createImage(palette); - sliderPaletteImage = Toolkit.getDefaultToolkit().createImage(sliderPalette); - - paletteLabel.setIcon(new ImageIcon(paletteImage)); - sliderPaletteLabel.setIcon(new ImageIcon(sliderPaletteImage)); - } - - private void cleanupPalettesIfNecessary() { - if (palette == null) { - return; - } - - palette.aborted = true; - sliderPalette.aborted = true; - - palette.nextFrame(); - sliderPalette.nextFrame(); - - palette = null; - sliderPalette = null; - - paletteImage = null; - sliderPaletteImage = null; - - paletteLabel.setIcon(null); - sliderPaletteLabel.setIcon(null); - } - - protected JLabel createPaletteLabel() { - return new JLabel() { - protected void paintComponent( Graphics g ) { - super.paintComponent( g ); - g.setColor( Color.white ); - g.drawOval( paletteSelection.x - 4, paletteSelection.y - 4, 8, 8 ); - } - }; - } - - public String getDisplayName() { - return UIManager.getString("ColorChooser.hsbNameText", getLocale()); - } - - /** - * Provides a hint to the look and feel as to the - * KeyEvent.VK constant that can be used as a mnemonic to - * access the panel. A return value <= 0 indicates there is no mnemonic. - *

      - * The return value here is a hint, it is ultimately up to the look - * and feel to honor the return value in some meaningful way. - *

      - * This implementation looks up the value from the default - * ColorChooser.hsbMnemonic, or if it - * isn't available (or not an Integer) returns -1. - * The lookup for the default is done through the UIManager: - * UIManager.get("ColorChooser.rgbMnemonic");. - * - * @return KeyEvent.VK constant identifying the mnemonic; <= 0 for no - * mnemonic - * @see #getDisplayedMnemonicIndex - * @since 1.4 - */ - public int getMnemonic() { - return getInt("ColorChooser.hsbMnemonic", -1); - } - - /** - * Provides a hint to the look and feel as to the index of the character in - * getDisplayName that should be visually identified as the - * mnemonic. The look and feel should only use this if - * getMnemonic returns a value > 0. - *

      - * The return value here is a hint, it is ultimately up to the look - * and feel to honor the return value in some meaningful way. For example, - * a look and feel may wish to render each - * AbstractColorChooserPanel in a JTabbedPane, - * and further use this return value to underline a character in - * the getDisplayName. - *

      - * This implementation looks up the value from the default - * ColorChooser.rgbDisplayedMnemonicIndex, or if it - * isn't available (or not an Integer) returns -1. - * The lookup for the default is done through the UIManager: - * UIManager.get("ColorChooser.hsbDisplayedMnemonicIndex");. - * - * @return Character index to render mnemonic for; -1 to provide no - * visual identifier for this panel. - * @see #getMnemonic - * @since 1.4 - */ - public int getDisplayedMnemonicIndex() { - return getInt("ColorChooser.hsbDisplayedMnemonicIndex", -1); - } - - public Icon getSmallDisplayIcon() { - return null; - } - - public Icon getLargeDisplayIcon() { - return null; - } - - /** - * Class for the slider and palette images. - */ - class HSBImage extends SyntheticImage { - protected float h = .0f; - protected float s = .0f; - protected float b = .0f; - protected float[] hsb = new float[3]; - - protected boolean isDirty = true; - protected int cachedY; - protected int cachedColor; - protected int type; - - private static final int HSQUARE = 0; - private static final int SSQUARE = 1; - private static final int BSQUARE = 2; - private static final int HSLIDER = 3; - private static final int SSLIDER = 4; - private static final int BSLIDER = 5; - - protected HSBImage(int type, int width, int height, float h, float s, float b) { - super(width, height); - setValues(type, h, s, b); - } - - public void setValues(int type, float h, float s, float b) { - this.type = type; - cachedY = -1; - cachedColor = 0; - setHue( h ); - setSaturation( s ); - setBrightness( b ); - } - - public final void setHue( float hue ) { - h = hue; - } - - public final void setSaturation( float saturation ) { - s = saturation; - } - - public final void setBrightness( float brightness ) { - b = brightness; - } - - public final float getHue() { - return h; - } - - public final float getSaturation() { - return s; - } - - public final float getBrightness() { - return b; - } - - protected boolean isStatic() { - return false; - } - - public synchronized void nextFrame() { - isDirty = true; - notifyAll(); - } - - public synchronized void addConsumer(ImageConsumer ic) { - isDirty = true; - super.addConsumer(ic); - } - - private int getRGBForLocation( int x, int y ) { - if (type >= HSLIDER && y == cachedY) { - return cachedColor; - } - - getHSBForLocation( x, y, hsb ); - cachedY = y; - cachedColor = Color.HSBtoRGB( hsb[0], hsb[1], hsb[2] ); - - return cachedColor; - } - - public void getHSBForLocation( int x, int y, float[] hsbArray ) { - switch (type) { - case HSQUARE: { - float saturationStep = ((float)x) / width; - float brightnessStep = ((float)y) / height; - hsbArray[0] = h; - hsbArray[1] = s - saturationStep; - hsbArray[2] = b - brightnessStep; - break; - } - case SSQUARE: { - float brightnessStep = ((float)y) / height; - float step = 1.0f / ((float)width); - hsbArray[0] = x * step; - hsbArray[1] = s; - hsbArray[2] = 1.0f - brightnessStep; - break; - } - case BSQUARE: { - float saturationStep = ((float)y) / height; - float step = 1.0f / ((float)width); - hsbArray[0] = x * step; - hsbArray[1] = 1.0f - saturationStep; - hsbArray[2] = b; - break; - } - case HSLIDER: { - float step = 1.0f / ((float)height); - hsbArray[0] = y * step; - hsbArray[1] = s; - hsbArray[2] = b; - break; - } - case SSLIDER: { - float saturationStep = ((float)y) / height; - hsbArray[0] = h; - hsbArray[1] = s - saturationStep; - hsbArray[2] = b; - break; - } - case BSLIDER: { - float brightnessStep = ((float)y) / height; - hsbArray[0] = h; - hsbArray[1] = s; - hsbArray[2] = b - brightnessStep; - break; - } - } - } - - /** - * Overriden method from SyntheticImage - */ - protected void computeRow( int y, int[] row ) { - if ( y == 0 ) { - synchronized ( this ) { - try { - while ( !isDirty ) { - wait(); - } - } catch (InterruptedException ie) { - } - isDirty = false; - } - } - - if (aborted) { - return; - } - - for ( int i = 0; i < row.length; ++i ) { - row[i] = getRGBForLocation( i, y ); - } - } - } - - public void stateChanged(ChangeEvent e) { - if (e.getSource() == slider) { - boolean modelIsAdjusting = slider.getModel().getValueIsAdjusting(); - - if (!modelIsAdjusting && !isAdjusting) { - int sliderValue = slider.getValue(); - int sliderRange = slider.getMaximum(); - float value = (float)sliderValue / (float)sliderRange; - - float[] hsb = getHSBColorFromModel(); - - switch ( currentMode ){ - case HUE_MODE: - updateHSB(value, hsb[1], hsb[2]); - break; - case SATURATION_MODE: - updateHSB(hsb[0], value, hsb[2]); - break; - case BRIGHTNESS_MODE: - updateHSB(hsb[0], hsb[1], value); - break; - } - } - } else if (e.getSource() instanceof JSpinner) { - float hue = ((Integer)hField.getValue()).floatValue() / 359f; - float saturation = ((Integer)sField.getValue()).floatValue() / 100f; - float brightness = ((Integer)bField.getValue()).floatValue() / 100f; - - updateHSB(hue, saturation, brightness); - } - } - - public void hierarchyChanged(HierarchyEvent he) { - if ((he.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) { - if (isDisplayable()) { - initializePalettesIfNecessary(); - } else { - cleanupPalettesIfNecessary(); - } - } - } - -} diff --git a/src/share/classes/javax/swing/colorchooser/DefaultRGBChooserPanel.java b/src/share/classes/javax/swing/colorchooser/DefaultRGBChooserPanel.java deleted file mode 100644 index 28850dffaac1e5fad906ccd9d86c2d07b8a130ef..0000000000000000000000000000000000000000 --- a/src/share/classes/javax/swing/colorchooser/DefaultRGBChooserPanel.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 1998-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 javax.swing.colorchooser; - -import javax.swing.*; -import javax.swing.event.*; -import java.awt.*; -import java.util.Locale; - -/** - * The standard RGB chooser. - *

      - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is - * appropriate for short term storage or RMI between applications running - * the same version of Swing. As of 1.4, support for long term storage - * of all JavaBeansTM - * has been added to the java.beans package. - * Please see {@link java.beans.XMLEncoder}. - * - * @author Steve Wilson - * @author Mark Davidson - * @see JColorChooser - * @see AbstractColorChooserPanel - */ -class DefaultRGBChooserPanel extends AbstractColorChooserPanel implements ChangeListener { - - protected JSlider redSlider; - protected JSlider greenSlider; - protected JSlider blueSlider; - protected JSpinner redField; - protected JSpinner blueField; - protected JSpinner greenField; - - private final int minValue = 0; - private final int maxValue = 255; - - private boolean isAdjusting = false; // indicates the fields are being set internally - - public DefaultRGBChooserPanel() { - super(); - setInheritsPopupMenu(true); - } - - /** - * Sets the values of the controls to reflect the color - */ - private void setColor( Color newColor ) { - int red = newColor.getRed(); - int blue = newColor.getBlue(); - int green = newColor.getGreen(); - - if (redSlider.getValue() != red) { - redSlider.setValue(red); - } - if (greenSlider.getValue() != green) { - greenSlider.setValue(green); - } - if (blueSlider.getValue() != blue) { - blueSlider.setValue(blue); - } - - if (((Integer)redField.getValue()).intValue() != red) - redField.setValue(new Integer(red)); - if (((Integer)greenField.getValue()).intValue() != green) - greenField.setValue(new Integer(green)); - if (((Integer)blueField.getValue()).intValue() != blue ) - blueField.setValue(new Integer(blue)); - } - - public String getDisplayName() { - return UIManager.getString("ColorChooser.rgbNameText", getLocale()); - } - - /** - * Provides a hint to the look and feel as to the - * KeyEvent.VK constant that can be used as a mnemonic to - * access the panel. A return value <= 0 indicates there is no mnemonic. - *

      - * The return value here is a hint, it is ultimately up to the look - * and feel to honor the return value in some meaningful way. - *

      - * This implementation looks up the value from the default - * ColorChooser.rgbMnemonic, or if it - * isn't available (or not an Integer) returns -1. - * The lookup for the default is done through the UIManager: - * UIManager.get("ColorChooser.rgbMnemonic");. - * - * @return KeyEvent.VK constant identifying the mnemonic; <= 0 for no - * mnemonic - * @see #getDisplayedMnemonicIndex - * @since 1.4 - */ - public int getMnemonic() { - return getInt("ColorChooser.rgbMnemonic", -1); - } - - /** - * Provides a hint to the look and feel as to the index of the character in - * getDisplayName that should be visually identified as the - * mnemonic. The look and feel should only use this if - * getMnemonic returns a value > 0. - *

      - * The return value here is a hint, it is ultimately up to the look - * and feel to honor the return value in some meaningful way. For example, - * a look and feel may wish to render each - * AbstractColorChooserPanel in a JTabbedPane, - * and further use this return value to underline a character in - * the getDisplayName. - *

      - * This implementation looks up the value from the default - * ColorChooser.rgbDisplayedMnemonicIndex, or if it - * isn't available (or not an Integer) returns -1. - * The lookup for the default is done through the UIManager: - * UIManager.get("ColorChooser.rgbDisplayedMnemonicIndex");. - * - * @return Character index to render mnemonic for; -1 to provide no - * visual identifier for this panel. - * @see #getMnemonic - * @since 1.4 - */ - public int getDisplayedMnemonicIndex() { - return getInt("ColorChooser.rgbDisplayedMnemonicIndex", -1); - } - - public Icon getSmallDisplayIcon() { - return null; - } - - public Icon getLargeDisplayIcon() { - return null; - } - - /** - * The background color, foreground color, and font are already set to the - * defaults from the defaults table before this method is called. - */ - public void installChooserPanel(JColorChooser enclosingChooser) { - super.installChooserPanel(enclosingChooser); - } - - protected void buildChooser() { - - Locale locale = getLocale(); - String redString = UIManager.getString("ColorChooser.rgbRedText", locale); - String greenString = UIManager.getString("ColorChooser.rgbGreenText", locale); - String blueString = UIManager.getString("ColorChooser.rgbBlueText", locale); - - setLayout( new BorderLayout() ); - Color color = getColorFromModel(); - - - JPanel enclosure = new JPanel(); - enclosure.setLayout( new SmartGridLayout( 3, 3 ) ); - enclosure.setInheritsPopupMenu(true); - - // The panel that holds the sliders - - add( enclosure, BorderLayout.CENTER ); - // sliderPanel.setBorder(new LineBorder(Color.black)); - - // The row for the red value - JLabel l = new JLabel(redString); - l.setDisplayedMnemonic(getInt("ColorChooser.rgbRedMnemonic", -1)); - enclosure.add(l); - redSlider = new JSlider(JSlider.HORIZONTAL, 0, 255, color.getRed()); - redSlider.setMajorTickSpacing( 85 ); - redSlider.setMinorTickSpacing( 17 ); - redSlider.setPaintTicks( true ); - redSlider.setPaintLabels( true ); - redSlider.setInheritsPopupMenu(true); - enclosure.add( redSlider ); - redField = new JSpinner( - new SpinnerNumberModel(color.getRed(), minValue, maxValue, 1)); - l.setLabelFor(redSlider); - redField.setInheritsPopupMenu(true); - JPanel redFieldHolder = new JPanel(new CenterLayout()); - redFieldHolder.setInheritsPopupMenu(true); - redField.addChangeListener(this); - redFieldHolder.add(redField); - enclosure.add(redFieldHolder); - - - // The row for the green value - l = new JLabel(greenString); - l.setDisplayedMnemonic(getInt("ColorChooser.rgbGreenMnemonic", -1)); - enclosure.add(l); - greenSlider = new JSlider(JSlider.HORIZONTAL, 0, 255, color.getGreen()); - greenSlider.setMajorTickSpacing( 85 ); - greenSlider.setMinorTickSpacing( 17 ); - greenSlider.setPaintTicks( true ); - greenSlider.setPaintLabels( true ); - greenSlider.setInheritsPopupMenu(true); - enclosure.add(greenSlider); - greenField = new JSpinner( - new SpinnerNumberModel(color.getGreen(), minValue, maxValue, 1)); - l.setLabelFor(greenSlider); - greenField.setInheritsPopupMenu(true); - JPanel greenFieldHolder = new JPanel(new CenterLayout()); - greenFieldHolder.add(greenField); - greenFieldHolder.setInheritsPopupMenu(true); - greenField.addChangeListener(this); - enclosure.add(greenFieldHolder); - - // The slider for the blue value - l = new JLabel(blueString); - l.setDisplayedMnemonic(getInt("ColorChooser.rgbBlueMnemonic", -1)); - enclosure.add(l); - blueSlider = new JSlider(JSlider.HORIZONTAL, 0, 255, color.getBlue()); - blueSlider.setMajorTickSpacing( 85 ); - blueSlider.setMinorTickSpacing( 17 ); - blueSlider.setPaintTicks( true ); - blueSlider.setPaintLabels( true ); - blueSlider.setInheritsPopupMenu(true); - enclosure.add(blueSlider); - blueField = new JSpinner( - new SpinnerNumberModel(color.getBlue(), minValue, maxValue, 1)); - l.setLabelFor(blueSlider); - blueField.setInheritsPopupMenu(true); - JPanel blueFieldHolder = new JPanel(new CenterLayout()); - blueFieldHolder.add(blueField); - blueField.addChangeListener(this); - blueFieldHolder.setInheritsPopupMenu(true); - enclosure.add(blueFieldHolder); - - redSlider.addChangeListener( this ); - greenSlider.addChangeListener( this ); - blueSlider.addChangeListener( this ); - - redSlider.putClientProperty("JSlider.isFilled", Boolean.TRUE); - greenSlider.putClientProperty("JSlider.isFilled", Boolean.TRUE); - blueSlider.putClientProperty("JSlider.isFilled", Boolean.TRUE); - } - - public void uninstallChooserPanel(JColorChooser enclosingChooser) { - super.uninstallChooserPanel(enclosingChooser); - removeAll(); - } - - public void updateChooser() { - if (!isAdjusting) { - isAdjusting = true; - - setColor(getColorFromModel()); - - isAdjusting = false; - } - } - - public void stateChanged( ChangeEvent e ) { - if ( e.getSource() instanceof JSlider && !isAdjusting) { - - int red = redSlider.getValue(); - int green = greenSlider.getValue(); - int blue = blueSlider.getValue() ; - Color color = new Color (red, green, blue); - - getColorSelectionModel().setSelectedColor(color); - } else if (e.getSource() instanceof JSpinner && !isAdjusting) { - - int red = ((Integer)redField.getValue()).intValue(); - int green = ((Integer)greenField.getValue()).intValue(); - int blue = ((Integer)blueField.getValue()).intValue(); - Color color = new Color (red, green, blue); - - getColorSelectionModel().setSelectedColor(color); - } - } - -} diff --git a/src/share/classes/javax/swing/colorchooser/DefaultSwatchChooserPanel.java b/src/share/classes/javax/swing/colorchooser/DefaultSwatchChooserPanel.java index 779b664a2804f612787a431e8612311cb7283a2e..3cbd0df3b855bfc8a114967f97dea59f2458d9aa 100644 --- a/src/share/classes/javax/swing/colorchooser/DefaultSwatchChooserPanel.java +++ b/src/share/classes/javax/swing/colorchooser/DefaultSwatchChooserPanel.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 @@ -213,17 +213,15 @@ class DefaultSwatchChooserPanel extends AbstractColorChooserPanel { class RecentSwatchListener extends MouseAdapter implements Serializable { public void mousePressed(MouseEvent e) { Color color = recentSwatchPanel.getColorForLocation(e.getX(), e.getY()); - getColorSelectionModel().setSelectedColor(color); - + setSelectedColor(color); } } class MainSwatchListener extends MouseAdapter implements Serializable { public void mousePressed(MouseEvent e) { Color color = swatchPanel.getColorForLocation(e.getX(), e.getY()); - getColorSelectionModel().setSelectedColor(color); + setSelectedColor(color); recentSwatchPanel.setMostRecentColor(color); - } } diff --git a/src/share/classes/javax/swing/colorchooser/DiagramComponent.java b/src/share/classes/javax/swing/colorchooser/DiagramComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..04905589e992e1e1e4718fffb9f00e132f84d312 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/DiagramComponent.java @@ -0,0 +1,160 @@ +/* + * 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.swing.colorchooser; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.image.BufferedImage; +import javax.swing.JComponent; + +final class DiagramComponent extends JComponent implements MouseListener, MouseMotionListener { + + private final ColorPanel panel; + private final boolean diagram; + + private final Insets insets = new Insets(0, 0, 0, 0); + + private int width; + private int height; + + private int[] array; + private BufferedImage image; + + DiagramComponent(ColorPanel panel, boolean diagram) { + this.panel = panel; + this.diagram = diagram; + addMouseListener(this); + addMouseMotionListener(this); + } + + @Override + protected void paintComponent(Graphics g) { + getInsets(this.insets); + this.width = getWidth() - this.insets.left - this.insets.right; + this.height = getHeight() - this.insets.top - this.insets.bottom; + + boolean update = (this.image == null) + || (this.width != this.image.getWidth()) + || (this.height != this.image.getHeight()); + if (update) { + int size = this.width * this.height; + if ((this.array == null) || (this.array.length < size)) { + this.array = new int[size]; + } + this.image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB); + } + { + float dx = 1.0f / (float) (this.width - 1); + float dy = 1.0f / (float) (this.height - 1); + + int offset = 0; + float y = 0.0f; + for (int h = 0; h < this.height; h++, y += dy) { + if (this.diagram) { + float x = 0.0f; + for (int w = 0; w < this.width; w++, x += dx, offset++) { + this.array[offset] = this.panel.getColor(x, y); + } + } + else { + int color = this.panel.getColor(y); + for (int w = 0; w < this.width; w++, offset++) { + this.array[offset] = color; + } + } + } + } + this.image.setRGB(0, 0, this.width, this.height, this.array, 0, this.width); + g.drawImage(this.image, this.insets.left, this.insets.top, this.width, this.height, this); + if (isEnabled()) { + this.width--; + this.height--; + g.setXORMode(Color.WHITE); + g.setColor(Color.BLACK); + if (this.diagram) { + int x = getValue(this.panel.getValueX(), this.insets.left, this.width); + int y = getValue(this.panel.getValueY(), this.insets.top, this.height); + g.drawLine(x - 8, y, x + 8, y); + g.drawLine(x, y - 8, x, y + 8); + } + else { + int z = getValue(this.panel.getValueZ(), this.insets.top, this.height); + g.drawLine(this.insets.left, z, this.insets.left + this.width, z); + } + g.setPaintMode(); + } + } + + public void mousePressed(MouseEvent event) { + mouseDragged(event); + } + + public void mouseReleased(MouseEvent event) { + } + + public void mouseClicked(MouseEvent event) { + } + + public void mouseEntered(MouseEvent event) { + } + + public void mouseExited(MouseEvent event) { + } + + public void mouseMoved(MouseEvent event) { + } + + public void mouseDragged(MouseEvent event) { + if (isEnabled()) { + float y = getValue(event.getY(), this.insets.top, this.height); + if (this.diagram) { + float x = getValue(event.getX(), this.insets.left, this.width); + this.panel.setValue(x, y); + } + else { + this.panel.setValue(y); + } + } + } + + private static int getValue(float value, int min, int max) { + return min + (int) (value * (float) (max)); + } + + private static float getValue(int value, int min, int max) { + if (min < value) { + value -= min; + return (value < max) + ? (float) value / (float) max + : 1.0f; + } + return 0.0f; + } +} diff --git a/src/share/classes/javax/swing/colorchooser/SlidingSpinner.java b/src/share/classes/javax/swing/colorchooser/SlidingSpinner.java new file mode 100644 index 0000000000000000000000000000000000000000..99e9bf298587f2998483c4e694298efd8a590fd9 --- /dev/null +++ b/src/share/classes/javax/swing/colorchooser/SlidingSpinner.java @@ -0,0 +1,118 @@ +/* + * 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.swing.colorchooser; + +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.JSpinner.DefaultEditor; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +final class SlidingSpinner implements ChangeListener { + + private final ColorPanel panel; + private final JComponent label; + private final SpinnerNumberModel model = new SpinnerNumberModel(); + private final JSlider slider = new JSlider(); + private final JSpinner spinner = new JSpinner(this.model); + private float value; + private boolean internal; + + SlidingSpinner(ColorPanel panel, JComponent label) { + this.panel = panel; + this.label = label; + this.slider.addChangeListener(this); + this.spinner.addChangeListener(this); + DefaultEditor editor = (DefaultEditor) this.spinner.getEditor(); + ValueFormatter.init(3, false, editor.getTextField()); + editor.setFocusable(false); + this.spinner.setFocusable(false); + } + + JComponent getLabel() { + return this.label; + } + + JSlider getSlider() { + return this.slider; + } + + JSpinner getSpinner() { + return this.spinner; + } + + float getValue() { + return this.value; + } + + void setValue(float value) { + int min = this.slider.getMinimum(); + int max = this.slider.getMaximum(); + this.internal = true; + this.slider.setValue(min + (int) (value * (float) (max - min))); + this.spinner.setValue(Integer.valueOf(this.slider.getValue())); + this.internal = false; + this.value = value; + } + + void setRange(int min, int max) { + this.internal = true; + this.slider.setMinimum(min); + this.slider.setMaximum(max); + this.model.setMinimum(Integer.valueOf(min)); + this.model.setMaximum(Integer.valueOf(max)); + this.internal = false; + } + + void setVisible(boolean visible) { + this.label.setVisible(visible); + this.slider.setVisible(visible); + this.spinner.setVisible(visible); + } + + public void stateChanged(ChangeEvent event) { + if (!this.internal) { + if (this.spinner == event.getSource()) { + Object value = this.spinner.getValue(); + if (value instanceof Integer) { + this.internal = true; + this.slider.setValue((Integer) value); + this.internal = false; + } + } + int value = this.slider.getValue(); + this.internal = true; + this.spinner.setValue(Integer.valueOf(value)); + this.internal = false; + int min = this.slider.getMinimum(); + int max = this.slider.getMaximum(); + this.value = (float) (value - min) / (float) (max - min); + this.panel.colorChanged(); + } + } +} diff --git a/src/share/classes/javax/swing/colorchooser/SyntheticImage.java b/src/share/classes/javax/swing/colorchooser/SyntheticImage.java deleted file mode 100644 index cec69e9c39d9ae269afe313b621056b0d289013d..0000000000000000000000000000000000000000 --- a/src/share/classes/javax/swing/colorchooser/SyntheticImage.java +++ /dev/null @@ -1,166 +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 javax.swing.colorchooser; - -import java.awt.*; -import java.awt.image.*; - -/** A helper class to make computing synthetic images a little easier. - * All you need to do is define a subclass that overrides computeRow - * to compute a row of the image. It is passed the y coordinate of the - * row and an array into which to put the pixels in - * - * standard ARGB format. - *

      Normal usage looks something like this: - *

       Image i = createImage(new SyntheticImage(200, 100) {
      - *       protected void computeRow(int y, int[] row) {
      - *         for(int i = width; --i>=0; ) {
      - *             int grey = i*255/(width-1);
      - *             row[i] = (255<<24)|(grey<<16)|(grey<<8)|grey;
      - *         }
      - *       }
      - *   }
      - *  
      This creates a image 200 pixels wide and 100 pixels high - * that is a horizontal grey ramp, going from black on the left to - * white on the right. - *

      - * If the image is to be a movie, override isStatic to return false, - * y cycling back to 0 is computeRow's signal that the next - * frame has started. It is acceptable (expected?) for computeRow(0,r) - * to pause until the appropriate time to start the next frame. - * - * @author James Gosling - */ -abstract class SyntheticImage implements ImageProducer { - private SyntheticImageGenerator root; - protected int width=10, height=100; - static final ColorModel cm = ColorModel.getRGBdefault(); - public static final int pixMask = 0xFF; - private Thread runner; - protected SyntheticImage() { } - protected SyntheticImage(int w, int h) { width = w; height = h; } - protected void computeRow(int y, int[] row) { - int p = 255-255*y/(height-1); - p = (pixMask<<24)|(p<<16)|(p<<8)|p; - for (int i = row.length; --i>=0; ) row[i] = p; - } - public synchronized void addConsumer(ImageConsumer ic){ - for (SyntheticImageGenerator ics = root; ics != null; ics = ics.next) - if (ics.ic == ic) return; - root = new SyntheticImageGenerator(ic, root, this); - } - public synchronized boolean isConsumer(ImageConsumer ic){ - for (SyntheticImageGenerator ics = root; ics != null; ics = ics.next) - if (ics.ic == ic) return true; - return false; - } - public synchronized void removeConsumer(ImageConsumer ic) { - SyntheticImageGenerator prev = null; - for (SyntheticImageGenerator ics = root; ics != null; ics = ics.next) { - if (ics.ic == ic) { - ics.useful = false; - if (prev!=null) prev.next = ics.next; - else root = ics.next; - return; - } - prev = ics; - } - } - public synchronized void startProduction(ImageConsumer ic) { - addConsumer(ic); - for (SyntheticImageGenerator ics = root; ics != null; ics = ics.next) - if (ics.useful && !ics.isAlive()) - ics.start(); - } - protected boolean isStatic() { return true; } - public void nextFrame(int param) {}//Override if !isStatic - public void requestTopDownLeftRightResend(ImageConsumer ic){} - - protected volatile boolean aborted = false; -} - -class SyntheticImageGenerator extends Thread { - ImageConsumer ic; - boolean useful; - SyntheticImageGenerator next; - SyntheticImage parent; - SyntheticImageGenerator(ImageConsumer ic, SyntheticImageGenerator next, - SyntheticImage parent) { - super("SyntheticImageGenerator"); - this.ic = ic; - this.next = next; - this.parent = parent; - useful = true; - setDaemon(true); - } - public void run() { - ImageConsumer ic = this.ic; - int w = parent.width; - int h = parent.height; - int hints = ic.SINGLEPASS|ic.COMPLETESCANLINES|ic.TOPDOWNLEFTRIGHT; - if (parent.isStatic()) - hints |= ic.SINGLEFRAME; - ic.setHints(hints); - ic.setDimensions(w, h); - ic.setProperties(null); - ic.setColorModel(parent.cm); - - if (useful) { - int[] row=new int[w]; - doPrivileged( new Runnable() { - public void run() { - Thread.currentThread().setPriority(Thread.MIN_PRIORITY); - } - }); - - do { - for (int y = 0; y>= 4; + } + return new String(array).toUpperCase(ENGLISH); + } + throw new ParseException("illegal object", 0); + } + + @Override + protected DocumentFilter getDocumentFilter() { + return this.filter; + } + + public void focusGained(FocusEvent event) { + Object source = event.getSource(); + if (source instanceof JFormattedTextField) { + this.text = (JFormattedTextField) source; + SwingUtilities.invokeLater(this); + } + } + + public void focusLost(FocusEvent event) { + } + + public void run() { + if (this.text != null) { + this.text.selectAll(); + } + } + + private boolean isValid(int length) { + return (0 <= length) && (length <= this.length); + } + + private boolean isValid(String text) { + int length = text.length(); + for (int i = 0; i < length; i++) { + char ch = text.charAt(i); + if (Character.digit(ch, this.radix) < 0) { + return false; + } + } + return true; + } +} diff --git a/src/share/classes/javax/swing/filechooser/FileSystemView.java b/src/share/classes/javax/swing/filechooser/FileSystemView.java index 855a357575eadf2df214b9495a944793b7e2ad72..c2ff7bb8df8e90a74f37ebeaedcbd4993cd9bd25 100644 --- a/src/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/src/share/classes/javax/swing/filechooser/FileSystemView.java @@ -136,8 +136,8 @@ public abstract class FileSystemView { } File[] roots = getRoots(); - for (int i = 0; i < roots.length; i++) { - if (roots[i].equals(f)) { + for (File root : roots) { + if (root.equals(f)) { return true; } } @@ -252,8 +252,8 @@ public abstract class FileSystemView { return true; } File[] children = getFiles(folder, false); - for (int i = 0; i < children.length; i++) { - if (file.equals(children[i])) { + for (File child : children) { + if (file.equals(child)) { return true; } } @@ -276,9 +276,9 @@ public abstract class FileSystemView { public File getChild(File parent, String fileName) { if (parent instanceof ShellFolder) { File[] children = getFiles(parent, false); - for (int i = 0; i < children.length; i++) { - if (children[i].getName().equals(fileName)) { - return children[i]; + for (File child : children) { + if (child.getName().equals(fileName)) { + return child; } } } @@ -444,7 +444,7 @@ public abstract class FileSystemView { * Gets the list of shown (i.e. not hidden) files. */ public File[] getFiles(File dir, boolean useFileHiding) { - Vector files = new Vector(); + Vector files = new Vector(); // add all files in dir @@ -483,7 +483,7 @@ public abstract class FileSystemView { } } - return (File[])files.toArray(new File[files.size()]); + return files.toArray(new File[files.size()]); } @@ -590,7 +590,7 @@ class UnixFileSystemView extends FileSystemView { if(containingDir == null) { throw new IOException("Containing directory is null:"); } - File newFolder = null; + File newFolder; // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE. newFolder = createFileObject(containingDir, newFolderString); int i = 1; @@ -614,11 +614,7 @@ class UnixFileSystemView extends FileSystemView { } public boolean isDrive(File dir) { - if (isFloppyDrive(dir)) { - return true; - } else { - return false; - } + return isFloppyDrive(dir); } public boolean isFloppyDrive(File dir) { @@ -700,9 +696,8 @@ class WindowsFileSystemView extends FileSystemView { if(containingDir == null) { throw new IOException("Containing directory is null:"); } - File newFolder = null; // Using NT's default folder name - newFolder = createFileObject(containingDir, newFolderString); + File newFolder = createFileObject(containingDir, newFolderString); int i = 2; while (newFolder.exists() && (i < 100)) { newFolder = createFileObject(containingDir, MessageFormat.format( @@ -770,9 +765,8 @@ class GenericFileSystemView extends FileSystemView { if(containingDir == null) { throw new IOException("Containing directory is null:"); } - File newFolder = null; // Using NT's default folder name - newFolder = createFileObject(containingDir, newFolderString); + File newFolder = createFileObject(containingDir, newFolderString); if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java b/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java index 05e35cc72ecd6ca3987a8b5a6ede8c8e5abffaae..c366217b73dd54568a6abcd9e1d227167009c2ce 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java @@ -165,7 +165,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, JRootPane root = b.getRootPane(); if (root != null) { BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType( - ((AbstractButton)b).getUI(), BasicButtonUI.class); + b.getUI(), BasicButtonUI.class); if (ui != null && DefaultLookup.getBoolean(b, ui, ui.getPropertyPrefix() + "defaultButtonFollowsFocus", true)) { @@ -185,7 +185,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, JButton initialDefault = (JButton)root.getClientProperty("initialDefaultButton"); if (b != initialDefault) { BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType( - ((AbstractButton)b).getUI(), BasicButtonUI.class); + b.getUI(), BasicButtonUI.class); if (ui != null && DefaultLookup.getBoolean(b, ui, ui.getPropertyPrefix() + "defaultButtonFollowsFocus", true)) { @@ -239,7 +239,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, } } } - }; + } public void mouseReleased(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { @@ -253,7 +253,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, model.setPressed(false); model.setArmed(false); } - }; + } public void mouseEntered(MouseEvent e) { AbstractButton b = (AbstractButton) e.getSource(); @@ -263,7 +263,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, } if (model.isPressed()) model.setArmed(true); - }; + } public void mouseExited(MouseEvent e) { AbstractButton b = (AbstractButton) e.getSource(); @@ -272,7 +272,7 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, model.setRollover(false); } model.setArmed(false); - }; + } /** diff --git a/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java b/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java index 6802c9d81bf867b9c36c823b29ae0a3f8db854c5..5dc98f2c17e3256d4a0c7eb4785e01b3d6cd168d 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java @@ -237,7 +237,7 @@ public class BasicButtonUI extends ButtonUI{ /* the fallback icon should be based on the selected state */ if (model.isSelected()) { - selectedIcon = (Icon) b.getSelectedIcon(); + selectedIcon = b.getSelectedIcon(); if (selectedIcon != null) { icon = selectedIcon; } @@ -245,31 +245,31 @@ public class BasicButtonUI extends ButtonUI{ if(!model.isEnabled()) { if(model.isSelected()) { - tmpIcon = (Icon) b.getDisabledSelectedIcon(); + tmpIcon = b.getDisabledSelectedIcon(); if (tmpIcon == null) { tmpIcon = selectedIcon; } } if (tmpIcon == null) { - tmpIcon = (Icon) b.getDisabledIcon(); + tmpIcon = b.getDisabledIcon(); } } else if(model.isPressed() && model.isArmed()) { - tmpIcon = (Icon) b.getPressedIcon(); + tmpIcon = b.getPressedIcon(); if(tmpIcon != null) { // revert back to 0 offset clearTextShiftOffset(); } } else if(b.isRolloverEnabled() && model.isRollover()) { if(model.isSelected()) { - tmpIcon = (Icon) b.getRolloverSelectedIcon(); + tmpIcon = b.getRolloverSelectedIcon(); if (tmpIcon == null) { tmpIcon = selectedIcon; } } if (tmpIcon == null) { - tmpIcon = (Icon) b.getRolloverIcon(); + tmpIcon = b.getRolloverIcon(); } } @@ -451,9 +451,9 @@ public class BasicButtonUI extends ButtonUI{ MouseMotionListener[] listeners = b.getMouseMotionListeners(); if (listeners != null) { - for (int counter = 0; counter < listeners.length; counter++) { - if (listeners[counter] instanceof BasicButtonListener) { - return (BasicButtonListener)listeners[counter]; + for (MouseMotionListener listener : listeners) { + if (listener instanceof BasicButtonListener) { + return (BasicButtonListener) listener; } } } diff --git a/src/share/classes/javax/swing/plaf/basic/BasicColorChooserUI.java b/src/share/classes/javax/swing/plaf/basic/BasicColorChooserUI.java index fd63e7fcbb6debe434b413d117128b924e8b0779..09f9372b9c346e07976c2c9adfa6c9851330f0c2 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicColorChooserUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -299,8 +299,10 @@ public class BasicColorChooserUI extends ColorChooserUI tabbedPane.addTab(name, centerWrapper); if (mnemonic > 0) { tabbedPane.setMnemonicAt(i, mnemonic); - tabbedPane.setDisplayedMnemonicIndexAt( - i, newPanels[i].getDisplayedMnemonicIndex()); + int index = newPanels[i].getDisplayedMnemonicIndex(); + if (index >= 0) { + tabbedPane.setDisplayedMnemonicIndexAt(i, index); + } } } } diff --git a/src/share/classes/javax/swing/plaf/basic/BasicComboBoxEditor.java b/src/share/classes/javax/swing/plaf/basic/BasicComboBoxEditor.java index bc41bfb0821c6926238ee92477763f11b0fb48de..c7ec981845c874c9301ff876ac899eca45ffa313 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicComboBoxEditor.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -92,7 +92,7 @@ public class BasicComboBoxEditor implements ComboBoxEditor,FocusListener { return oldValue; } else { // Must take the value from the editor and get the value and cast it to the new type. - Class cls = oldValue.getClass(); + Class cls = oldValue.getClass(); try { Method method = cls.getMethod("valueOf", new Class[]{String.class}); newValue = method.invoke(oldValue, new Object[] { editor.getText()}); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java b/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java index f073eeda816fbc3b7ffad44c4918c6c8cd5933f2..c49387fd91f05055ada42b2ea37a3cee1873e796 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -1509,15 +1509,21 @@ public class BasicComboBoxUI extends ComboBoxUI { || ui.isTableCellEditor) { Object listItem = ui.popup.getList().getSelectedValue(); if (listItem != null) { - comboBox.getModel().setSelectedItem(listItem); - // Ensure that JComboBox.actionPerformed() - // doesn't set editor value as selected item + // Use the selected value from popup + // to set the selected item in combo box, + // but ensure before that JComboBox.actionPerformed() + // won't use editor's value to set the selected item comboBox.getEditor().setItem(listItem); + comboBox.setSelectedItem(listItem); } } comboBox.setPopupVisible(false); } else { + // Hide combo box if it is a table cell editor + if (ui.isTableCellEditor && !comboBox.isEditable()) { + comboBox.setSelectedItem(comboBox.getSelectedItem()); + } // Call the default button binding. // This is a pretty messy way of passing an event through // to the root pane. diff --git a/src/share/classes/javax/swing/plaf/basic/BasicDesktopIconUI.java b/src/share/classes/javax/swing/plaf/basic/BasicDesktopIconUI.java index 9aab4dbe17d1a503ef87781f25aab4de8ea11163..5ebb6289440702a8a618f008a7d6fe105877d89a 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicDesktopIconUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicDesktopIconUI.java @@ -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 @@ -47,6 +47,7 @@ public class BasicDesktopIconUI extends DesktopIconUI { protected JInternalFrame.JDesktopIcon desktopIcon; protected JInternalFrame frame; + private DesktopIconMover desktopIconMover; /** * The title pane component used in the desktop icon. @@ -127,12 +128,21 @@ public class BasicDesktopIconUI extends DesktopIconUI { mouseInputListener = createMouseInputListener(); desktopIcon.addMouseMotionListener(mouseInputListener); desktopIcon.addMouseListener(mouseInputListener); + getDesktopIconMover().installListeners(); } protected void uninstallListeners() { desktopIcon.removeMouseMotionListener(mouseInputListener); desktopIcon.removeMouseListener(mouseInputListener); mouseInputListener = null; + getDesktopIconMover().uninstallListeners(); + } + + private DesktopIconMover getDesktopIconMover() { + if (desktopIconMover == null) { + desktopIconMover = new DesktopIconMover(desktopIcon); + } + return desktopIconMover; } protected void installDefaults() { diff --git a/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 528778392183074f807de139a9a01b97e3f050ec..8cff0a3e7cb4accf6153592881333ef874e23082 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -43,10 +43,10 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh private JFileChooser filechooser = null; // PENDING(jeff) pick the size more sensibly - private Vector fileCache = new Vector(50); + private Vector fileCache = new Vector(50); private LoadFilesThread loadThread = null; - private Vector files = null; - private Vector directories = null; + private Vector files = null; + private Vector directories = null; private int fetchID = 0; private PropertyChangeSupport changeSupport; @@ -106,14 +106,14 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh if (files != null) { return files; } - files = new Vector(); - directories = new Vector(); + files = new Vector(); + directories = new Vector(); directories.addElement(filechooser.getFileSystemView().createFileObject( filechooser.getCurrentDirectory(), "..") ); for (int i = 0; i < getSize(); i++) { - File f = (File)fileCache.get(i); + File f = fileCache.get(i); if (filechooser.isTraversable(f)) { directories.add(f); } else { @@ -215,7 +215,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh class LoadFilesThread extends Thread { File currentDirectory = null; int fid; - Vector runnables = new Vector(10); + Vector runnables = new Vector(10); public LoadFilesThread(File currentDirectory, int fid) { super("Basic L&F File Loading Thread"); @@ -223,7 +223,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh this.fid = fid; } - private void invokeLater(Runnable runnable) { + private void invokeLater(DoChangeContents runnable) { runnables.addElement(runnable); SwingUtilities.invokeLater(runnable); } @@ -245,9 +245,9 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh } // run through the file list, add directories and selectable files to fileCache - for (int i = 0; i < list.length; i++) { - if(filechooser.accept(list[i])) { - acceptsList.addElement(list[i]); + for (File file : list) { + if (filechooser.accept(file)) { + acceptsList.addElement(file); } } @@ -258,11 +258,11 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh // First sort alphabetically by filename sort(acceptsList); - Vector newDirectories = new Vector(50); - Vector newFiles = new Vector(); + Vector newDirectories = new Vector(50); + Vector newFiles = new Vector(); // run through list grabbing directories in chunks of ten for(int i = 0; i < acceptsList.size(); i++) { - File f = (File) acceptsList.elementAt(i); + File f = acceptsList.elementAt(i); boolean isTraversable = filechooser.isTraversable(f); if (isTraversable) { newDirectories.addElement(f); @@ -274,7 +274,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh } } - Vector newFileCache = new Vector(newDirectories); + Vector newFileCache = new Vector(newDirectories); newFileCache.addAll(newFiles); int newSize = newFileCache.size(); @@ -320,7 +320,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh if(isInterrupted()) { return; } - invokeLater(new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), + invokeLater(new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), start, fid)); newFileCache = null; } @@ -334,9 +334,9 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh } - public void cancelRunnables(Vector runnables) { - for(int i = 0; i < runnables.size(); i++) { - ((DoChangeContents)runnables.elementAt(i)).cancel(); + public void cancelRunnables(Vector runnables) { + for (DoChangeContents runnable : runnables) { + runnable.cancel(); } } @@ -449,15 +449,14 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh class DoChangeContents implements Runnable { - private List addFiles; - private List remFiles; + private List addFiles; + private List remFiles; private boolean doFire = true; private int fid; private int addStart = 0; private int remStart = 0; - private int change; - public DoChangeContents(List addFiles, int addStart, List remFiles, int remStart, int fid) { + public DoChangeContents(List addFiles, int addStart, List remFiles, int remStart, int fid) { this.addFiles = addFiles; this.addStart = addStart; this.remFiles = remFiles; diff --git a/src/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java b/src/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java index 467db5a1bb7b78b01001296f3a4a5984ed3714b1..13d13cdcefe930c28066cb7fe619a41524961b73 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java @@ -36,6 +36,7 @@ import java.awt.datatransfer.*; import java.beans.*; import java.io.*; import java.util.*; +import java.util.List; import java.util.regex.*; import sun.awt.shell.ShellFolder; import sun.swing.*; @@ -159,9 +160,9 @@ public class BasicFileChooserUI extends FileChooserUI { } public void uninstallUI(JComponent c) { - uninstallListeners((JFileChooser) filechooser); - uninstallComponents((JFileChooser) filechooser); - uninstallDefaults((JFileChooser) filechooser); + uninstallListeners(filechooser); + uninstallComponents(filechooser); + uninstallDefaults(filechooser); if(accessoryPanel != null) { accessoryPanel.removeAll(); @@ -506,9 +507,9 @@ public class BasicFileChooserUI extends FileChooserUI { setDirectorySelected(true); setDirectory(((File)objects[0])); } else { - ArrayList fList = new ArrayList(objects.length); - for (int i = 0; i < objects.length; i++) { - File f = (File)objects[i]; + ArrayList fList = new ArrayList(objects.length); + for (Object object : objects) { + File f = (File) object; boolean isDir = f.isDirectory(); if ((chooser.isFileSelectionEnabled() && !isDir) || (chooser.isDirectorySelectionEnabled() @@ -518,7 +519,7 @@ public class BasicFileChooserUI extends FileChooserUI { } } if (fList.size() > 0) { - files = (File[])fList.toArray(new File[fList.size()]); + files = fList.toArray(new File[fList.size()]); } setDirectorySelected(false); } @@ -829,11 +830,17 @@ public class BasicFileChooserUI extends FileChooserUI { File dir = chooser.getCurrentDirectory(); if (filename != null) { - // Remove whitespace from beginning and end of filename - filename = filename.trim(); + // Remove whitespaces from end of filename + int i = filename.length() - 1; + + while (i >=0 && filename.charAt(i) <= ' ') { + i--; + } + + filename = filename.substring(0, i + 1); } - if (filename == null || filename.equals("")) { + if (filename == null || filename.length() == 0) { // no file selected, multiple selection off, therefore cancel the approve action resetGlobFilter(); return; @@ -842,100 +849,93 @@ public class BasicFileChooserUI extends FileChooserUI { File selectedFile = null; File[] selectedFiles = null; - if (filename != null && !filename.equals("")) { - // Unix: Resolve '~' to user's home directory - if (File.separatorChar == '/') { - if (filename.startsWith("~/")) { - filename = System.getProperty("user.home") + filename.substring(1); - } else if (filename.equals("~")) { - filename = System.getProperty("user.home"); - } + // Unix: Resolve '~' to user's home directory + if (File.separatorChar == '/') { + if (filename.startsWith("~/")) { + filename = System.getProperty("user.home") + filename.substring(1); + } else if (filename.equals("~")) { + filename = System.getProperty("user.home"); } + } - if (chooser.isMultiSelectionEnabled() && filename.startsWith("\"")) { - ArrayList fList = new ArrayList(); + if (chooser.isMultiSelectionEnabled() && filename.length() > 1 && + filename.charAt(0) == '"' && filename.charAt(filename.length() - 1) == '"') { + List fList = new ArrayList(); - filename = filename.substring(1); - if (filename.endsWith("\"")) { - filename = filename.substring(0, filename.length()-1); - } - File[] children = null; - int childIndex = 0; - do { - String str; - int i = filename.indexOf("\" \""); - if (i > 0) { - str = filename.substring(0, i); - filename = filename.substring(i+3); - } else { - str = filename; - filename = ""; + String[] files = filename.substring(1, filename.length() - 1).split("\" \""); + // Optimize searching files by names in "children" array + Arrays.sort(files); + + File[] children = null; + int childIndex = 0; + + for (String str : files) { + File file = fs.createFileObject(str); + if (!file.isAbsolute()) { + if (children == null) { + children = fs.getFiles(dir, false); + Arrays.sort(children); } - File file = fs.createFileObject(str); - if (!file.isAbsolute()) { - if (children == null) { - children = fs.getFiles(dir, false); - Arrays.sort(children); - } - for (int k = 0; k < children.length; k++) { - int l = (childIndex + k) % children.length; - if (children[l].getName().equals(str)) { - file = children[l]; - childIndex = l + 1; - break; - } + for (int k = 0; k < children.length; k++) { + int l = (childIndex + k) % children.length; + if (children[l].getName().equals(str)) { + file = children[l]; + childIndex = l + 1; + break; } } - fList.add(file); - } while (filename.length() > 0); - if (fList.size() > 0) { - selectedFiles = (File[])fList.toArray(new File[fList.size()]); } - resetGlobFilter(); - } else { - selectedFile = fs.createFileObject(filename); - if(!selectedFile.isAbsolute()) { - selectedFile = fs.getChild(dir, filename); + fList.add(file); + } + + if (!fList.isEmpty()) { + selectedFiles = fList.toArray(new File[fList.size()]); + } + resetGlobFilter(); + } else { + selectedFile = fs.createFileObject(filename); + if (!selectedFile.isAbsolute()) { + selectedFile = fs.getChild(dir, filename); + } + // check for wildcard pattern + FileFilter currentFilter = chooser.getFileFilter(); + if (!selectedFile.exists() && isGlobPattern(filename)) { + changeDirectory(selectedFile.getParentFile()); + if (globFilter == null) { + globFilter = new GlobFilter(); } - // check for wildcard pattern - FileFilter currentFilter = chooser.getFileFilter(); - if (!selectedFile.exists() && isGlobPattern(filename)) { - changeDirectory(selectedFile.getParentFile()); - if (globFilter == null) { - globFilter = new GlobFilter(); - } - try { - globFilter.setPattern(selectedFile.getName()); - if (!(currentFilter instanceof GlobFilter)) { - actualFileFilter = currentFilter; - } - chooser.setFileFilter(null); - chooser.setFileFilter(globFilter); - return; - } catch (PatternSyntaxException pse) { - // Not a valid glob pattern. Abandon filter. + try { + globFilter.setPattern(selectedFile.getName()); + if (!(currentFilter instanceof GlobFilter)) { + actualFileFilter = currentFilter; } + chooser.setFileFilter(null); + chooser.setFileFilter(globFilter); + return; + } catch (PatternSyntaxException pse) { + // Not a valid glob pattern. Abandon filter. } + } - resetGlobFilter(); + resetGlobFilter(); - // Check for directory change action - boolean isDir = (selectedFile != null && selectedFile.isDirectory()); - boolean isTrav = (selectedFile != null && chooser.isTraversable(selectedFile)); - boolean isDirSelEnabled = chooser.isDirectorySelectionEnabled(); - boolean isFileSelEnabled = chooser.isFileSelectionEnabled(); - boolean isCtrl = (e != null && (e.getModifiers() & ActionEvent.CTRL_MASK) != 0); + // Check for directory change action + boolean isDir = (selectedFile != null && selectedFile.isDirectory()); + boolean isTrav = (selectedFile != null && chooser.isTraversable(selectedFile)); + boolean isDirSelEnabled = chooser.isDirectorySelectionEnabled(); + boolean isFileSelEnabled = chooser.isFileSelectionEnabled(); + boolean isCtrl = (e != null && (e.getModifiers() & ActionEvent.CTRL_MASK) != 0); - if (isDir && isTrav && (isCtrl || !isDirSelEnabled)) { - changeDirectory(selectedFile); - return; - } else if ((isDir || !isFileSelEnabled) - && (!isDir || !isDirSelEnabled) - && (!isDirSelEnabled || selectedFile.exists())) { - selectedFile = null; - } + if (isDir && isTrav && (isCtrl || !isDirSelEnabled)) { + changeDirectory(selectedFile); + return; + } else if ((isDir || !isFileSelEnabled) + && (!isDir || !isDirSelEnabled) + && (!isDirSelEnabled || selectedFile.exists())) { + selectedFile = null; } } + if (selectedFiles != null || selectedFile != null) { if (selectedFiles != null || chooser.isMultiSelectionEnabled()) { if (selectedFiles == null) { @@ -1213,7 +1213,7 @@ public class BasicFileChooserUI extends FileChooserUI { } public Icon getCachedIcon(File f) { - return (Icon) iconCache.get(f); + return iconCache.get(f); } public void cacheIcon(File f, Icon i) { @@ -1296,8 +1296,7 @@ public class BasicFileChooserUI extends FileChooserUI { htmlBuf.append("\n\n

        \n"); - for (int i = 0; i < values.length; i++) { - Object obj = values[i]; + for (Object obj : values) { String val = ((obj == null) ? "" : obj.toString()); plainBuf.append(val + "\n"); htmlBuf.append("
      • " + val + "\n"); @@ -1337,9 +1336,9 @@ public class BasicFileChooserUI extends FileChooserUI { */ protected Object getRicherData(DataFlavor flavor) { if (DataFlavor.javaFileListFlavor.equals(flavor)) { - ArrayList files = new ArrayList(); - for (int i = 0; i < fileData.length; i++) { - files.add(fileData[i]); + ArrayList files = new ArrayList(); + for (Object file : this.fileData) { + files.add(file); } return files; } diff --git a/src/share/classes/javax/swing/plaf/basic/BasicGraphicsUtils.java b/src/share/classes/javax/swing/plaf/basic/BasicGraphicsUtils.java index ecb8f0dccc04df4c5236af84dee0cc290a51088e..3cf822cfec21a16e075ab578e97b271ab68235a2 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicGraphicsUtils.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicGraphicsUtils.java @@ -266,7 +266,7 @@ public class BasicGraphicsUtils return null; } - Icon icon = (Icon) b.getIcon(); + Icon icon = b.getIcon(); String text = b.getText(); Font font = b.getFont(); @@ -277,7 +277,7 @@ public class BasicGraphicsUtils Rectangle viewR = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE); SwingUtilities.layoutCompoundLabel( - (JComponent) b, fm, text, icon, + b, fm, text, icon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewR, iconR, textR, (text == null ? 0 : textIconGap) diff --git a/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java index 344a4b2b512b2f0d8215256dcfb9596cab0788d2..b131824f441fc92209d0bfe9ad735e1b9085be4a 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java @@ -86,6 +86,7 @@ public class BasicInternalFrameTitlePane extends JComponent protected Action moveAction; protected Action sizeAction; + // These constants are not used in JDK code protected static final String CLOSE_CMD = UIManager.getString("InternalFrameTitlePane.closeButtonText"); protected static final String ICONIFY_CMD = @@ -268,18 +269,18 @@ public class BasicInternalFrameTitlePane extends JComponent } protected void addSystemMenuItems(JMenu systemMenu) { - JMenuItem mi = (JMenuItem)systemMenu.add(restoreAction); + JMenuItem mi = systemMenu.add(restoreAction); mi.setMnemonic('R'); - mi = (JMenuItem)systemMenu.add(moveAction); + mi = systemMenu.add(moveAction); mi.setMnemonic('M'); - mi = (JMenuItem)systemMenu.add(sizeAction); + mi = systemMenu.add(sizeAction); mi.setMnemonic('S'); - mi = (JMenuItem)systemMenu.add(iconifyAction); + mi = systemMenu.add(iconifyAction); mi.setMnemonic('n'); - mi = (JMenuItem)systemMenu.add(maximizeAction); + mi = systemMenu.add(maximizeAction); mi.setMnemonic('x'); systemMenu.add(new JSeparator()); - mi = (JMenuItem)systemMenu.add(closeAction); + mi = systemMenu.add(closeAction); mi.setMnemonic('C'); } @@ -413,7 +414,7 @@ public class BasicInternalFrameTitlePane extends JComponent // PropertyChangeListener // public void propertyChange(PropertyChangeEvent evt) { - String prop = (String)evt.getPropertyName(); + String prop = evt.getPropertyName(); if (prop == JInternalFrame.IS_SELECTED_PROPERTY) { repaint(); @@ -428,19 +429,19 @@ public class BasicInternalFrameTitlePane extends JComponent } if ("closable" == prop) { - if ((Boolean)evt.getNewValue() == Boolean.TRUE) { + if (evt.getNewValue() == Boolean.TRUE) { add(closeButton); } else { remove(closeButton); } } else if ("maximizable" == prop) { - if ((Boolean)evt.getNewValue() == Boolean.TRUE) { + if (evt.getNewValue() == Boolean.TRUE) { add(maxButton); } else { remove(maxButton); } } else if ("iconable" == prop) { - if ((Boolean)evt.getNewValue() == Boolean.TRUE) { + if (evt.getNewValue() == Boolean.TRUE) { add(iconButton); } else { remove(iconButton); @@ -600,7 +601,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class CloseAction extends AbstractAction { public CloseAction() { - super(CLOSE_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.closeButtonText")); } public void actionPerformed(ActionEvent e) { @@ -616,7 +618,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class MaximizeAction extends AbstractAction { public MaximizeAction() { - super(MAXIMIZE_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.maximizeButtonText")); } public void actionPerformed(ActionEvent evt) { @@ -644,7 +647,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class IconifyAction extends AbstractAction { public IconifyAction() { - super(ICONIFY_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.minimizeButtonText")); } public void actionPerformed(ActionEvent e) { @@ -664,7 +668,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class RestoreAction extends AbstractAction { public RestoreAction() { - super(RESTORE_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.restoreButtonText")); } public void actionPerformed(ActionEvent evt) { @@ -690,7 +695,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class MoveAction extends AbstractAction { public MoveAction() { - super(MOVE_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.moveButtonText")); } public void actionPerformed(ActionEvent e) { @@ -723,7 +729,8 @@ public class BasicInternalFrameTitlePane extends JComponent */ public class SizeAction extends AbstractAction { public SizeAction() { - super(SIZE_CMD); + super(UIManager.getString( + "InternalFrameTitlePane.sizeButtonText")); } public void actionPerformed(ActionEvent e) { @@ -774,7 +781,7 @@ public class BasicInternalFrameTitlePane extends JComponent } } public boolean isFocusTraversable() { return false; } - public void requestFocus() {}; + public void requestFocus() {} public AccessibleContext getAccessibleContext() { AccessibleContext ac = super.getAccessibleContext(); if (uiKey != null) { @@ -783,6 +790,6 @@ public class BasicInternalFrameTitlePane extends JComponent } return ac; } - }; // end NoFocusButton + } // end NoFocusButton } // End Title Pane Class diff --git a/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java b/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java index 83b0fd73bd96c677ad4f6811f160e79ef7937f48..46eefa26c142da9fd6f01d9cc33110307ec50787 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -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 @@ -55,7 +55,6 @@ public class BasicInternalFrameUI extends InternalFrameUI protected MouseInputAdapter borderListener; protected PropertyChangeListener propertyChangeListener; protected LayoutManager internalFrameLayout; - protected ComponentListener componentListener; protected MouseInputListener glassPaneDispatcher; private InternalFrameListener internalFrameListener; @@ -67,9 +66,9 @@ public class BasicInternalFrameUI extends InternalFrameUI protected BasicInternalFrameTitlePane titlePane; // access needs this private static DesktopManager sharedDesktopManager; - private boolean componentListenerAdded = false; private Rectangle parentBounds; + private DesktopIconMover desktopIconMover; private boolean dragging = false; private boolean resizing = false; @@ -210,14 +209,17 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.getGlassPane().addMouseListener(glassPaneDispatcher); frame.getGlassPane().addMouseMotionListener(glassPaneDispatcher); } - componentListener = createComponentListener(); if (frame.getParent() != null) { parentBounds = frame.getParent().getBounds(); } - if ((frame.getParent() != null) && !componentListenerAdded) { - frame.getParent().addComponentListener(componentListener); - componentListenerAdded = true; + getDesktopIconMover().installListeners(); + } + + private DesktopIconMover getDesktopIconMover() { + if (desktopIconMover == null) { + desktopIconMover = new DesktopIconMover(frame); } + return desktopIconMover; } // Provide a FocusListener to listen for a WINDOW_LOST_FOCUS event, @@ -288,11 +290,7 @@ public class BasicInternalFrameUI extends InternalFrameUI * @since 1.3 */ protected void uninstallListeners() { - if ((frame.getParent() != null) && componentListenerAdded) { - frame.getParent().removeComponentListener(componentListener); - componentListenerAdded = false; - } - componentListener = null; + getDesktopIconMover().uninstallListeners(); if (glassPaneDispatcher != null) { frame.getGlassPane().removeMouseListener(glassPaneDispatcher); frame.getGlassPane().removeMouseMotionListener(glassPaneDispatcher); @@ -320,7 +318,7 @@ public class BasicInternalFrameUI extends InternalFrameUI if (resizing) { return; } - Cursor s = (Cursor)frame.getLastCursor(); + Cursor s = frame.getLastCursor(); if (s == null) { s = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); } @@ -338,13 +336,13 @@ public class BasicInternalFrameUI extends InternalFrameUI public Dimension getPreferredSize(JComponent x) { - if((JComponent)frame == x) + if(frame == x) return frame.getLayout().preferredLayoutSize(x); return new Dimension(100, 100); } public Dimension getMinimumSize(JComponent x) { - if((JComponent)frame == x) { + if(frame == x) { return frame.getLayout().minimumLayoutSize(x); } return new Dimension(0, 0); @@ -1095,7 +1093,7 @@ public class BasicInternalFrameUI extends InternalFrameUI updateFrameCursor(); } - }; /// End BorderListener Class + } /// End BorderListener Class protected class ComponentHandler implements ComponentListener { // NOTE: This class exists only for backward compatability. All @@ -1198,7 +1196,6 @@ public class BasicInternalFrameUI extends InternalFrameUI } } - private static boolean isDragging = false; private class Handler implements ComponentListener, InternalFrameListener, LayoutManager, MouseInputListener, PropertyChangeListener, WindowFocusListener, SwingConstants { @@ -1230,15 +1227,6 @@ public class BasicInternalFrameUI extends InternalFrameUI } } - // Relocate the icon base on the new parent bounds. - if (icon != null) { - Rectangle iconBounds = icon.getBounds(); - int y = iconBounds.y + - (parentNewBounds.height - parentBounds.height); - icon.setBounds(iconBounds.x, y, - iconBounds.width, iconBounds.height); - } - // Update the new parent bounds for next resize. if (!parentBounds.equals(parentNewBounds)) { parentBounds = parentNewBounds; @@ -1384,9 +1372,6 @@ public class BasicInternalFrameUI extends InternalFrameUI // MouseInputListener - private Component mouseEventTarget = null; - private Component dragSource = null; - public void mousePressed(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } @@ -1403,7 +1388,7 @@ public class BasicInternalFrameUI extends InternalFrameUI // PropertyChangeListener public void propertyChange(PropertyChangeEvent evt) { - String prop = (String)evt.getPropertyName(); + String prop = evt.getPropertyName(); JInternalFrame f = (JInternalFrame)evt.getSource(); Object newValue = evt.getNewValue(); Object oldValue = evt.getOldValue(); @@ -1413,10 +1398,6 @@ public class BasicInternalFrameUI extends InternalFrameUI // Cancel a resize in progress if the internal frame // gets a setClosed(true) or dispose(). cancelResize(); - if ((frame.getParent() != null) && componentListenerAdded) { - frame.getParent().removeComponentListener( - componentListener); - } closeFrame(f); } } else if (JInternalFrame.IS_MAXIMUM_PROPERTY == prop) { @@ -1449,16 +1430,6 @@ public class BasicInternalFrameUI extends InternalFrameUI } else { parentBounds = null; } - if ((frame.getParent() != null) && !componentListenerAdded) { - f.getParent().addComponentListener(componentListener); - componentListenerAdded = true; - } else if ((newValue == null) && componentListenerAdded) { - if (f.getParent() != null) { - f.getParent().removeComponentListener( - componentListener); - } - componentListenerAdded = false; - } } else if (JInternalFrame.TITLE_PROPERTY == prop || prop == "closable" || prop == "iconable" || prop == "maximizable") { diff --git a/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java b/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java index af51ecc7c5024b71fe6b12741ef65e06bcf20463..c1f65d2aa2396b85badd0981439842ae72c1f8ca 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java @@ -65,6 +65,9 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener protected static BasicLabelUI labelUI = new BasicLabelUI(); private final static BasicLabelUI SAFE_BASIC_LABEL_UI = new BasicLabelUI(); + private Rectangle paintIconR = new Rectangle(); + private Rectangle paintTextR = new Rectangle(); + static void loadActionMap(LazyActionMap map) { map.put(new Actions(Actions.PRESS)); map.put(new Actions(Actions.RELEASE)); @@ -135,17 +138,6 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener textX, textY); } - - /* These rectangles/insets are allocated once for this shared LabelUI - * implementation. Re-using rectangles rather than allocating - * them in each paint call halved the time it took paint to run. - */ - private static Rectangle paintIconR = new Rectangle(); - private static Rectangle paintTextR = new Rectangle(); - private static Rectangle paintViewR = new Rectangle(); - private static Insets paintViewInsets = new Insets(0, 0, 0, 0); - - /** * Paint the label text in the foreground color, if the label * is opaque then paint the entire background with the background @@ -194,10 +186,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener private String layout(JLabel label, FontMetrics fm, int width, int height) { - Insets insets = label.getInsets(paintViewInsets); + Insets insets = label.getInsets(null); String text = label.getText(); Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon(); + Rectangle paintViewR = new Rectangle(); paintViewR.x = insets.left; paintViewR.y = insets.top; paintViewR.width = width - (insets.left + insets.right); @@ -208,24 +201,13 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener paintTextR); } - - /* These rectangles/insets are allocated once for this shared LabelUI - * implementation. Re-using rectangles rather than allocating - * them in each getPreferredSize call sped up the method substantially. - */ - private static Rectangle iconR = new Rectangle(); - private static Rectangle textR = new Rectangle(); - private static Rectangle viewR = new Rectangle(); - private static Insets viewInsets = new Insets(0, 0, 0, 0); - - public Dimension getPreferredSize(JComponent c) { JLabel label = (JLabel)c; String text = label.getText(); Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon(); - Insets insets = label.getInsets(viewInsets); + Insets insets = label.getInsets(null); Font font = label.getFont(); int dx = insets.left + insets.right; @@ -242,6 +224,9 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener } else { FontMetrics fm = label.getFontMetrics(font); + Rectangle iconR = new Rectangle(); + Rectangle textR = new Rectangle(); + Rectangle viewR = new Rectangle(); iconR.x = iconR.y = iconR.width = iconR.height = 0; textR.x = textR.y = textR.width = textR.height = 0; diff --git a/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index e0d139f48ef34bd41512d80d7a87a324026bcf4c..68bba5774b74427a46158ec25724ccf84da29feb 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -2102,8 +2102,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab * soundFile passed into this method, it will * return null. * - * @param baseClass used as the root class/location to get the - * soundFile from * @param soundFile the name of the audio file to be retrieved * from disk * @return A byte[] with audio data or null @@ -2120,9 +2118,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab * Class.getResourceAsStream just returns raw * bytes, which we can convert to a sound. */ - byte[] buffer = (byte[])AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { + byte[] buffer = AccessController.doPrivileged( + new PrivilegedAction() { + public byte[] run() { try { InputStream resource = BasicLookAndFeel.this. getClass().getResourceAsStream(soundFile); @@ -2184,9 +2182,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab UIManager.get("AuditoryCues.playList"); if (audioStrings != null) { // create a HashSet to help us decide to play or not - HashSet audioCues = new HashSet(); - for (int i = 0; i < audioStrings.length; i++) { - audioCues.add(audioStrings[i]); + HashSet audioCues = new HashSet(); + for (Object audioString : audioStrings) { + audioCues.add(audioString); } // get the name of the Action String actionName = (String)audioAction.getValue(Action.NAME); @@ -2237,7 +2235,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab * This class contains listener that watches for all the mouse * events that can possibly invoke popup on the component */ - class AWTEventHelper implements AWTEventListener,PrivilegedAction { + class AWTEventHelper implements AWTEventListener,PrivilegedAction { AWTEventHelper() { super(); AccessController.doPrivileged(this); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java index 85f56a52cd998fe9eccdbac2c4a429a7b79a1d65..a58cc467c5f58601e6776532ce6ed3c1e09e02ad 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -25,9 +25,6 @@ package javax.swing.plaf.basic; -import sun.swing.MenuItemCheckIconFactory; -import sun.swing.SwingUtilities2; -import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; @@ -39,8 +36,7 @@ import javax.swing.border.*; import javax.swing.plaf.*; import javax.swing.text.View; -import sun.swing.UIAction; -import sun.swing.StringUIClientPropertyKey; +import sun.swing.*; /** * BasicMenuItem implementation @@ -91,24 +87,6 @@ public class BasicMenuItemUI extends MenuItemUI private static final boolean VERBOSE = false; // show reuse hits/misses private static final boolean DEBUG = false; // show bad params, misc. - // Allows to reuse layoutInfo object. - // Shouldn't be used directly. Use getLayoutInfo() instead. - private final transient LayoutInfo layoutInfo = new LayoutInfo(); - - /* Client Property keys for calculation of maximal widths */ - static final StringUIClientPropertyKey MAX_ARROW_WIDTH = - new StringUIClientPropertyKey("maxArrowWidth"); - static final StringUIClientPropertyKey MAX_CHECK_WIDTH = - new StringUIClientPropertyKey("maxCheckWidth"); - static final StringUIClientPropertyKey MAX_ICON_WIDTH = - new StringUIClientPropertyKey("maxIconWidth"); - static final StringUIClientPropertyKey MAX_TEXT_WIDTH = - new StringUIClientPropertyKey("maxTextWidth"); - static final StringUIClientPropertyKey MAX_ACC_WIDTH = - new StringUIClientPropertyKey("maxAccWidth"); - static final StringUIClientPropertyKey MAX_LABEL_WIDTH = - new StringUIClientPropertyKey("maxLabelWidth"); - static void loadActionMap(LazyActionMap map) { // NOTE: BasicMenuUI also calls into this method. map.put(new Actions(Actions.CLICK)); @@ -199,13 +177,14 @@ public class BasicMenuItemUI extends MenuItemUI //In case of column layout, .checkIconFactory is defined for this UI, //the icon is compatible with it and useCheckAndArrow() is true, //then the icon is handled by the checkIcon. - boolean isColumnLayout = LayoutInfo.isColumnLayout( + boolean isColumnLayout = MenuItemLayoutHelper.isColumnLayout( BasicGraphicsUtils.isLeftToRight(menuItem), menuItem); if (isColumnLayout) { MenuItemCheckIconFactory iconFactory = (MenuItemCheckIconFactory) UIManager.get(prefix + ".checkIconFactory"); - if (iconFactory != null && useCheckAndArrow() + if (iconFactory != null + && MenuItemLayoutHelper.useCheckAndArrow(menuItem) && iconFactory.isCompatible(checkIcon, prefix)) { checkIcon = iconFactory.getIcon(menuItem); } @@ -256,20 +235,7 @@ public class BasicMenuItemUI extends MenuItemUI uninstallComponents(menuItem); uninstallListeners(); uninstallKeyboardActions(); - - - // Remove values from the parent's Client Properties. - JComponent p = getMenuItemParent(menuItem); - if(p != null) { - p.putClientProperty(BasicMenuItemUI.MAX_ARROW_WIDTH, null ); - p.putClientProperty(BasicMenuItemUI.MAX_CHECK_WIDTH, null ); - p.putClientProperty(BasicMenuItemUI.MAX_ACC_WIDTH, null ); - p.putClientProperty(BasicMenuItemUI.MAX_TEXT_WIDTH, null ); - p.putClientProperty(BasicMenuItemUI.MAX_ICON_WIDTH, null ); - p.putClientProperty(BasicMenuItemUI.MAX_LABEL_WIDTH, null ); - p.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null ); - } - + MenuItemLayoutHelper.clearUsedParentClientProperties(menuItem); menuItem = null; } @@ -405,19 +371,6 @@ public class BasicMenuItemUI extends MenuItemUI return d; } - // Returns parent of this component if it is not a top-level menu - // Otherwise returns null - private static JComponent getMenuItemParent(JMenuItem mi) { - Container parent = mi.getParent(); - if ((parent instanceof JComponent) && - (!(mi instanceof JMenu) || - !((JMenu)mi).isTopLevelMenu())) { - return (JComponent) parent; - } else { - return null; - } - } - protected Dimension getPreferredMenuItemSize(JComponent c, Icon checkIcon, Icon arrowIcon, @@ -447,32 +400,36 @@ public class BasicMenuItemUI extends MenuItemUI // the icon and text when user points a menu item by mouse. JMenuItem mi = (JMenuItem) c; - LayoutInfo li = getLayoutInfo(mi, checkIcon, arrowIcon, - createMaxViewRect(), defaultTextIconGap, acceleratorDelimiter, - BasicGraphicsUtils.isLeftToRight(mi), acceleratorFont, - useCheckAndArrow(), getPropertyPrefix()); + MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon, + arrowIcon, MenuItemLayoutHelper.createMaxRect(), defaultTextIconGap, + acceleratorDelimiter, BasicGraphicsUtils.isLeftToRight(mi), + mi.getFont(), acceleratorFont, + MenuItemLayoutHelper.useCheckAndArrow(menuItem), + getPropertyPrefix()); Dimension result = new Dimension(); // Calculate the result width - result.width = li.leadingGap; - addWidth(li.maxCheckWidth, li.afterCheckIconGap, result); + result.width = lh.getLeadingGap(); + MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(), + lh.getAfterCheckIconGap(), result); // Take into account mimimal text offset. - if ((!li.isTopLevelMenu) - && (li.minTextOffset > 0) - && (result.width < li.minTextOffset)) { - result.width = li.minTextOffset; + if ((!lh.isTopLevelMenu()) + && (lh.getMinTextOffset() > 0) + && (result.width < lh.getMinTextOffset())) { + result.width = lh.getMinTextOffset(); } - addWidth(li.maxLabelWidth, li.gap, result); - addWidth(li.maxAccWidth, li.gap, result); - addWidth(li.maxArrowWidth, li.gap, result); + MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), lh.getGap(), result); + MenuItemLayoutHelper.addMaxWidth(lh.getAccSize(), lh.getGap(), result); + MenuItemLayoutHelper.addMaxWidth(lh.getArrowSize(), lh.getGap(), result); // Calculate the result height - result.height = max(li.checkRect.height, li.labelRect.height, - li.accRect.height, li.arrowRect.height); + result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(), + lh.getLabelSize().getHeight(), lh.getAccSize().getHeight(), + lh.getArrowSize().getHeight()); // Take into account menu item insets - Insets insets = li.mi.getInsets(); + Insets insets = lh.getMenuItem().getInsets(); if(insets != null) { result.width += insets.left + insets.right; result.height += insets.top + insets.bottom; @@ -492,500 +449,9 @@ public class BasicMenuItemUI extends MenuItemUI result.height++; } - li.clear(); return result; } - private Rectangle createMaxViewRect() { - return new Rectangle(0,0,Short.MAX_VALUE, Short.MAX_VALUE); - } - - private void addWidth(int width, int gap, Dimension result) { - if (width > 0) { - result.width += width + gap; - } - } - - private static int max(int... values) { - int maxValue = Integer.MIN_VALUE; - for (int i : values) { - if (i > maxValue) { - maxValue = i; - } - } - return maxValue; - } - - // LayoutInfo helps to calculate preferred size and to paint a menu item - private static class LayoutInfo { - JMenuItem mi; - JComponent miParent; - - FontMetrics fm; - FontMetrics accFm; - - Icon icon; - Icon checkIcon; - Icon arrowIcon; - String text; - String accText; - - boolean isColumnLayout; - boolean useCheckAndArrow; - boolean isLeftToRight; - boolean isTopLevelMenu; - View htmlView; - - int verticalAlignment; - int horizontalAlignment; - int verticalTextPosition; - int horizontalTextPosition; - int gap; - int leadingGap; - int afterCheckIconGap; - int minTextOffset; - - Rectangle viewRect; - Rectangle iconRect; - Rectangle textRect; - Rectangle accRect; - Rectangle checkRect; - Rectangle arrowRect; - Rectangle labelRect; - - int origIconWidth; - int origTextWidth; - int origAccWidth; - int origCheckWidth; - int origArrowWidth; - - int maxIconWidth; - int maxTextWidth; - int maxAccWidth; - int maxCheckWidth; - int maxArrowWidth; - int maxLabelWidth; - - // Empty constructor helps to create "final" LayoutInfo object - public LayoutInfo() { - } - - public LayoutInfo(JMenuItem mi, Icon checkIcon, Icon arrowIcon, - Rectangle viewRect, int gap, String accDelimiter, - boolean isLeftToRight, Font acceleratorFont, - boolean useCheckAndArrow, String propertyPrefix) { - reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, - isLeftToRight, acceleratorFont, useCheckAndArrow, - propertyPrefix); - } - - // Allows to reuse a LayoutInfo object - public void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon, - Rectangle viewRect, int gap, String accDelimiter, - boolean isLeftToRight, Font acceleratorFont, - boolean useCheckAndArrow, String propertyPrefix) { - this.mi = mi; - this.miParent = getMenuItemParent(mi); - this.accText = getAccText(accDelimiter); - this.verticalAlignment = mi.getVerticalAlignment(); - this.horizontalAlignment = mi.getHorizontalAlignment(); - this.verticalTextPosition = mi.getVerticalTextPosition(); - this.horizontalTextPosition = mi.getHorizontalTextPosition(); - this.useCheckAndArrow = useCheckAndArrow; - this.fm = mi.getFontMetrics(mi.getFont()); - this.accFm = mi.getFontMetrics(acceleratorFont); - this.isLeftToRight = isLeftToRight; - this.isColumnLayout = isColumnLayout(); - this.isTopLevelMenu = (this.miParent == null)? true : false; - this.checkIcon = checkIcon; - this.icon = getIcon(propertyPrefix); - this.arrowIcon = arrowIcon; - this.text = mi.getText(); - this.gap = gap; - this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix); - this.minTextOffset = getMinTextOffset(propertyPrefix); - this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey); - - this.viewRect = viewRect; - this.iconRect = new Rectangle(); - this.textRect = new Rectangle(); - this.accRect = new Rectangle(); - this.checkRect = new Rectangle(); - this.arrowRect = new Rectangle(); - this.labelRect = new Rectangle(); - - calcWidthsAndHeights(); - this.origIconWidth = iconRect.width; - this.origTextWidth = textRect.width; - this.origAccWidth = accRect.width; - this.origCheckWidth = checkRect.width; - this.origArrowWidth = arrowRect.width; - - calcMaxWidths(); - this.leadingGap = getLeadingGap(propertyPrefix); - calcMaxTextOffset(); - } - - // Clears fields to remove all links to other objects - // to prevent memory leaks - public void clear() { - mi = null; - miParent = null; - fm = null; - accFm = null; - icon = null; - checkIcon = null; - arrowIcon = null; - text = null; - accText = null; - htmlView = null; - viewRect = null; - iconRect = null; - textRect = null; - accRect = null; - checkRect = null; - arrowRect = null; - labelRect = null; - } - - private String getAccText(String acceleratorDelimiter) { - String accText = ""; - KeyStroke accelerator = mi.getAccelerator(); - if (accelerator != null) { - int modifiers = accelerator.getModifiers(); - if (modifiers > 0) { - accText = KeyEvent.getKeyModifiersText(modifiers); - accText += acceleratorDelimiter; - } - int keyCode = accelerator.getKeyCode(); - if (keyCode != 0) { - accText += KeyEvent.getKeyText(keyCode); - } else { - accText += accelerator.getKeyChar(); - } - } - return accText; - } - - // In case of column layout, .checkIconFactory is defined for this UI, - // the icon is compatible with it and useCheckAndArrow() is true, - // then the icon is handled by the checkIcon. - private Icon getIcon(String propertyPrefix) { - Icon icon = null; - MenuItemCheckIconFactory iconFactory = - (MenuItemCheckIconFactory) UIManager.get(propertyPrefix - + ".checkIconFactory"); - if (!isColumnLayout || !useCheckAndArrow || iconFactory == null - || !iconFactory.isCompatible(checkIcon, propertyPrefix)) { - icon = mi.getIcon(); - } - return icon; - } - - private int getMinTextOffset(String propertyPrefix) { - int minimumTextOffset = 0; - Object minimumTextOffsetObject = - UIManager.get(propertyPrefix + ".minimumTextOffset"); - if (minimumTextOffsetObject instanceof Integer) { - minimumTextOffset = (Integer) minimumTextOffsetObject; - } - return minimumTextOffset; - } - - private int getAfterCheckIconGap(String propertyPrefix) { - int afterCheckIconGap = gap; - Object afterCheckIconGapObject = - UIManager.get(propertyPrefix + ".afterCheckIconGap"); - if (afterCheckIconGapObject instanceof Integer) { - afterCheckIconGap = (Integer) afterCheckIconGapObject; - } - return afterCheckIconGap; - } - - private int getLeadingGap(String propertyPrefix) { - if (maxCheckWidth > 0) { - return getCheckOffset(propertyPrefix); - } else { - return gap; // There is no any check icon - } - } - - private int getCheckOffset(String propertyPrefix) { - int checkIconOffset = gap; - Object checkIconOffsetObject = - UIManager.get(propertyPrefix + ".checkIconOffset"); - if (checkIconOffsetObject instanceof Integer) { - checkIconOffset = (Integer) checkIconOffsetObject; - } - return checkIconOffset; - } - - private void calcWidthsAndHeights() - { - // iconRect - if (icon != null) { - iconRect.width = icon.getIconWidth(); - iconRect.height = icon.getIconHeight(); - } - - // accRect - if (!accText.equals("")) { - accRect.width = SwingUtilities2.stringWidth( - mi, accFm, accText); - accRect.height = accFm.getHeight(); - } - - // textRect - if (text == null) { - text = ""; - } else if (!text.equals("")) { - if (htmlView != null) { - // Text is HTML - textRect.width = - (int) htmlView.getPreferredSpan(View.X_AXIS); - textRect.height = - (int) htmlView.getPreferredSpan(View.Y_AXIS); - } else { - // Text isn't HTML - textRect.width = - SwingUtilities2.stringWidth(mi, fm, text); - textRect.height = fm.getHeight(); - } - } - - if (useCheckAndArrow) { - // checkIcon - if (checkIcon != null) { - checkRect.width = checkIcon.getIconWidth(); - checkRect.height = checkIcon.getIconHeight(); - } - // arrowRect - if (arrowIcon != null) { - arrowRect.width = arrowIcon.getIconWidth(); - arrowRect.height = arrowIcon.getIconHeight(); - } - } - - // labelRect - if (isColumnLayout) { - labelRect.width = iconRect.width + textRect.width + gap; - labelRect.height = max(checkRect.height, iconRect.height, - textRect.height, accRect.height, arrowRect.height); - } else { - textRect = new Rectangle(); - iconRect = new Rectangle(); - SwingUtilities.layoutCompoundLabel(mi, fm, text, icon, - verticalAlignment, horizontalAlignment, - verticalTextPosition, horizontalTextPosition, - viewRect, iconRect, textRect, gap); - labelRect = iconRect.union(textRect); - } - } - - private void calcMaxWidths() { - maxCheckWidth = calcMaxValue(BasicMenuItemUI.MAX_CHECK_WIDTH, - checkRect.width); - maxArrowWidth = calcMaxValue(BasicMenuItemUI.MAX_ARROW_WIDTH, - arrowRect.width); - maxAccWidth = calcMaxValue(BasicMenuItemUI.MAX_ACC_WIDTH, - accRect.width); - - if (isColumnLayout) { - maxIconWidth = calcMaxValue(BasicMenuItemUI.MAX_ICON_WIDTH, - iconRect.width); - maxTextWidth = calcMaxValue(BasicMenuItemUI.MAX_TEXT_WIDTH, - textRect.width); - int curGap = gap; - if ((maxIconWidth == 0) || (maxTextWidth == 0)) { - curGap = 0; - } - maxLabelWidth = - calcMaxValue(BasicMenuItemUI.MAX_LABEL_WIDTH, - maxIconWidth + maxTextWidth + curGap); - } else { - // We shouldn't use current icon and text widths - // in maximal widths calculation for complex layout. - maxIconWidth = getParentIntProperty(BasicMenuItemUI.MAX_ICON_WIDTH); - maxLabelWidth = calcMaxValue(BasicMenuItemUI.MAX_LABEL_WIDTH, - labelRect.width); - // If maxLabelWidth is wider - // than the widest icon + the widest text + gap, - // we should update the maximal text witdh - int candidateTextWidth = maxLabelWidth - maxIconWidth; - if (maxIconWidth > 0) { - candidateTextWidth -= gap; - } - maxTextWidth = calcMaxValue(BasicMenuItemUI.MAX_TEXT_WIDTH, - candidateTextWidth); - } - } - - // Calculates and returns maximal value - // through specified parent component client property. - private int calcMaxValue(Object propertyName, int value) { - // Get maximal value from parent client property - int maxValue = getParentIntProperty(propertyName); - // Store new maximal width in parent client property - if (value > maxValue) { - if (miParent != null) { - miParent.putClientProperty(propertyName, value); - } - return value; - } else { - return maxValue; - } - } - - // Returns parent client property as int - private int getParentIntProperty(Object propertyName) { - Object value = null; - if (miParent != null) { - value = miParent.getClientProperty(propertyName); - } - if ((value == null) || !(value instanceof Integer)){ - value = 0; - } - return (Integer)value; - } - - private boolean isColumnLayout() { - return isColumnLayout(isLeftToRight, horizontalAlignment, - horizontalTextPosition, verticalTextPosition); - } - - public static boolean isColumnLayout(boolean isLeftToRight, - JMenuItem mi) { - assert(mi != null); - return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(), - mi.getHorizontalTextPosition(), mi.getVerticalTextPosition()); - } - - // Answers should we do column layout for a menu item or not. - // We do it when a user doesn't set any alignments - // and text positions manually, except the vertical alignment. - public static boolean isColumnLayout( boolean isLeftToRight, - int horizontalAlignment, int horizontalTextPosition, - int verticalTextPosition) { - if (verticalTextPosition != SwingConstants.CENTER) { - return false; - } - if (isLeftToRight) { - if (horizontalAlignment != SwingConstants.LEADING - && horizontalAlignment != SwingConstants.LEFT) { - return false; - } - if (horizontalTextPosition != SwingConstants.TRAILING - && horizontalTextPosition != SwingConstants.RIGHT) { - return false; - } - } else { - if (horizontalAlignment != SwingConstants.LEADING - && horizontalAlignment != SwingConstants.RIGHT) { - return false; - } - if (horizontalTextPosition != SwingConstants.TRAILING - && horizontalTextPosition != SwingConstants.LEFT) { - return false; - } - } - return true; - } - - // Calculates maximal text offset. - // It is required for some L&Fs (ex: Vista L&F). - // The offset is meaningful only for L2R column layout. - private void calcMaxTextOffset() { - if (!isColumnLayout || !isLeftToRight) { - return; - } - - // Calculate the current text offset - int offset = viewRect.x + leadingGap + maxCheckWidth - + afterCheckIconGap + maxIconWidth + gap; - if (maxCheckWidth == 0) { - offset -= afterCheckIconGap; - } - if (maxIconWidth == 0) { - offset -= gap; - } - - // maximal text offset shouldn't be less than minimal text offset; - if (offset < minTextOffset) { - offset = minTextOffset; - } - - // Calculate and store the maximal text offset - calcMaxValue(BASICMENUITEMUI_MAX_TEXT_OFFSET, offset); - } - - public String toString() { - StringBuilder result = new StringBuilder(); - result.append(super.toString()).append("\n"); - result.append("accFm = ").append(accFm).append("\n"); - result.append("accRect = ").append(accRect).append("\n"); - result.append("accText = ").append(accText).append("\n"); - result.append("afterCheckIconGap = ").append(afterCheckIconGap) - .append("\n"); - result.append("arrowIcon = ").append(arrowIcon).append("\n"); - result.append("arrowRect = ").append(arrowRect).append("\n"); - result.append("checkIcon = ").append(checkIcon).append("\n"); - result.append("checkRect = ").append(checkRect).append("\n"); - result.append("fm = ").append(fm).append("\n"); - result.append("gap = ").append(gap).append("\n"); - result.append("horizontalAlignment = ").append(horizontalAlignment) - .append("\n"); - result.append("horizontalTextPosition = ") - .append(horizontalTextPosition).append("\n"); - result.append("htmlView = ").append(htmlView).append("\n"); - result.append("icon = ").append(icon).append("\n"); - result.append("iconRect = ").append(iconRect).append("\n"); - result.append("isColumnLayout = ").append(isColumnLayout).append("\n"); - result.append("isLeftToRight = ").append(isLeftToRight).append("\n"); - result.append("isTopLevelMenu = ").append(isTopLevelMenu).append("\n"); - result.append("labelRect = ").append(labelRect).append("\n"); - result.append("leadingGap = ").append(leadingGap).append("\n"); - result.append("maxAccWidth = ").append(maxAccWidth).append("\n"); - result.append("maxArrowWidth = ").append(maxArrowWidth).append("\n"); - result.append("maxCheckWidth = ").append(maxCheckWidth).append("\n"); - result.append("maxIconWidth = ").append(maxIconWidth).append("\n"); - result.append("maxLabelWidth = ").append(maxLabelWidth).append("\n"); - result.append("maxTextWidth = ").append(maxTextWidth).append("\n"); - result.append("maxTextOffset = ") - .append(getParentIntProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET)) - .append("\n"); - result.append("mi = ").append(mi).append("\n"); - result.append("minTextOffset = ").append(minTextOffset).append("\n"); - result.append("miParent = ").append(miParent).append("\n"); - result.append("origAccWidth = ").append(origAccWidth).append("\n"); - result.append("origArrowWidth = ").append(origArrowWidth).append("\n"); - result.append("origCheckWidth = ").append(origCheckWidth).append("\n"); - result.append("origIconWidth = ").append(origIconWidth).append("\n"); - result.append("origTextWidth = ").append(origTextWidth).append("\n"); - result.append("text = ").append(text).append("\n"); - result.append("textRect = ").append(textRect).append("\n"); - result.append("useCheckAndArrow = ").append(useCheckAndArrow) - .append("\n"); - result.append("verticalAlignment = ").append(verticalAlignment) - .append("\n"); - result.append("verticalTextPosition = ") - .append(verticalTextPosition).append("\n"); - result.append("viewRect = ").append(viewRect).append("\n"); - return result.toString(); - } - } // End of LayoutInfo - - // Reuses layoutInfo object to reduce the amount of produced garbage - private LayoutInfo getLayoutInfo(JMenuItem mi, Icon checkIcon, Icon arrowIcon, - Rectangle viewRect, int gap, String accDelimiter, - boolean isLeftToRight, Font acceleratorFont, - boolean useCheckAndArrow, String propertyPrefix) { - // layoutInfo is final and always not null - layoutInfo.reset(mi, checkIcon, arrowIcon, viewRect, - gap, accDelimiter, isLeftToRight, acceleratorFont, - useCheckAndArrow, propertyPrefix); - return layoutInfo; - } - /** * We draw the background in paintMenuItem() * so override update (which fills the background of opaque @@ -1016,122 +482,132 @@ public class BasicMenuItemUI extends MenuItemUI Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); applyInsets(viewRect, mi.getInsets()); - LayoutInfo li = getLayoutInfo(mi, checkIcon, arrowIcon, - viewRect, defaultTextIconGap, acceleratorDelimiter, - BasicGraphicsUtils.isLeftToRight(mi), acceleratorFont, - useCheckAndArrow(), getPropertyPrefix()); - layoutMenuItem(li); + MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon, + arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter, + BasicGraphicsUtils.isLeftToRight(mi), mi.getFont(), + acceleratorFont, MenuItemLayoutHelper.useCheckAndArrow(menuItem), + getPropertyPrefix()); + MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); paintBackground(g, mi, background); - paintCheckIcon(g, li, holdc, foreground); - paintIcon(g, li, holdc); - paintText(g, li); - paintAccText(g, li); - paintArrowIcon(g, li, foreground); + paintCheckIcon(g, lh, lr, holdc, foreground); + paintIcon(g, lh, lr, holdc); + paintText(g, lh, lr); + paintAccText(g, lh, lr); + paintArrowIcon(g, lh, lr, foreground); // Restore original graphics font and color g.setColor(holdc); g.setFont(holdf); - - li.clear(); } - private void paintIcon(Graphics g, LayoutInfo li, Color holdc) { - if (li.icon != null) { + private void paintIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc) { + if (lh.getIcon() != null) { Icon icon; - ButtonModel model = li.mi.getModel(); + ButtonModel model = lh.getMenuItem().getModel(); if (!model.isEnabled()) { - icon = (Icon) li.mi.getDisabledIcon(); + icon = lh.getMenuItem().getDisabledIcon(); } else if (model.isPressed() && model.isArmed()) { - icon = (Icon) li.mi.getPressedIcon(); + icon = lh.getMenuItem().getPressedIcon(); if (icon == null) { // Use default icon - icon = (Icon) li.mi.getIcon(); + icon = lh.getMenuItem().getIcon(); } } else { - icon = (Icon) li.mi.getIcon(); + icon = lh.getMenuItem().getIcon(); } if (icon != null) { - icon.paintIcon(li.mi, g, li.iconRect.x, li.iconRect.y); + icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, + lr.getIconRect().y); g.setColor(holdc); } } } - private void paintCheckIcon(Graphics g, LayoutInfo li, + private void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc, Color foreground) { - if (li.checkIcon != null) { - ButtonModel model = li.mi.getModel(); - if (model.isArmed() - || (li.mi instanceof JMenu && model.isSelected())) { + if (lh.getCheckIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { g.setColor(foreground); } else { g.setColor(holdc); } - if (li.useCheckAndArrow) { - li.checkIcon.paintIcon(li.mi, g, li.checkRect.x, - li.checkRect.y); + if (lh.useCheckAndArrow()) { + lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, + lr.getCheckRect().x, lr.getCheckRect().y); } g.setColor(holdc); } } - private void paintAccText(Graphics g, LayoutInfo li) { - if (!li.accText.equals("")) { - ButtonModel model = li.mi.getModel(); - g.setFont(acceleratorFont); + private void paintAccText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getAccText().equals("")) { + ButtonModel model = lh.getMenuItem().getModel(); + g.setFont(lh.getAccFontMetrics().getFont()); if (!model.isEnabled()) { // *** paint the accText disabled if (disabledForeground != null) { g.setColor(disabledForeground); - SwingUtilities2.drawString(li.mi, g, li.accText, - li.accRect.x, - li.accRect.y + li.accFm.getAscent()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); } else { - g.setColor(li.mi.getBackground().brighter()); - SwingUtilities2.drawString(li.mi, g, li.accText, li.accRect.x, - li.accRect.y + li.accFm.getAscent()); - g.setColor(li.mi.getBackground().darker()); - SwingUtilities2.drawString(li.mi, g, li.accText, - li.accRect.x - 1, - li.accRect.y + li.accFm.getAscent() - 1); + g.setColor(lh.getMenuItem().getBackground().brighter()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + g.setColor(lh.getMenuItem().getBackground().darker()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x - 1, + lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); } } else { // *** paint the accText normally - if (model.isArmed() || - (li.mi instanceof JMenu && model.isSelected())) { + if (model.isArmed() + || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { g.setColor(acceleratorSelectionForeground); } else { g.setColor(acceleratorForeground); } - SwingUtilities2.drawString(li.mi, g, li.accText, li.accRect.x, - li.accRect.y + li.accFm.getAscent()); + SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), + lr.getAccRect().x, lr.getAccRect().y + + lh.getAccFontMetrics().getAscent()); } } } - private void paintText(Graphics g, LayoutInfo li) { - if (!li.text.equals("")) { - if (li.htmlView != null) { + private void paintText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getText().equals("")) { + if (lh.getHtmlView() != null) { // Text is HTML - li.htmlView.paint(g, li.textRect); + lh.getHtmlView().paint(g, lr.getTextRect()); } else { // Text isn't HTML - paintText(g, li.mi, li.textRect, li.text); + paintText(g, lh.getMenuItem(), lr.getTextRect(), lh.getText()); } } } - private void paintArrowIcon(Graphics g, LayoutInfo li, Color foreground) { - if (li.arrowIcon != null) { - ButtonModel model = li.mi.getModel(); - if (model.isArmed() - || (li.mi instanceof JMenu && model.isSelected())) { + private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color foreground) { + if (lh.getArrowIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { g.setColor(foreground); } - if (li.useCheckAndArrow) { - li.arrowIcon.paintIcon(li.mi, g, li.arrowRect.x, li.arrowRect.y); + if (lh.useCheckAndArrow()) { + lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, + lr.getArrowRect().x, lr.getArrowRect().y); } } } @@ -1216,346 +692,6 @@ public class BasicMenuItemUI extends MenuItemUI } } - - /** - * Layout icon, text, check icon, accelerator text and arrow icon - * in the viewRect and return their positions. - * - * If horizontalAlignment, verticalTextPosition and horizontalTextPosition - * are default (user doesn't set any manually) the layouting algorithm is: - * Elements are layouted in the five columns: - * check icon + icon + text + accelerator text + arrow icon - * - * In the other case elements are layouted in the four columns: - * check icon + label + accelerator text + arrow icon - * Label is icon and text rectangles union. - * - * The order of columns can be reversed. - * It depends on the menu item orientation. - */ - private void layoutMenuItem(LayoutInfo li) - { - li.checkRect.width = li.maxCheckWidth; - li.accRect.width = li.maxAccWidth; - li.arrowRect.width = li.maxArrowWidth; - - if (li.isColumnLayout) { - if (li.isLeftToRight) { - doLTRColumnLayout(li); - } else { - doRTLColumnLayout(li); - } - } else { - if (li.isLeftToRight) { - doLTRComplexLayout(li); - } else { - doRTLComplexLayout(li); - } - } - - alignAccCheckAndArrowVertically(li); - } - - // Aligns the accelertor text and the check and arrow icons vertically - // with the center of the label rect. - private void alignAccCheckAndArrowVertically(LayoutInfo li) { - li.accRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2 - - (float)li.accRect.height/2); - fixVerticalAlignment(li, li.accRect); - if (li.useCheckAndArrow) { - li.arrowRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2 - - (float)li.arrowRect.height/2); - li.checkRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2 - - (float)li.checkRect.height/2); - fixVerticalAlignment(li, li.arrowRect); - fixVerticalAlignment(li, li.checkRect); - } - } - - // Fixes vertical alignment of all menu item elements if a rect.y - // or (rect.y + rect.height) is out of viewRect bounds - private void fixVerticalAlignment(LayoutInfo li, Rectangle r) { - int delta = 0; - if (r.y < li.viewRect.y) { - delta = li.viewRect.y - r.y; - } else if (r.y + r.height > li.viewRect.y + li.viewRect.height) { - delta = li.viewRect.y + li.viewRect.height - r.y - r.height; - } - if (delta != 0) { - li.checkRect.y += delta; - li.iconRect.y += delta; - li.textRect.y += delta; - li.accRect.y += delta; - li.arrowRect.y += delta; - } - } - - private void doLTRColumnLayout(LayoutInfo li) { - // Set maximal width for all the five basic rects - // (three other ones are already maximal) - li.iconRect.width = li.maxIconWidth; - li.textRect.width = li.maxTextWidth; - - // Set X coordinates - // All rects will be aligned at the left side - calcXPositionsL2R(li.viewRect.x, li.leadingGap, li.gap, li.checkRect, - li.iconRect, li.textRect); - - // Tune afterCheckIconGap - if (li.checkRect.width > 0) { // there is the afterCheckIconGap - li.iconRect.x += li.afterCheckIconGap - li.gap; - li.textRect.x += li.afterCheckIconGap - li.gap; - } - - calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.gap, - li.arrowRect, li.accRect); - - // Take into account minimal text offset - int textOffset = li.textRect.x - li.viewRect.x; - if (!li.isTopLevelMenu && (textOffset < li.minTextOffset)) { - li.textRect.x += li.minTextOffset - textOffset; - } - - // Take into account the left side bearings for text and accelerator text. - fixTextRects(li); - - // Set Y coordinate for text and icon. - // Y coordinates for other rects - // will be calculated later in layoutMenuItem. - calcTextAndIconYPositions(li); - - // Calculate valid X and Y coordinates for labelRect - li.labelRect = li.textRect.union(li.iconRect); - } - - private void doLTRComplexLayout(LayoutInfo li) { - li.labelRect.width = li.maxLabelWidth; - - // Set X coordinates - calcXPositionsL2R(li.viewRect.x, li.leadingGap, li.gap, li.checkRect, - li.labelRect); - - // Tune afterCheckIconGap - if (li.checkRect.width > 0) { // there is the afterCheckIconGap - li.labelRect.x += li.afterCheckIconGap - li.gap; - } - - calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.gap, - li.arrowRect, li.accRect); - - // Take into account minimal text offset - int labelOffset = li.labelRect.x - li.viewRect.x; - if (!li.isTopLevelMenu && (labelOffset < li.minTextOffset)) { - li.labelRect.x += li.minTextOffset - labelOffset; - } - - // Take into account the left side bearing for accelerator text. - // The LSB for text is taken into account in layoutCompoundLabel() below. - fixAccTextRect(li); - - // Layout icon and text with SwingUtilities.layoutCompoundLabel() - // within the labelRect - li.textRect = new Rectangle(); - li.iconRect = new Rectangle(); - SwingUtilities.layoutCompoundLabel( - li.mi, li.fm, li.text, li.icon, li.verticalAlignment, - li.horizontalAlignment, li.verticalTextPosition, - li.horizontalTextPosition, li.labelRect, - li.iconRect, li.textRect, li.gap); - } - - private void doRTLColumnLayout(LayoutInfo li) { - // Set maximal width for all the five basic rects - // (three other ones are already maximal) - li.iconRect.width = li.maxIconWidth; - li.textRect.width = li.maxTextWidth; - - // Set X coordinates - calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.leadingGap, - li.gap, li.checkRect, li.iconRect, li.textRect); - - // Tune the gap after check icon - if (li.checkRect.width > 0) { // there is the gap after check icon - li.iconRect.x -= li.afterCheckIconGap - li.gap; - li.textRect.x -= li.afterCheckIconGap - li.gap; - } - - calcXPositionsL2R(li.viewRect.x, li.gap, li.arrowRect, - li.accRect); - - // Take into account minimal text offset - int textOffset = (li.viewRect.x + li.viewRect.width) - - (li.textRect.x + li.textRect.width); - if (!li.isTopLevelMenu && (textOffset < li.minTextOffset)) { - li.textRect.x -= li.minTextOffset - textOffset; - } - - // Align icon, text, accelerator text, check icon and arrow icon - // at the right side - rightAlignAllRects(li); - - // Take into account the left side bearings for text and accelerator text. - fixTextRects(li); - - // Set Y coordinates for text and icon. - // Y coordinates for other rects - // will be calculated later in layoutMenuItem. - calcTextAndIconYPositions(li); - - // Calculate valid X and Y coordinate for labelRect - li.labelRect = li.textRect.union(li.iconRect); - } - - private void doRTLComplexLayout(LayoutInfo li) { - li.labelRect.width = li.maxLabelWidth; - - // Set X coordinates - calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.leadingGap, - li.gap, li.checkRect, li.labelRect); - - // Tune the gap after check icon - if (li.checkRect.width > 0) { // there is the gap after check icon - li.labelRect.x -= li.afterCheckIconGap - li.gap; - } - - calcXPositionsL2R(li.viewRect.x, li.gap, li.arrowRect, - li.accRect); - - // Take into account minimal text offset - int labelOffset = (li.viewRect.x + li.viewRect.width) - - (li.labelRect.x + li.labelRect.width); - if (!li.isTopLevelMenu && (labelOffset < li.minTextOffset)) { - li.labelRect.x -= li.minTextOffset - labelOffset; - } - - // Align icon, text, accelerator text, check icon and arrow icon - // at the right side - rightAlignAllRects(li); - - // Take into account the left side bearing for accelerator text. - // The LSB for text is taken into account in layoutCompoundLabel() below. - fixAccTextRect(li); - - // Layout icon and text with SwingUtilities.layoutCompoundLabel() - // within the labelRect - li.textRect = new Rectangle(); - li.iconRect = new Rectangle(); - SwingUtilities.layoutCompoundLabel( - menuItem, li.fm, li.text, li.icon, li.verticalAlignment, - li.horizontalAlignment, li.verticalTextPosition, - li.horizontalTextPosition, li.labelRect, - li.iconRect, li.textRect, li.gap); - } - - private void calcXPositionsL2R(int startXPos, int leadingGap, - int gap, Rectangle... rects) { - int curXPos = startXPos + leadingGap; - for (Rectangle rect : rects) { - rect.x = curXPos; - if (rect.width > 0) { - curXPos += rect.width + gap; - } - } - } - - private void calcXPositionsL2R(int startXPos, int gap, Rectangle... rects) { - calcXPositionsL2R(startXPos, gap, gap, rects); - } - - private void calcXPositionsR2L(int startXPos, int leadingGap, - int gap, Rectangle... rects) { - int curXPos = startXPos - leadingGap; - for (Rectangle rect : rects) { - rect.x = curXPos - rect.width; - if (rect.width > 0) { - curXPos -= rect.width + gap; - } - } - } - - private void calcXPositionsR2L(int startXPos, int gap, Rectangle... rects) { - calcXPositionsR2L(startXPos, gap, gap, rects); - } - - // Takes into account the left side bearings for text and accelerator text - private void fixTextRects(LayoutInfo li) { - if (li.htmlView == null) { // The text isn't a HTML - int lsb = SwingUtilities2.getLeftSideBearing(li.mi, li.fm, li.text); - if (lsb < 0) { - li.textRect.x -= lsb; - } - } - fixAccTextRect(li); - } - - // Takes into account the left side bearing for accelerator text - private void fixAccTextRect(LayoutInfo li) { - int lsb = SwingUtilities2 - .getLeftSideBearing(li.mi, li.accFm, li.accText); - if (lsb < 0) { - li.accRect.x -= lsb; - } - } - - // Sets Y coordinates of text and icon - // taking into account the vertical alignment - private void calcTextAndIconYPositions(LayoutInfo li) { - if (li.verticalAlignment == SwingUtilities.TOP) { - li.textRect.y = (int)(li.viewRect.y - + (float)li.labelRect.height/2 - - (float)li.textRect.height/2); - li.iconRect.y = (int)(li.viewRect.y - + (float)li.labelRect.height/2 - - (float)li.iconRect.height/2); - } else if (li.verticalAlignment == SwingUtilities.CENTER) { - li.textRect.y = (int)(li.viewRect.y - + (float)li.viewRect.height/2 - - (float)li.textRect.height/2); - li.iconRect.y = (int)(li.viewRect.y - + (float)li.viewRect.height/2 - - (float)li.iconRect.height/2); - } - else if (li.verticalAlignment == SwingUtilities.BOTTOM) { - li.textRect.y = (int)(li.viewRect.y + li.viewRect.height - - (float)li.labelRect.height/2 - - (float)li.textRect.height/2); - li.iconRect.y = (int)(li.viewRect.y + li.viewRect.height - - (float)li.labelRect.height/2 - - (float)li.iconRect.height/2); - } - } - - // Aligns icon, text, accelerator text, check icon and arrow icon - // at the right side - private void rightAlignAllRects(LayoutInfo li) { - li.iconRect.x = li.iconRect.x + li.iconRect.width - li.origIconWidth; - li.iconRect.width = li.origIconWidth; - li.textRect.x = li.textRect.x + li.textRect.width - li.origTextWidth; - li.textRect.width = li.origTextWidth; - li.accRect.x = li.accRect.x + li.accRect.width - - li.origAccWidth; - li.accRect.width = li.origAccWidth; - li.checkRect.x = li.checkRect.x + li.checkRect.width - - li.origCheckWidth; - li.checkRect.width = li.origCheckWidth; - li.arrowRect.x = li.arrowRect.x + li.arrowRect.width - - li.origArrowWidth; - li.arrowRect.width = li.origArrowWidth; - } - - /* - * Returns false if the component is a JMenu and it is a top - * level menu (on the menubar). - */ - private boolean useCheckAndArrow(){ - boolean b = true; - if((menuItem instanceof JMenu) && - (((JMenu)menuItem).isTopLevelMenu())) { - b = false; - } - return b; - } - public MenuElement[] getPath() { MenuSelectionManager m = MenuSelectionManager.defaultManager(); MenuElement oldPath[] = m.getSelectedPath(); @@ -1601,7 +737,7 @@ public class BasicMenuItemUI extends MenuItemUI for(i=0,j=path.length; i 0) { me = new MenuElement[4]; me[0] = (MenuElement) cnt; - me[1] = (MenuElement) menu; - me[2] = (MenuElement) menu.getPopupMenu(); + me[1] = menu; + me[2] = menu.getPopupMenu(); me[3] = subElements[0]; } else { me = new MenuElement[3]; me[0] = (MenuElement)cnt; me[1] = menu; - me[2] = (MenuElement) menu.getPopupMenu(); + me[2] = menu.getPopupMenu(); } defaultManager.setSelectedPath(me); } @@ -606,7 +605,7 @@ public class BasicMenuUI extends BasicMenuItemUI MenuSelectionManager manager = e.getMenuSelectionManager(); if (key == Character.toLowerCase(e.getKeyChar())) { JPopupMenu popupMenu = ((JMenu)menuItem).getPopupMenu(); - ArrayList newList = new ArrayList(Arrays.asList(path)); + ArrayList newList = new ArrayList(Arrays.asList(path)); newList.add(popupMenu); MenuElement subs[] = popupMenu.getSubElements(); MenuElement sub = @@ -614,8 +613,8 @@ public class BasicMenuUI extends BasicMenuItemUI if(sub != null) { newList.add(sub); } - MenuElement newPath[] = new MenuElement[0];; - newPath = (MenuElement[]) newList.toArray(newPath); + MenuElement newPath[] = new MenuElement[0]; + newPath = newList.toArray(newPath); manager.setSelectedPath(newPath); e.consume(); } else if (((JMenu)menuItem).isTopLevelMenu() diff --git a/src/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index 4a226a282e9efe5ae665f1f142ecf2fe0a3014cb..5f0610fa14e0e85c2c71f37a2108a2f4eca8e70a 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -109,7 +109,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { static { - newline = (String)java.security.AccessController.doPrivileged( + newline = java.security.AccessController.doPrivileged( new GetPropertyAction("line.separator")); if (newline == null) { newline = "\n"; @@ -262,7 +262,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { * getMinimumOptionPaneSize. */ public Dimension getPreferredSize(JComponent c) { - if ((JOptionPane)c == optionPane) { + if (c == optionPane) { Dimension ourMin = getMinimumOptionPaneSize(); LayoutManager lm = c.getLayout(); @@ -366,8 +366,8 @@ public class BasicOptionPaneUI extends OptionPaneUI { } else if (msg instanceof Object[]) { Object [] msgs = (Object[]) msg; - for (int i = 0; i < msgs.length; i++) { - addMessageComponents(container, cons, msgs[i], maxll, false); + for (Object o : msgs) { + addMessageComponents(container, cons, o, maxll, false); } } else if (msg instanceof Icon) { @@ -381,7 +381,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { if (len <= 0) { return; } - int nl = -1; + int nl; int nll = 0; if ((nl = s.indexOf(newline)) >= 0) { @@ -1320,7 +1320,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { else if (changeName == "componentOrientation") { ComponentOrientation o = (ComponentOrientation)e.getNewValue(); JOptionPane op = (JOptionPane)e.getSource(); - if (o != (ComponentOrientation)e.getOldValue()) { + if (o != e.getOldValue()) { op.applyComponentOrientation(o); } } @@ -1418,7 +1418,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { } JButton createButton() { - JButton button = null; + JButton button; if (minimumWidth > 0) { button = new ConstrainedButton(text, minimumWidth); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index d2d3a0197b7f88c17498b6c3d543b32afce9fc80..8fbb79fffae56c4e2c51b0e03e8380e6a687b323 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -225,14 +225,14 @@ public class BasicPopupMenuUI extends PopupMenuUI { return popup; } - static List getPopups() { + static List getPopups() { MenuSelectionManager msm = MenuSelectionManager.defaultManager(); MenuElement[] p = msm.getSelectedPath(); - List list = new ArrayList(p.length); - for(int i = 0; i < p.length; i++) { - if (p[i] instanceof JPopupMenu) { - list.add((JPopupMenu)p[i]); + List list = new ArrayList(p.length); + for (MenuElement element : p) { + if (element instanceof JPopupMenu) { + list.add((JPopupMenu) element); } } return list; @@ -290,14 +290,14 @@ public class BasicPopupMenuUI extends PopupMenuUI { MenuElement subitem = findEnabledChild( subpopup.getSubElements(), -1, true); - ArrayList lst = new ArrayList(Arrays.asList(e.getPath())); + ArrayList lst = new ArrayList(Arrays.asList(e.getPath())); lst.add(menuToOpen); lst.add(subpopup); if (subitem != null) { lst.add(subitem); } - MenuElement newPath[] = new MenuElement[0];; - newPath = (MenuElement[])lst.toArray(newPath); + MenuElement newPath[] = new MenuElement[0]; + newPath = lst.toArray(newPath); MenuSelectionManager.defaultManager().setSelectedPath(newPath); e.consume(); } @@ -345,7 +345,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { } if (matches == 0) { - ; // no op + // no op } else if (matches == 1) { // Invoke the menu action JMenuItem item = (JMenuItem)items[firstMatch]; @@ -362,7 +362,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { // Select the menu item with the matching mnemonic. If // the same mnemonic has been invoked then select the next // menu item in the cycle. - MenuElement newItem = null; + MenuElement newItem; newItem = items[indexes[(currentIndex + 1) % matches]]; @@ -372,7 +372,6 @@ public class BasicPopupMenuUI extends PopupMenuUI { manager.setSelectedPath(newPath); e.consume(); } - return; } public void menuKeyReleased(MenuKeyEvent e) { @@ -625,7 +624,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { // 4234793: This action should call JPopupMenu.firePopupMenuCanceled but it's // a protected method. The real solution could be to make // firePopupMenuCanceled public and call it directly. - JPopupMenu lastPopup = (JPopupMenu)getLastPopup(); + JPopupMenu lastPopup = getLastPopup(); if (lastPopup != null) { lastPopup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE); } @@ -703,7 +702,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { static MenuElement findEnabledChild(MenuElement e[], int fromIndex, boolean forward) { - MenuElement result = null; + MenuElement result; if (forward) { result = nextEnabledChild(e, fromIndex+1, e.length-1); if (result == null) result = nextEnabledChild(e, 0, fromIndex-1); @@ -752,7 +751,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { // A grab needs to be added final Toolkit tk = Toolkit.getDefaultToolkit(); java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction() { public Object run() { tk.addAWTEventListener(MouseGrabber.this, AWTEvent.MOUSE_EVENT_MASK | @@ -785,7 +784,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { final Toolkit tk = Toolkit.getDefaultToolkit(); // The grab should be removed java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction() { public Object run() { tk.removeAWTEventListener(MouseGrabber.this); return null; @@ -911,10 +910,8 @@ public class BasicPopupMenuUI extends PopupMenuUI { // 4234793: This action should call firePopupMenuCanceled but it's // a protected method. The real solution could be to make // firePopupMenuCanceled public and call it directly. - List popups = getPopups(); - Iterator iter = popups.iterator(); - while (iter.hasNext()) { - JPopupMenu popup = (JPopupMenu) iter.next(); + List popups = getPopups(); + for (JPopupMenu popup : popups) { popup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE); } MenuSelectionManager.defaultManager().clearSelectedPath(); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java b/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java index 567f4e794467794213b9da99ddaa72edc552f146..d1ddab9934a4ed9aa0e4d0c8dd3a08d4468d9284 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -150,15 +150,15 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI } } else if(model.isSelected()) { if(b.isRolloverEnabled() && model.isRollover()) { - altIcon = (Icon) b.getRolloverSelectedIcon(); + altIcon = b.getRolloverSelectedIcon(); if (altIcon == null) { - altIcon = (Icon) b.getSelectedIcon(); + altIcon = b.getSelectedIcon(); } } else { - altIcon = (Icon) b.getSelectedIcon(); + altIcon = b.getSelectedIcon(); } } else if(b.isRolloverEnabled() && model.isRollover()) { - altIcon = (Icon) b.getRolloverIcon(); + altIcon = b.getRolloverIcon(); } if(altIcon == null) { @@ -214,7 +214,7 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI String text = b.getText(); - Icon buttonIcon = (Icon) b.getIcon(); + Icon buttonIcon = b.getIcon(); if(buttonIcon == null) { buttonIcon = getDefaultIcon(); } diff --git a/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java b/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java index 28427f7b3b0f96c2fb832ee99e368ad329a580e7..0c7e995f05343be1de0c9f3ce6a509038cf86a56 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -106,13 +106,13 @@ public class BasicSplitPaneUI extends SplitPaneUI * Keys to use for forward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusForwardTraversalKeys; + private static Set managingFocusForwardTraversalKeys; /** * Keys to use for backward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusBackwardTraversalKeys; + private static Set managingFocusBackwardTraversalKeys; /** @@ -370,7 +370,7 @@ public class BasicSplitPaneUI extends SplitPaneUI // focus forward traversal key if (managingFocusForwardTraversalKeys==null) { - managingFocusForwardTraversalKeys = new HashSet(); + managingFocusForwardTraversalKeys = new HashSet(); managingFocusForwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); } @@ -378,7 +378,7 @@ public class BasicSplitPaneUI extends SplitPaneUI managingFocusForwardTraversalKeys); // focus backward traversal key if (managingFocusBackwardTraversalKeys==null) { - managingFocusBackwardTraversalKeys = new HashSet(); + managingFocusBackwardTraversalKeys = new HashSet(); managingFocusBackwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK)); } @@ -2170,7 +2170,7 @@ public class BasicSplitPaneUI extends SplitPaneUI Component focusOn = (direction > 0) ? policy.getComponentAfter(rootAncestor, splitPane) : policy.getComponentBefore(rootAncestor, splitPane); - HashSet focusFrom = new HashSet(); + HashSet focusFrom = new HashSet(); if (splitPane.isAncestorOf(focusOn)) { do { focusFrom.add(focusOn); @@ -2212,7 +2212,7 @@ public class BasicSplitPaneUI extends SplitPaneUI private Component getNextSide(JSplitPane splitPane, Component focus) { Component left = splitPane.getLeftComponent(); Component right = splitPane.getRightComponent(); - Component next = null; + Component next; if (focus!=null && SwingUtilities.isDescendingFrom(focus, left) && right!=null) { next = getFirstAvailableComponent(right); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 29919d50475eacba927f2f1412dbf81c24cfc230..a266b77141e9f50091cc177cf4cff00880402267 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -142,9 +142,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { private Component visibleComponent; // PENDING(api): See comment for ContainerHandler - private Vector htmlViews; + private Vector htmlViews; - private Hashtable mnemonicToIndexMap; + private Hashtable mnemonicToIndexMap; /** * InputMap used for mnemonics. Only non-null if the JTabbedPane has @@ -546,7 +546,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { * Installs the state needed for mnemonics. */ private void initMnemonics() { - mnemonicToIndexMap = new Hashtable(); + mnemonicToIndexMap = new Hashtable(); mnemonicInputMap = new ComponentInputMapUIResource(tabPane); mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane, JComponent.WHEN_IN_FOCUSED_WINDOW)); @@ -909,10 +909,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { private static final int CROP_SEGMENT = 12; private static Polygon createCroppedTabShape(int tabPlacement, Rectangle tabRect, int cropline) { - int rlen = 0; - int start = 0; - int end = 0; - int ostart = 0; + int rlen; + int start; + int end; + int ostart; switch(tabPlacement) { case LEFT: @@ -1014,7 +1014,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { tabPane.putClientProperty("html", v); } - SwingUtilities.layoutCompoundLabel((JComponent) tabPane, + SwingUtilities.layoutCompoundLabel(tabPane, metrics, title, icon, SwingUtilities.CENTER, SwingUtilities.CENTER, @@ -1694,7 +1694,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { */ protected View getTextViewForTab(int tabIndex) { if (htmlViews != null) { - return (View)htmlViews.elementAt(tabIndex); + return htmlViews.elementAt(tabIndex); } return null; } @@ -2230,8 +2230,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { if (mnemonic >= 'a' && mnemonic <='z') { mnemonic -= ('a' - 'A'); } - Integer index = (Integer)ui.mnemonicToIndexMap. - get(Integer.valueOf(mnemonic)); + Integer index = ui.mnemonicToIndexMap.get(Integer.valueOf(mnemonic)); if (index != null && pane.isEnabledAt(index.intValue())) { pane.setSelectedIndex(index.intValue()); } @@ -2292,8 +2291,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { for (int i = 0; i < tabPane.getTabCount(); i++) { Component component = tabPane.getComponentAt(i); if (component != null) { - Dimension size = zeroSize; - size = minimum? component.getMinimumSize() : + Dimension size = minimum ? component.getMinimumSize() : component.getPreferredSize(); if (size != null) { @@ -2305,7 +2303,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { // Add content border insets to minimum size width += cWidth; height += cHeight; - int tabExtent = 0; + int tabExtent; // Calculate how much space the tabs will need, based on the // minimum size required to display largest child + content border @@ -3143,7 +3141,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { Insets tabAreaInsets = getTabAreaInsets(tabPlacement); int fontHeight = metrics.getHeight(); int selectedIndex = tabPane.getSelectedIndex(); - int i, j; + int i; boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT); boolean leftToRight = BasicGraphicsUtils.isLeftToRight(tabPane); int x = tabAreaInsets.left; @@ -3433,10 +3431,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { } public String toString() { - return new String("viewport.viewSize="+viewport.getViewSize()+"\n"+ + return "viewport.viewSize=" + viewport.getViewSize() + "\n" + "viewport.viewRectangle="+viewport.getViewRect()+"\n"+ "leadingTabIndex="+leadingTabIndex+"\n"+ - "tabViewPosition="+tabViewPosition); + "tabViewPosition=" + tabViewPosition; } } @@ -3788,8 +3786,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { } } - private Vector createHTMLVector() { - Vector htmlViews = new Vector(); + private Vector createHTMLVector() { + Vector htmlViews = new Vector(); int count = tabPane.getTabCount(); if (count>0) { for (int i=0 ; i storedForwardTraversalKeys = editor. getFocusTraversalKeys(KeyboardFocusManager. FORWARD_TRAVERSAL_KEYS); - Set storedBackwardTraversalKeys = editor. + Set storedBackwardTraversalKeys = editor. getFocusTraversalKeys(KeyboardFocusManager. BACKWARD_TRAVERSAL_KEYS); - Set forwardTraversalKeys = - new HashSet(storedForwardTraversalKeys); - Set backwardTraversalKeys = - new HashSet(storedBackwardTraversalKeys); + Set forwardTraversalKeys = + new HashSet(storedForwardTraversalKeys); + Set backwardTraversalKeys = + new HashSet(storedBackwardTraversalKeys); if (editor.isEditable()) { forwardTraversalKeys. remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); @@ -1888,7 +1888,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * * @param e The change notification from the currently associated * document. - * @see DocumentListener#changeUpdate + * @see DocumentListener#changedUpdate(DocumentEvent) */ public final void changedUpdate(DocumentEvent e) { Rectangle alloc = (painted) ? getVisibleEditorRect() : null; @@ -1964,9 +1964,9 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { } try { rootView.setSize(alloc.width, alloc.height); - Enumeration components = constraints.keys(); + Enumeration components = constraints.keys(); while (components.hasMoreElements()) { - Component comp = (Component) components.nextElement(); + Component comp = components.nextElement(); View v = (View) constraints.get(comp); Shape ca = calculateViewPosition(alloc, v); if (ca != null) { @@ -2009,7 +2009,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { public void addLayoutComponent(Component comp, Object constraint) { if (constraint instanceof View) { if (constraints == null) { - constraints = new Hashtable(7); + constraints = new Hashtable(7); } constraints.put(comp, constraint); } @@ -2060,7 +2060,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * These are View objects for those components that are represented * by a View in the View tree. */ - private Hashtable constraints; + private Hashtable constraints; private boolean i18nView = false; } @@ -2457,8 +2457,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { JTextComponent c = (JTextComponent)comp; int pos = modeBetween - ? ((JTextComponent.DropLocation)c.getDropLocation()).getIndex() - : c.getCaretPosition(); + ? c.getDropLocation().getIndex() : c.getCaretPosition(); // if we are importing to the same component that we exported from // then don't actually do anything if the drop location is inside diff --git a/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java b/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java index 60802d6cc7019b1fd2f923e69dd5b132ec9618cf..18daffa5999faa77fa16d8ebc49bd8a2ed946453 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -125,31 +125,31 @@ public class BasicToggleButtonUI extends BasicButtonUI { if(!model.isEnabled()) { if(model.isSelected()) { - icon = (Icon) b.getDisabledSelectedIcon(); + icon = b.getDisabledSelectedIcon(); } else { - icon = (Icon) b.getDisabledIcon(); + icon = b.getDisabledIcon(); } } else if(model.isPressed() && model.isArmed()) { - icon = (Icon) b.getPressedIcon(); + icon = b.getPressedIcon(); if(icon == null) { // Use selected icon - icon = (Icon) b.getSelectedIcon(); + icon = b.getSelectedIcon(); } } else if(model.isSelected()) { if(b.isRolloverEnabled() && model.isRollover()) { - icon = (Icon) b.getRolloverSelectedIcon(); + icon = b.getRolloverSelectedIcon(); if (icon == null) { - icon = (Icon) b.getSelectedIcon(); + icon = b.getSelectedIcon(); } } else { - icon = (Icon) b.getSelectedIcon(); + icon = b.getSelectedIcon(); } } else if(b.isRolloverEnabled() && model.isRollover()) { - icon = (Icon) b.getRolloverIcon(); + icon = b.getRolloverIcon(); } if(icon == null) { - icon = (Icon) b.getIcon(); + icon = b.getIcon(); } icon.paintIcon(b, g, iconRect.x, iconRect.y); diff --git a/src/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java b/src/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java index 061dd31b4ed703f31e42fb72c9d35575b22a1e7d..0eafa7e3b6b8f648ba7086bcb5783dc1a6988248 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java @@ -83,8 +83,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants private static Border nonRolloverToggleBorder; private boolean rolloverBorders = false; - private HashMap borderTable = new HashMap(); - private Hashtable rolloverTable = new Hashtable(); + private HashMap borderTable = new HashMap(); + private Hashtable rolloverTable = new Hashtable(); /** @@ -171,7 +171,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants uninstallKeyboardActions(); // Clear instance vars - if (isFloating() == true) + if (isFloating()) setFloating(false, null); floatingToolBar = null; @@ -273,9 +273,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants // Put focus listener on all components in toolbar Component[] components = toolBar.getComponents(); - for ( int i = 0; i < components.length; ++i ) - { - components[ i ].addFocusListener( toolBarFocusListener ); + for (Component component : components) { + component.addFocusListener(toolBarFocusListener); } } } @@ -307,9 +306,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants // Remove focus listener from all components in toolbar Component[] components = toolBar.getComponents(); - for ( int i = 0; i < components.length; ++i ) - { - components[ i ].removeFocusListener( toolBarFocusListener ); + for (Component component : components) { + component.removeFocusListener(toolBarFocusListener); } toolBarFocusListener = null; @@ -616,10 +614,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants // Put rollover borders on buttons Component[] components = c.getComponents(); - for ( int i = 0; i < components.length; ++i ) { - if ( components[ i ] instanceof JComponent ) { - ( (JComponent)components[ i ] ).updateUI(); - setBorderToRollover( components[ i ] ); + for (Component component : components) { + if (component instanceof JComponent) { + ((JComponent) component).updateUI(); + setBorderToRollover(component); } } } @@ -640,10 +638,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants // Put non-rollover borders on buttons. These borders reduce the margin. Component[] components = c.getComponents(); - for ( int i = 0; i < components.length; ++i ) { - if ( components[ i ] instanceof JComponent ) { - ( (JComponent)components[ i ] ).updateUI(); - setBorderToNonRollover( components[ i ] ); + for (Component component : components) { + if (component instanceof JComponent) { + ((JComponent) component).updateUI(); + setBorderToNonRollover(component); } } } @@ -664,8 +662,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants // Put back the normal borders on buttons Component[] components = c.getComponents(); - for ( int i = 0; i < components.length; ++i ) { - setBorderToNormal( components[ i ] ); + for (Component component : components) { + setBorderToNormal(component); } } @@ -681,7 +679,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (c instanceof AbstractButton) { AbstractButton b = (AbstractButton)c; - Border border = (Border)borderTable.get(b); + Border border = borderTable.get(b); if (border == null || border instanceof UIResource) { borderTable.put(b, b.getBorder()); } @@ -721,7 +719,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (c instanceof AbstractButton) { AbstractButton b = (AbstractButton)c; - Border border = (Border)borderTable.get(b); + Border border = borderTable.get(b); if (border == null || border instanceof UIResource) { borderTable.put(b, b.getBorder()); } @@ -765,10 +763,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (c instanceof AbstractButton) { AbstractButton b = (AbstractButton)c; - Border border = (Border)borderTable.remove(b); + Border border = borderTable.remove(b); b.setBorder(border); - Boolean value = (Boolean)rolloverTable.remove(b); + Boolean value = rolloverTable.remove(b); if (value != null) { b.setRolloverEnabled(value.booleanValue()); } @@ -785,7 +783,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants } public void setFloating(boolean b, Point p) { - if (toolBar.isFloatable() == true) { + if (toolBar.isFloatable()) { boolean visible = false; Window ancestor = SwingUtilities.getWindowAncestor(toolBar); if (ancestor != null) { @@ -953,7 +951,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants protected void dragTo(Point position, Point origin) { - if (toolBar.isFloatable() == true) + if (toolBar.isFloatable()) { try { @@ -1003,7 +1001,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants protected void floatAt(Point position, Point origin) { - if(toolBar.isFloatable() == true) + if(toolBar.isFloatable()) { try { @@ -1174,7 +1172,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (!tb.isEnabled()) { return; } - if (isDragging == true) { + if (isDragging) { Point position = evt.getPoint(); if (origin == null) origin = evt.getComponent().getLocationOnScreen(); @@ -1242,7 +1240,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants protected class FrameListener extends WindowAdapter { public void windowClosing(WindowEvent w) { - if (toolBar.isFloatable() == true) { + if (toolBar.isFloatable()) { if (dragWindow != null) dragWindow.setVisible(false); floating = false; diff --git a/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 56b16ba7cce34a633827f343e346d9be98bfb9c1..eee08821e05741f6a51596b29f6237f9434b19cd 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -1263,7 +1263,7 @@ public class BasicTreeUI extends TreeUI } private Rectangle getDropLineRect(JTree.DropLocation loc) { - Rectangle rect = null; + Rectangle rect; TreePath path = loc.getPath(); int index = loc.getChildIndex(); boolean ltr = leftToRight; @@ -2138,7 +2138,7 @@ public class BasicTreeUI extends TreeUI compositeRequestFocus(editingComponent); boolean selectAll = true; - if(event != null && event instanceof MouseEvent) { + if(event != null) { /* Find the component that will get forwarded all the mouse events until mouseReleased. */ Point componentPoint = SwingUtilities.convertPoint @@ -3125,7 +3125,7 @@ public class BasicTreeUI extends TreeUI private static final TransferHandler defaultTransferHandler = new TreeTransferHandler(); - static class TreeTransferHandler extends TransferHandler implements UIResource, Comparator { + static class TreeTransferHandler extends TransferHandler implements UIResource, Comparator { private JTree tree; @@ -3156,9 +3156,7 @@ public class BasicTreeUI extends TreeUI TreePath lastPath = null; TreePath[] displayPaths = getDisplayOrderPaths(paths); - for (int i = 0; i < displayPaths.length; i++) { - TreePath path = displayPaths[i]; - + for (TreePath path : displayPaths) { Object node = path.getLastPathComponent(); boolean leaf = model.isLeaf(node); String label = getDisplayString(path, true, leaf); @@ -3179,9 +3177,9 @@ public class BasicTreeUI extends TreeUI return null; } - public int compare(Object o1, Object o2) { - int row1 = tree.getRowForPath((TreePath)o1); - int row2 = tree.getRowForPath((TreePath)o2); + public int compare(TreePath o1, TreePath o2) { + int row1 = tree.getRowForPath(o1); + int row2 = tree.getRowForPath(o2); return row1 - row2; } @@ -3200,15 +3198,15 @@ public class BasicTreeUI extends TreeUI */ TreePath[] getDisplayOrderPaths(TreePath[] paths) { // sort the paths to display order rather than selection order - ArrayList selOrder = new ArrayList(); - for (int i = 0; i < paths.length; i++) { - selOrder.add(paths[i]); + ArrayList selOrder = new ArrayList(); + for (TreePath path : paths) { + selOrder.add(path); } Collections.sort(selOrder, this); int n = selOrder.size(); TreePath[] displayPaths = new TreePath[n]; for (int i = 0; i < n; i++) { - displayPaths[i] = (TreePath) selOrder.get(i); + displayPaths[i] = selOrder.get(i); } return displayPaths; } @@ -3321,10 +3319,7 @@ public class BasicTreeUI extends TreeUI InputMap inputMap = tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); KeyStroke key = KeyStroke.getKeyStrokeForEvent(event); - if (inputMap != null && inputMap.get(key) != null) { - return true; - } - return false; + return inputMap != null && inputMap.get(key) != null; } diff --git a/src/share/classes/javax/swing/plaf/basic/DefaultMenuLayout.java b/src/share/classes/javax/swing/plaf/basic/DefaultMenuLayout.java index b29cfaf7aa6ac3362d7b1e06b5db233a5b0345fb..5acae97ededcb0bd5f105c319c878a9d513dfd11 100644 --- a/src/share/classes/javax/swing/plaf/basic/DefaultMenuLayout.java +++ b/src/share/classes/javax/swing/plaf/basic/DefaultMenuLayout.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 @@ -30,7 +30,6 @@ import javax.swing.plaf.UIResource; import java.awt.Container; import java.awt.Dimension; -import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; /** * The default layout manager for Popup menus and menubars. This @@ -49,18 +48,7 @@ public class DefaultMenuLayout extends BoxLayout implements UIResource { public Dimension preferredLayoutSize(Container target) { if (target instanceof JPopupMenu) { JPopupMenu popupMenu = (JPopupMenu) target; - - // Before the calculation of menu preferred size - // clear the previously calculated maximal widths and offsets - // in menu's Client Properties - popupMenu.putClientProperty(BasicMenuItemUI.MAX_ACC_WIDTH, null); - popupMenu.putClientProperty(BasicMenuItemUI.MAX_ARROW_WIDTH, null); - popupMenu.putClientProperty(BasicMenuItemUI.MAX_CHECK_WIDTH, null); - popupMenu.putClientProperty(BasicMenuItemUI.MAX_ICON_WIDTH, null); - popupMenu.putClientProperty(BasicMenuItemUI.MAX_LABEL_WIDTH, null); - popupMenu.putClientProperty(BasicMenuItemUI.MAX_TEXT_WIDTH, null); - popupMenu.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null); - + sun.swing.MenuItemLayoutHelper.clearUsedClientProperties(popupMenu); if (popupMenu.getComponentCount() == 0) { return new Dimension(0, 0); } diff --git a/src/share/classes/javax/swing/plaf/basic/DesktopIconMover.java b/src/share/classes/javax/swing/plaf/basic/DesktopIconMover.java new file mode 100644 index 0000000000000000000000000000000000000000..deff4f27a5f9ebb542a68fbc3af211ec99859e16 --- /dev/null +++ b/src/share/classes/javax/swing/plaf/basic/DesktopIconMover.java @@ -0,0 +1,168 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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.swing.plaf.basic; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.beans.*; + +/** + * DesktopIconMover is intended to move desktop icon + * when parent window is resized. + */ +class DesktopIconMover implements ComponentListener, PropertyChangeListener { + private Component parent; + private JInternalFrame frame; // if not null, DesktopIconMover(frame) + // constructor was used + private JInternalFrame.JDesktopIcon icon; + private Rectangle parentBounds; + private boolean componentListenerAdded = false; + + public DesktopIconMover(JInternalFrame frame) { + if (frame == null) { + throw new NullPointerException("Frame cannot be null"); + } + this.frame = frame; + this.icon = frame.getDesktopIcon(); + if (icon == null) { + throw new NullPointerException( + "frame.getDesktopIcon() cannot be null"); + } + this.parent = frame.getParent(); + if (this.parent != null) { + parentBounds = this.parent.getBounds(); + } + } + + public DesktopIconMover(JInternalFrame.JDesktopIcon icon) { + if (icon == null) { + throw new NullPointerException("Icon cannot be null"); + } + this.icon = icon; + this.parent = icon.getParent(); + if (this.parent != null) { + parentBounds = this.parent.getBounds(); + } + } + + public void installListeners() { + if (frame != null) { + frame.addPropertyChangeListener(this); + } else { + icon.addPropertyChangeListener(this); + } + addComponentListener(); + } + + public void uninstallListeners() { + if (frame != null) { + frame.removePropertyChangeListener(this); + } else { + icon.removePropertyChangeListener(this); + } + removeComponentListener(); + } + + public void propertyChange(PropertyChangeEvent evt) { + String propName = evt.getPropertyName(); + if ("ancestor".equals(propName)) { + Component newAncestor = (Component) evt.getNewValue(); + + // Remove component listener if parent is changing + Component probablyNewParent = getCurrentParent(); + if ((probablyNewParent != null) && + (!probablyNewParent.equals(parent))) { + removeComponentListener(); + parent = probablyNewParent; + } + + if (newAncestor == null) { + removeComponentListener(); + } else { + addComponentListener(); + } + + // Update parentBounds + if (parent != null) { + parentBounds = parent.getBounds(); + } else { + parentBounds = null; + } + } else if (JInternalFrame.IS_CLOSED_PROPERTY.equals(propName)) { + removeComponentListener(); + } + } + + private void addComponentListener() { + if (!componentListenerAdded && (parent != null)) { + parent.addComponentListener(this); + componentListenerAdded = true; + } + } + + private void removeComponentListener() { + if ((parent != null) && componentListenerAdded) { + parent.removeComponentListener(this); + componentListenerAdded = false; + } + } + + private Component getCurrentParent() { + if (frame != null) { + return frame.getParent(); + } else { + return icon.getParent(); + } + } + + public void componentResized(ComponentEvent e) { + if ((parent == null) || (parentBounds == null)) { + return; + } + + Rectangle parentNewBounds = parent.getBounds(); + if ((parentNewBounds == null) || parentNewBounds.equals(parentBounds)) { + return; + } + + // Move desktop icon only in up-down direction + int newIconY = icon.getLocation().y + + (parentNewBounds.height - parentBounds.height); + icon.setLocation(icon.getLocation().x, newIconY); + + parentBounds = parentNewBounds; + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentShown(ComponentEvent e) { + } + + public void componentHidden(ComponentEvent e) { + } +} diff --git a/src/share/classes/javax/swing/plaf/basic/DragRecognitionSupport.java b/src/share/classes/javax/swing/plaf/basic/DragRecognitionSupport.java index 060019810e4f3ca8cb7e8fe3317a6ad241188e9b..be457ccb258e3b86327525dcec8de6689a77b601 100644 --- a/src/share/classes/javax/swing/plaf/basic/DragRecognitionSupport.java +++ b/src/share/classes/javax/swing/plaf/basic/DragRecognitionSupport.java @@ -73,8 +73,7 @@ class DragRecognitionSupport { * Returns whether or not the event is potentially part of a drag sequence. */ public static boolean mousePressed(MouseEvent me) { - return ((DragRecognitionSupport)getDragRecognitionSupport()). - mousePressedImpl(me); + return getDragRecognitionSupport().mousePressedImpl(me); } /** @@ -82,16 +81,14 @@ class DragRecognitionSupport { * that started the recognition. Otherwise, return null. */ public static MouseEvent mouseReleased(MouseEvent me) { - return ((DragRecognitionSupport)getDragRecognitionSupport()). - mouseReleasedImpl(me); + return getDragRecognitionSupport().mouseReleasedImpl(me); } /** * Returns whether or not a drag gesture recognition is ongoing. */ public static boolean mouseDragged(MouseEvent me, BeforeDrag bd) { - return ((DragRecognitionSupport)getDragRecognitionSupport()). - mouseDraggedImpl(me, bd); + return getDragRecognitionSupport().mouseDraggedImpl(me, bd); } private void clearState() { diff --git a/src/share/classes/javax/swing/plaf/basic/LazyActionMap.java b/src/share/classes/javax/swing/plaf/basic/LazyActionMap.java index f148707a769909bc4310fa31bb8a4de9926bda60..e57ff78d23d9a167a77a10e691d74d4ebee03b65 100644 --- a/src/share/classes/javax/swing/plaf/basic/LazyActionMap.java +++ b/src/share/classes/javax/swing/plaf/basic/LazyActionMap.java @@ -142,7 +142,7 @@ class LazyActionMap extends ActionMapUIResource { Object loader = _loader; _loader = null; - Class klass = (Class)loader; + Class klass = (Class)loader; try { Method method = klass.getDeclaredMethod("loadActionMap", new Class[] { LazyActionMap.class }); diff --git a/src/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java b/src/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java index dbb9b346a4d6dd07d913a55ff6e9126f2b0b36ea..96b944d0db249585ea24a3ae78db76591b95462f 100644 --- a/src/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java +++ b/src/share/classes/javax/swing/plaf/metal/DefaultMetalTheme.java @@ -387,9 +387,9 @@ public class DefaultMetalTheme extends MetalTheme { * that it is wrapped inside a doPrivileged call. */ protected Font getPrivilegedFont(final int key) { - return (Font)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { + return java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Font run() { return Font.getFont(getDefaultPropertyName(key)); } } diff --git a/src/share/classes/javax/swing/plaf/metal/MetalBumps.java b/src/share/classes/javax/swing/plaf/metal/MetalBumps.java index ec6f0300c8af8e70e502df4fd7486736227de4c6..47e379a48ff04ce2a3836fe67d9cc4940695807a 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalBumps.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalBumps.java @@ -49,7 +49,7 @@ class MetalBumps implements Icon { protected Color shadowColor; protected Color backColor; - protected static Vector buffers = new Vector(); + protected static Vector buffers = new Vector(); protected BumpBuffer buffer; public MetalBumps( Dimension bumpArea ) { @@ -81,10 +81,7 @@ class MetalBumps implements Icon { } BumpBuffer result = null; - Enumeration elements = buffers.elements(); - - while ( elements.hasMoreElements() ) { - BumpBuffer aBuffer = (BumpBuffer)elements.nextElement(); + for (BumpBuffer aBuffer : buffers) { if ( aBuffer.hasSameConfiguration(gc, aTopColor, aShadowColor, aBackColor)) { result = aBuffer; @@ -120,8 +117,7 @@ class MetalBumps implements Icon { public void paintIcon( Component c, Graphics g, int x, int y ) { GraphicsConfiguration gc = (g instanceof Graphics2D) ? - (GraphicsConfiguration)((Graphics2D)g). - getDeviceConfiguration() : null; + ((Graphics2D) g).getDeviceConfiguration() : null; buffer = getBuffer(gc, topColor, shadowColor, backColor); diff --git a/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java b/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java index 3489cd3e4eae06cc5a348580d49fb9f8d708fd5b..fd837b9abf2a8b0356fcc5da26c1f807f4e7d7e1 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -782,7 +782,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { } else if (s.equals("componentOrientation")) { ComponentOrientation o = (ComponentOrientation)e.getNewValue(); JFileChooser cc = (JFileChooser)e.getSource(); - if (o != (ComponentOrientation)e.getOldValue()) { + if (o != e.getOldValue()) { cc.applyComponentOrientation(o); } } else if (s == "FileChooser.useShellFolder") { @@ -927,7 +927,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { * Data model for a type-face selection combo-box. */ protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { - Vector directories = new Vector(); + Vector directories = new Vector(); int[] depths = null; File selectedDirectory = null; JFileChooser chooser = getFileChooser(); @@ -966,7 +966,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { // Get the canonical (full) path. This has the side // benefit of removing extraneous chars from the path, // for example /foo/bar/ becomes /foo/bar - File canonical = null; + File canonical; try { canonical = ShellFolder.getNormalizedFile(directory); } catch (IOException e) { @@ -979,7 +979,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { File sf = useShellFolder ? ShellFolder.getShellFolder(canonical) : canonical; File f = sf; - Vector path = new Vector(10); + Vector path = new Vector(10); do { path.addElement(f); } while ((f = f.getParentFile()) != null); @@ -987,7 +987,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { int pathCount = path.size(); // Insert chain at appropriate place in vector for (int i = 0; i < pathCount; i++) { - f = (File)path.get(i); + f = path.get(i); if (directories.contains(f)) { int topIndex = directories.indexOf(f); for (int j = i-1; j >= 0; j--) { @@ -1006,12 +1006,12 @@ public class MetalFileChooserUI extends BasicFileChooserUI { private void calculateDepths() { depths = new int[directories.size()]; for (int i = 0; i < depths.length; i++) { - File dir = (File)directories.get(i); + File dir = directories.get(i); File parent = dir.getParentFile(); depths[i] = 0; if (parent != null) { for (int j = i-1; j >= 0; j--) { - if (parent.equals((File)directories.get(j))) { + if (parent.equals(directories.get(j))) { depths[i] = depths[j] + 1; break; } @@ -1110,8 +1110,8 @@ public class MetalFileChooserUI extends BasicFileChooserUI { FileFilter currentFilter = getFileChooser().getFileFilter(); boolean found = false; if(currentFilter != null) { - for(int i=0; i < filters.length; i++) { - if(filters[i] == currentFilter) { + for (FileFilter filter : filters) { + if (filter == currentFilter) { found = true; } } diff --git a/src/share/classes/javax/swing/plaf/metal/MetalIconFactory.java b/src/share/classes/javax/swing/plaf/metal/MetalIconFactory.java index c7da086d46663e6a2e63c3cdae5b287ba152a0da..212961e5174cb6b2d4cf17199f8b16e661b9746b 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalIconFactory.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalIconFactory.java @@ -598,7 +598,7 @@ public class MetalIconFactory implements Serializable { } // Some calculations that are needed more than once later on. - int oneHalf = (int)(iconSize / 2); // 16 -> 8 + int oneHalf = iconSize / 2; // 16 -> 8 g.translate(x, y); @@ -1502,7 +1502,7 @@ public class MetalIconFactory implements Serializable { // PENDING: Replace this class with CachedPainter. - Vector images = new Vector(1, 1); + Vector images = new Vector(1, 1); ImageGcPair currentImageGcPair; class ImageGcPair { @@ -1514,12 +1514,8 @@ public class MetalIconFactory implements Serializable { } boolean hasSameConfiguration(GraphicsConfiguration newGC) { - if (((newGC != null) && (newGC.equals(gc))) || - ((newGC == null) && (gc == null))) - { - return true; - } - return false; + return ((newGC != null) && (newGC.equals(gc))) || + ((newGC == null) && (gc == null)); } } @@ -1528,9 +1524,7 @@ public class MetalIconFactory implements Serializable { if ((currentImageGcPair == null) || !(currentImageGcPair.hasSameConfiguration(newGC))) { - Enumeration elements = images.elements(); - while (elements.hasMoreElements()) { - ImageGcPair imgGcPair = (ImageGcPair)elements.nextElement(); + for (ImageGcPair imgGcPair : images) { if (imgGcPair.hasSameConfiguration(newGC)) { currentImageGcPair = imgGcPair; return imgGcPair.image; diff --git a/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java index a0b8ada118f4bd1da2de06340562d245db9233a8..6de655d586eb449904c4bdd8ec97df1d8b049fb2 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java @@ -191,7 +191,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane { extends BasicInternalFrameTitlePane.PropertyChangeHandler { public void propertyChange(PropertyChangeEvent evt) { - String prop = (String)evt.getPropertyName(); + String prop = evt.getPropertyName(); if( prop.equals(JInternalFrame.IS_SELECTED_PROPERTY) ) { Boolean b = (Boolean)evt.getNewValue(); iconButton.putClientProperty("paintActive", b); @@ -242,7 +242,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane { } // Compute height. - int height = 0; + int height; if (isPalette) { height = paletteTitleHeight; } else { @@ -410,7 +410,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane { g.drawLine ( width - 1, 0 , width -1, 0); - int titleLength = 0; + int titleLength; int xOffset = leftToRight ? 5 : width - 5; String frameTitle = frame.getTitle(); diff --git a/src/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java b/src/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java index f0084d9f1623b2e0668b76075b58f8405b994bcc..0743284196124bfcd82062f64e009574dbb58e0c 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -2208,9 +2208,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel if (methodName == null) { return c.newInstance(); } - Method method = (Method)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { + Method method = AccessController.doPrivileged( + new PrivilegedAction() { + public Method run() { Method[] methods = c.getDeclaredMethods(); for (int counter = methods.length - 1; counter >= 0; counter--) { @@ -2273,7 +2273,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel } } - static ReferenceQueue queue = new ReferenceQueue(); + static ReferenceQueue queue = new ReferenceQueue(); static void flushUnreferenced() { AATextListener aatl; @@ -2283,7 +2283,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel } static class AATextListener - extends WeakReference implements PropertyChangeListener { + extends WeakReference implements PropertyChangeListener { private String key = SunToolkit.DESKTOPFONTHINTS; @@ -2294,7 +2294,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel } public void propertyChange(PropertyChangeEvent pce) { - LookAndFeel laf = (LookAndFeel)get(); + LookAndFeel laf = get(); if (laf == null || laf != UIManager.getLookAndFeel()) { dispose(); return; @@ -2318,8 +2318,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel private static void updateWindowUI(Window window) { SwingUtilities.updateComponentTreeUI(window); Window ownedWins[] = window.getOwnedWindows(); - for (int i=0; i < ownedWins.length; i++) { - updateWindowUI(ownedWins[i]); + for (Window w : ownedWins) { + updateWindowUI(w); } } @@ -2328,8 +2328,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel */ private static void updateAllUIs() { Frame appFrames[] = Frame.getFrames(); - for (int j=0; j < appFrames.length; j++) { - updateWindowUI(appFrames[j]); + for (Frame frame : appFrames) { + updateWindowUI(frame); } } diff --git a/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java b/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java index 1d6882455c1fbc26328196f7f4d5d97a207ae5e3..ba96b21e6ee6e06ef08b84c5cbf9fa507bcc65de 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -164,15 +164,15 @@ public class MetalRadioButtonUI extends BasicRadioButtonUI { } } else if(model.isSelected()) { if(b.isRolloverEnabled() && model.isRollover()) { - altIcon = (Icon) b.getRolloverSelectedIcon(); + altIcon = b.getRolloverSelectedIcon(); if (altIcon == null) { - altIcon = (Icon) b.getSelectedIcon(); + altIcon = b.getSelectedIcon(); } } else { - altIcon = (Icon) b.getSelectedIcon(); + altIcon = b.getSelectedIcon(); } } else if(b.isRolloverEnabled() && model.isRollover()) { - altIcon = (Icon) b.getRolloverIcon(); + altIcon = b.getRolloverIcon(); } if(altIcon == null) { diff --git a/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java b/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java index 13563b80ecca638cafc0ab6e9ec017dd7369a319..7a26c46b225679877f255c10199a87db8d43244a 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java @@ -27,23 +27,13 @@ package javax.swing.plaf.metal; import javax.swing.plaf.basic.BasicSliderUI; -import java.awt.Component; -import java.awt.Container; import java.awt.Graphics; import java.awt.Dimension; import java.awt.Rectangle; -import java.awt.Point; -import java.awt.Insets; import java.awt.Color; -import java.io.Serializable; -import java.awt.IllegalComponentStateException; -import java.awt.Polygon; import java.beans.*; -import javax.swing.border.AbstractBorder; - import javax.swing.*; -import javax.swing.event.*; import javax.swing.plaf.*; /** @@ -131,10 +121,7 @@ public class MetalSliderUI extends BasicSliderUI { scrollListener.setScrollByBlock( false ); - Object sliderFillProp = c.getClientProperty( SLIDER_FILL ); - if ( sliderFillProp != null ) { - filledSlider = ((Boolean)sliderFillProp).booleanValue(); - } + prepareFilledSliderField(); } protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) { @@ -145,18 +132,23 @@ public class MetalSliderUI extends BasicSliderUI { public void propertyChange( PropertyChangeEvent e ) { // listen for slider fill super.propertyChange( e ); - String name = e.getPropertyName(); - if ( name.equals( SLIDER_FILL ) ) { - if ( e.getNewValue() != null ) { - filledSlider = ((Boolean)e.getNewValue()).booleanValue(); - } - else { - filledSlider = false; - } + if (e.getPropertyName().equals(SLIDER_FILL)) { + prepareFilledSliderField(); } } } + private void prepareFilledSliderField() { + // Use true for Ocean theme + filledSlider = MetalLookAndFeel.usingOcean(); + + Object sliderFillProp = slider.getClientProperty(SLIDER_FILL); + + if (sliderFillProp != null) { + filledSlider = ((Boolean) sliderFillProp).booleanValue(); + } + } + public void paintThumb(Graphics g) { Rectangle knobBounds = thumbRect; @@ -172,22 +164,11 @@ public class MetalSliderUI extends BasicSliderUI { g.translate( -knobBounds.x, -knobBounds.y ); } - /** - * If chooseFirstis true, c1 is returned, - * otherwise c2. - */ - private Color chooseColor(boolean chooseFirst, Color c1, Color c2) { - if (chooseFirst) { - return c2; - } - return c1; - } - /** * Returns a rectangle enclosing the track that will be painted. */ private Rectangle getPaintTrackRect() { - int trackLeft = 0, trackRight = 0, trackTop = 0, trackBottom = 0; + int trackLeft = 0, trackRight, trackTop = 0, trackBottom; if (slider.getOrientation() == JSlider.HORIZONTAL) { trackBottom = (trackRect.height - 1) - getThumbOverhang(); trackTop = trackBottom - (getTrackWidth() - 1); @@ -223,8 +204,8 @@ public class MetalSliderUI extends BasicSliderUI { int trackLeft = 0; int trackTop = 0; - int trackRight = 0; - int trackBottom = 0; + int trackRight; + int trackBottom; // Draw the track if ( slider.getOrientation() == JSlider.HORIZONTAL ) { @@ -266,11 +247,11 @@ public class MetalSliderUI extends BasicSliderUI { // Draw the fill if ( filledSlider ) { - int middleOfThumb = 0; - int fillTop = 0; - int fillLeft = 0; - int fillBottom = 0; - int fillRight = 0; + int middleOfThumb; + int fillTop; + int fillLeft; + int fillBottom; + int fillRight; if ( slider.getOrientation() == JSlider.HORIZONTAL ) { middleOfThumb = thumbRect.x + (thumbRect.width / 2); @@ -314,8 +295,7 @@ public class MetalSliderUI extends BasicSliderUI { } else { g.setColor( MetalLookAndFeel.getControlShadow() ); - g.fillRect( fillLeft, fillTop, - fillRight - fillLeft, trackBottom - trackTop ); + g.fillRect(fillLeft, fillTop, fillRight - fillLeft, fillBottom - fillTop); } } @@ -336,105 +316,137 @@ public class MetalSliderUI extends BasicSliderUI { int w = paintRect.width; int h = paintRect.height; - if (!slider.isEnabled()) { - g.setColor(MetalLookAndFeel.getControlShadow()); - g.drawRect(0, 0, w - 1, h - 1); - } - else if (slider.getOrientation() == JSlider.HORIZONTAL) { - int middleOfThumb = thumbRect.x + (thumbRect.width / 2) - - paintRect.x; - int fillMinX; - int fillMaxX; - - if (middleOfThumb > 0) { - g.setColor(chooseColor(drawInverted, - MetalLookAndFeel.getPrimaryControlDarkShadow(), - MetalLookAndFeel.getControlDarkShadow())); - g.drawRect(0, 0, middleOfThumb - 1, h - 1); - } - if (middleOfThumb < w) { - g.setColor(chooseColor(drawInverted, - MetalLookAndFeel.getControlDarkShadow(), - MetalLookAndFeel.getPrimaryControlDarkShadow())); - g.drawRect(middleOfThumb, 0, w - middleOfThumb - 1, h - 1); - } - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); - if (drawInverted) { - fillMinX = middleOfThumb; - fillMaxX = w - 2; - g.drawLine(1, 1, middleOfThumb, 1); - } - else { - fillMinX = 1; - fillMaxX = middleOfThumb; - g.drawLine(middleOfThumb, 1, w - 1, 1); - } - if (h == 6) { - g.setColor(MetalLookAndFeel.getWhite()); - g.drawLine(fillMinX, 1, fillMaxX, 1); - g.setColor(sliderAltTrackColor); - g.drawLine(fillMinX, 2, fillMaxX, 2); + if (slider.getOrientation() == JSlider.HORIZONTAL) { + int middleOfThumb = thumbRect.x + thumbRect.width / 2 - paintRect.x; + + if (slider.isEnabled()) { + int fillMinX; + int fillMaxX; + + if (middleOfThumb > 0) { + g.setColor(drawInverted ? MetalLookAndFeel.getControlDarkShadow() : + MetalLookAndFeel.getPrimaryControlDarkShadow()); + + g.drawRect(0, 0, middleOfThumb - 1, h - 1); + } + + if (middleOfThumb < w) { + g.setColor(drawInverted ? MetalLookAndFeel.getPrimaryControlDarkShadow() : + MetalLookAndFeel.getControlDarkShadow()); + + g.drawRect(middleOfThumb, 0, w - middleOfThumb - 1, h - 1); + } + + if (filledSlider) { + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + if (drawInverted) { + fillMinX = middleOfThumb; + fillMaxX = w - 2; + g.drawLine(1, 1, middleOfThumb, 1); + } else { + fillMinX = 1; + fillMaxX = middleOfThumb; + g.drawLine(middleOfThumb, 1, w - 1, 1); + } + if (h == 6) { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(fillMinX, 1, fillMaxX, 1); + g.setColor(sliderAltTrackColor); + g.drawLine(fillMinX, 2, fillMaxX, 2); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(fillMinX, 3, fillMaxX, 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(fillMinX, 4, fillMaxX, 4); + } + } + } else { g.setColor(MetalLookAndFeel.getControlShadow()); - g.drawLine(fillMinX, 3, fillMaxX, 3); - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); - g.drawLine(fillMinX, 4, fillMaxX, 4); - } - } - else { - int middleOfThumb = thumbRect.y + (thumbRect.height / 2) - - paintRect.y; - int fillMinY; - int fillMaxY; - - if (middleOfThumb > 0) { - g.setColor(chooseColor(drawInverted, - MetalLookAndFeel.getControlDarkShadow(), - MetalLookAndFeel.getPrimaryControlDarkShadow())); - g.drawRect(0, 0, w - 1, middleOfThumb - 1); - } - if (middleOfThumb < h) { - g.setColor(chooseColor(drawInverted, - MetalLookAndFeel.getPrimaryControlDarkShadow(), - MetalLookAndFeel.getControlDarkShadow())); - g.drawRect(0, middleOfThumb, w - 1, h - middleOfThumb - 1); - } - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); - if (drawInverted()) { - fillMinY = 1; - fillMaxY = middleOfThumb; - if (leftToRight) { - g.drawLine(1, middleOfThumb, 1, h - 1); + + if (middleOfThumb > 0) { + if (!drawInverted && filledSlider) { + g.fillRect(0, 0, middleOfThumb - 1, h - 1); + } else { + g.drawRect(0, 0, middleOfThumb - 1, h - 1); + } } - else { - g.drawLine(w - 2, middleOfThumb, w - 2, h - 1); + + if (middleOfThumb < w) { + if (drawInverted && filledSlider) { + g.fillRect(middleOfThumb, 0, w - middleOfThumb - 1, h - 1); + } else { + g.drawRect(middleOfThumb, 0, w - middleOfThumb - 1, h - 1); + } } } - else { - fillMinY = middleOfThumb; - fillMaxY = h - 2; - if (leftToRight) { - g.drawLine(1, 1, 1, middleOfThumb); + } else { + int middleOfThumb = thumbRect.y + (thumbRect.height / 2) - paintRect.y; + + if (slider.isEnabled()) { + int fillMinY; + int fillMaxY; + + if (middleOfThumb > 0) { + g.setColor(drawInverted ? MetalLookAndFeel.getPrimaryControlDarkShadow() : + MetalLookAndFeel.getControlDarkShadow()); + + g.drawRect(0, 0, w - 1, middleOfThumb - 1); } - else { - g.drawLine(w - 2, 1, w - 2, middleOfThumb); + + if (middleOfThumb < h) { + g.setColor(drawInverted ? MetalLookAndFeel.getControlDarkShadow() : + MetalLookAndFeel.getPrimaryControlDarkShadow()); + + g.drawRect(0, middleOfThumb, w - 1, h - middleOfThumb - 1); + } + + if (filledSlider) { + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + if (drawInverted()) { + fillMinY = 1; + fillMaxY = middleOfThumb; + if (leftToRight) { + g.drawLine(1, middleOfThumb, 1, h - 1); + } else { + g.drawLine(w - 2, middleOfThumb, w - 2, h - 1); + } + } else { + fillMinY = middleOfThumb; + fillMaxY = h - 2; + if (leftToRight) { + g.drawLine(1, 1, 1, middleOfThumb); + } else { + g.drawLine(w - 2, 1, w - 2, middleOfThumb); + } + } + if (w == 6) { + g.setColor(leftToRight ? MetalLookAndFeel.getWhite() : MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(1, fillMinY, 1, fillMaxY); + g.setColor(leftToRight ? sliderAltTrackColor : MetalLookAndFeel.getControlShadow()); + g.drawLine(2, fillMinY, 2, fillMaxY); + g.setColor(leftToRight ? MetalLookAndFeel.getControlShadow() : sliderAltTrackColor); + g.drawLine(3, fillMinY, 3, fillMaxY); + g.setColor(leftToRight ? MetalLookAndFeel.getPrimaryControlShadow() : MetalLookAndFeel.getWhite()); + g.drawLine(4, fillMinY, 4, fillMaxY); + } + } + } else { + g.setColor(MetalLookAndFeel.getControlShadow()); + + if (middleOfThumb > 0) { + if (drawInverted && filledSlider) { + g.fillRect(0, 0, w - 1, middleOfThumb - 1); + } else { + g.drawRect(0, 0, w - 1, middleOfThumb - 1); + } + } + + if (middleOfThumb < h) { + if (!drawInverted && filledSlider) { + g.fillRect(0, middleOfThumb, w - 1, h - middleOfThumb - 1); + } else { + g.drawRect(0, middleOfThumb, w - 1, h - middleOfThumb - 1); + } } - } - if (w == 6) { - g.setColor(chooseColor(!leftToRight, - MetalLookAndFeel.getWhite(), - MetalLookAndFeel.getPrimaryControlShadow())); - g.drawLine(1, fillMinY, 1, fillMaxY); - g.setColor(chooseColor(!leftToRight, sliderAltTrackColor, - MetalLookAndFeel.getControlShadow())); - g.drawLine(2, fillMinY, 2, fillMaxY); - g.setColor(chooseColor(!leftToRight, - MetalLookAndFeel.getControlShadow(), - sliderAltTrackColor)); - g.drawLine(3, fillMinY, 3, fillMaxY); - g.setColor(chooseColor(!leftToRight, - MetalLookAndFeel.getPrimaryControlShadow(), - MetalLookAndFeel.getWhite())); - g.drawLine(4, fillMinY, 4, fillMaxY); } } diff --git a/src/share/classes/javax/swing/plaf/metal/MetalToolBarUI.java b/src/share/classes/javax/swing/plaf/metal/MetalToolBarUI.java index eed7d630351623cfba47eabbd2476802029cc234..24e4e54f394be173c7abb091c645803f9c7f0fc2 100644 --- a/src/share/classes/javax/swing/plaf/metal/MetalToolBarUI.java +++ b/src/share/classes/javax/swing/plaf/metal/MetalToolBarUI.java @@ -61,7 +61,7 @@ public class MetalToolBarUI extends BasicToolBarUI * instances of JToolBars and JMenuBars and is used to find * JToolBars/JMenuBars that border each other. */ - private static java.util.List components = new ArrayList(); + private static List> components = new ArrayList>(); /** * This protected field is implemenation specific. Do not access directly @@ -95,7 +95,7 @@ public class MetalToolBarUI extends BasicToolBarUI // typed to throw an NPE. throw new NullPointerException("JComponent must be non-null"); } - components.add(new WeakReference(c)); + components.add(new WeakReference(c)); } /** @@ -105,8 +105,7 @@ public class MetalToolBarUI extends BasicToolBarUI for (int counter = components.size() - 1; counter >= 0; counter--) { // Search for the component, removing any flushed references // along the way. - WeakReference ref = (WeakReference)components.get(counter); - Object target = ((WeakReference)components.get(counter)).get(); + JComponent target = components.get(counter).get(); if (target == c || target == null) { components.remove(counter); diff --git a/src/share/classes/javax/swing/plaf/synth/DefaultMenuLayout.java b/src/share/classes/javax/swing/plaf/synth/DefaultMenuLayout.java index 678452328d90a3ace5c0c079dc55973db70aa806..1757a2e661ab44e3b2666f1dcddfd45b0827e92e 100644 --- a/src/share/classes/javax/swing/plaf/synth/DefaultMenuLayout.java +++ b/src/share/classes/javax/swing/plaf/synth/DefaultMenuLayout.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 @@ -47,19 +47,22 @@ class DefaultMenuLayout extends BoxLayout implements UIResource { super(target, axis); } - public void invalidateLayout(Container target) { + public Dimension preferredLayoutSize(Container target) { if (target instanceof JPopupMenu) { - SynthPopupMenuUI popupUI = (SynthPopupMenuUI)((JPopupMenu)target). - getUI(); - popupUI.resetAlignmentHints(); + JPopupMenu popupMenu = (JPopupMenu) target; + + popupMenu.putClientProperty( + SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null); + sun.swing.MenuItemLayoutHelper.clearUsedClientProperties(popupMenu); + + if (popupMenu.getComponentCount() == 0) { + return new Dimension(0, 0); + } } + + // Make BoxLayout recalculate cached preferred sizes super.invalidateLayout(target); - } - public Dimension preferredLayoutSize(Container target) { - if (target instanceof JPopupMenu && target.getComponentCount() == 0) { - return new Dimension(0, 0); - } return super.preferredLayoutSize(target); } } diff --git a/src/share/classes/javax/swing/plaf/synth/DefaultSynthStyleFactory.java b/src/share/classes/javax/swing/plaf/synth/DefaultSynthStyleFactory.java index 93512afb46dbdd83683d87b72eb0dcc94b9534fa..bbcbbad8168d993fa2bc5ea4c10a285ab12145ed 100644 --- a/src/share/classes/javax/swing/plaf/synth/DefaultSynthStyleFactory.java +++ b/src/share/classes/javax/swing/plaf/synth/DefaultSynthStyleFactory.java @@ -63,7 +63,7 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { /** * Maps from a List (BakedArrayList to be precise) to the merged style. */ - private Map _resolvedStyles; + private Map _resolvedStyles; /** * Used if there are no styles matching a widget. @@ -74,7 +74,7 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { DefaultSynthStyleFactory() { _tmpList = new BakedArrayList(5); _styles = new ArrayList(); - _resolvedStyles = new HashMap(); + _resolvedStyles = new HashMap(); } public synchronized void addStyle(DefaultSynthStyle style, @@ -138,7 +138,7 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { * Fetches any styles that match the passed into arguments into * matches. */ - private void getMatchingStyles(java.util.List matches, JComponent c, + private void getMatchingStyles(List matches, JComponent c, Region id) { String idName = id.getLowerCaseName(); String cName = c.getName(); @@ -166,7 +166,7 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { /** * Caches the specified style. */ - private void cacheStyle(java.util.List styles, SynthStyle style) { + private void cacheStyle(List styles, SynthStyle style) { BakedArrayList cachedStyles = new BakedArrayList(styles); _resolvedStyles.put(cachedStyles, style); @@ -175,11 +175,11 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { /** * Returns the cached style from the passed in arguments. */ - private SynthStyle getCachedStyle(java.util.List styles) { + private SynthStyle getCachedStyle(List styles) { if (styles.size() == 0) { return null; } - return (SynthStyle)_resolvedStyles.get(styles); + return _resolvedStyles.get(styles); } /** @@ -187,7 +187,7 @@ class DefaultSynthStyleFactory extends SynthStyleFactory { * is reverse sorted, that is the most recently added style found to * match will be first. */ - private SynthStyle mergeStyles(java.util.List styles) { + private SynthStyle mergeStyles(List styles) { int size = styles.size(); if (size == 0) { diff --git a/src/share/classes/javax/swing/plaf/synth/ImagePainter.java b/src/share/classes/javax/swing/plaf/synth/ImagePainter.java index b9a02a6193108dfb4d006fb1389575459d026881..943e91dbde78b4707cd12df903a4168ab90371e4 100644 --- a/src/share/classes/javax/swing/plaf/synth/ImagePainter.java +++ b/src/share/classes/javax/swing/plaf/synth/ImagePainter.java @@ -66,7 +66,7 @@ class ImagePainter extends SynthPainter { Paint9Painter painter; if (cacheRef == null || (painter = cacheRef.get()) == null) { painter = new Paint9Painter(30); - cacheRef = new WeakReference(painter); + cacheRef = new WeakReference(painter); AppContext.getAppContext().put(CACHE_KEY, cacheRef); } return painter; diff --git a/src/share/classes/javax/swing/plaf/synth/Region.java b/src/share/classes/javax/swing/plaf/synth/Region.java index ef9342646683809c6e0e8e6beb7bb21915ee07d3..bd144bf682893d13681210bac7249490f04dcd75 100644 --- a/src/share/classes/javax/swing/plaf/synth/Region.java +++ b/src/share/classes/javax/swing/plaf/synth/Region.java @@ -67,8 +67,8 @@ import java.util.*; * @author Scott Violet */ public class Region { - private static final Map uiToRegionMap = new HashMap(); - private static final Map lowerCaseNameMap = new HashMap(); + private static final Map uiToRegionMap = new HashMap(); + private static final Map lowerCaseNameMap = new HashMap(); /** * ArrowButton's are special types of buttons that also render a @@ -451,15 +451,11 @@ public class Region { static Region getRegion(JComponent c) { - return (Region)uiToRegionMap.get(c.getUIClassID()); + return uiToRegionMap.get(c.getUIClassID()); } static void registerUIs(UIDefaults table) { - Iterator uis = uiToRegionMap.keySet().iterator(); - - while (uis.hasNext()) { - Object key = uis.next(); - + for (String key : uiToRegionMap.keySet()) { table.put(key, "javax.swing.plaf.synth.SynthLookAndFeel"); } } @@ -521,7 +517,7 @@ public class Region { */ String getLowerCaseName() { synchronized(lowerCaseNameMap) { - String lowerCaseName = (String)lowerCaseNameMap.get(this); + String lowerCaseName = lowerCaseNameMap.get(this); if (lowerCaseName == null) { lowerCaseName = getName().toLowerCase(); lowerCaseNameMap.put(this, lowerCaseName); diff --git a/src/share/classes/javax/swing/plaf/synth/SynthButtonUI.java b/src/share/classes/javax/swing/plaf/synth/SynthButtonUI.java index 78dd60bd3e337738002eeca87fbc78f25e3ea07d..e0f057e903752efa6620eb59bd7f36c2f925d23d 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthButtonUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthButtonUI.java @@ -262,7 +262,7 @@ class SynthButtonUI extends BasicButtonUI implements * Returns the default icon. This should NOT callback * to the JComponent. * - * @param b AbstractButton the iocn is associated with + * @param b AbstractButton the icon is associated with * @return default icon */ @@ -445,9 +445,7 @@ class SynthButtonUI extends BasicButtonUI implements * Returns the Icon used in calculating the pref/min/max size. */ protected Icon getSizingIcon(AbstractButton b) { - // NOTE: this is slightly different than BasicButtonUI, where it - // would just use getIcon, but this should be ok. - Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); + Icon icon = getEnabledIcon(b, b.getIcon()); if (icon == null) { icon = getDefaultIcon(b); } diff --git a/src/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java b/src/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java index 926c31e56e22f9160de6d91bb59f2deb34c56a0f..b4b0b9db4e14722578cf8779beaf3bd3497dbf8d 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java @@ -336,7 +336,7 @@ class SynthComboBoxUI extends BasicComboBoxUI implements return oldValue; } else { // Must take the value from the editor and get the value and cast it to the new type. - Class cls = oldValue.getClass(); + Class cls = oldValue.getClass(); try { Method method = cls.getMethod("valueOf", new Class[]{String.class}); newValue = method.invoke(oldValue, new Object[] { editor.getText()}); diff --git a/src/share/classes/javax/swing/plaf/synth/SynthContext.java b/src/share/classes/javax/swing/plaf/synth/SynthContext.java index 3b3b0b8e07273a8d962f7976d944e293ea6e5596..f63c3abcfddf95a70726f02bc7854a4e6df88b94 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthContext.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthContext.java @@ -39,7 +39,7 @@ import java.util.*; * @author Scott Violet */ public class SynthContext { - private static final Map contextMap; + private static final Map> contextMap; private JComponent component; private Region region; @@ -48,7 +48,7 @@ public class SynthContext { static { - contextMap = new HashMap(); + contextMap = new HashMap>(); } @@ -58,13 +58,13 @@ public class SynthContext { SynthContext context = null; synchronized(contextMap) { - java.util.List instances = (java.util.List)contextMap.get(type); + List instances = contextMap.get(type); if (instances != null) { int size = instances.size(); if (size > 0) { - context = (SynthContext)instances.remove(size - 1); + context = instances.remove(size - 1); } } } @@ -81,11 +81,10 @@ public class SynthContext { static void releaseContext(SynthContext context) { synchronized(contextMap) { - java.util.List instances = (java.util.List)contextMap.get( - context.getClass()); + List instances = contextMap.get(context.getClass()); if (instances == null) { - instances = new ArrayList(5); + instances = new ArrayList(5); contextMap.put(context.getClass(), instances); } instances.add(context); diff --git a/src/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java b/src/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java index b63ab2a60cd2e7a9070d89b43502929fb0b2a54b..f99741a013884469606f441a8be39e2bd1477b56 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthEditorPaneUI.java @@ -45,8 +45,8 @@ class SynthEditorPaneUI extends BasicEditorPaneUI implements SynthUI { * I would prefer to use UIResource instad of this. * Unfortunately Boolean is a final class */ - private Boolean localTrue = new Boolean(true); - private Boolean localFalse = new Boolean(false); + private Boolean localTrue = Boolean.TRUE; + private Boolean localFalse = Boolean.FALSE; /** * Creates a UI for the JTextPane. @@ -69,7 +69,7 @@ class SynthEditorPaneUI extends BasicEditorPaneUI implements SynthUI { c.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, localTrue); } - updateStyle((JTextComponent)getComponent()); + updateStyle(getComponent()); } protected void uninstallDefaults() { diff --git a/src/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java b/src/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java index 7d8bade8675b244e798292a8b0e4e5fda3e7ea9f..a8ec7728a6421134687caf0a109b19da3ce7e714 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.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 @@ -25,6 +25,8 @@ package javax.swing.plaf.synth; import sun.swing.SwingUtilities2; +import sun.swing.MenuItemLayoutHelper; + import java.awt.*; import javax.swing.*; import javax.swing.plaf.basic.BasicHTML; @@ -411,12 +413,204 @@ public class SynthGraphicsUtils { } + /** + * A quick note about how preferred sizes are calculated... Generally + * speaking, SynthPopupMenuUI will run through the list of its children + * (from top to bottom) and ask each for its preferred size. Each menu + * item will add up the max width of each element (icons, text, + * accelerator spacing, accelerator text or arrow icon) encountered thus + * far, so by the time all menu items have been calculated, we will + * know the maximum (preferred) menu item size for that popup menu. + * Later when it comes time to paint each menu item, we can use those + * same accumulated max element sizes in order to layout the item. + */ + static Dimension getPreferredMenuItemSize(SynthContext context, + SynthContext accContext, JComponent c, + Icon checkIcon, Icon arrowIcon, int defaultTextIconGap, + String acceleratorDelimiter, boolean useCheckAndArrow, + String propertyPrefix) { + + JMenuItem mi = (JMenuItem) c; + SynthMenuItemLayoutHelper lh = new SynthMenuItemLayoutHelper( + context, accContext, mi, checkIcon, arrowIcon, + MenuItemLayoutHelper.createMaxRect(), defaultTextIconGap, + acceleratorDelimiter, SynthLookAndFeel.isLeftToRight(mi), + useCheckAndArrow, propertyPrefix); + + Dimension result = new Dimension(); + + // Calculate the result width + int gap = lh.getGap(); + result.width = 0; + MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(), gap, result); + MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), gap, result); + MenuItemLayoutHelper.addWidth(lh.getMaxAccOrArrowWidth(), 5 * gap, result); + // The last gap is unnecessary + result.width -= gap; + + // Calculate the result height + result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(), + lh.getLabelSize().getHeight(), lh.getAccSize().getHeight(), + lh.getArrowSize().getHeight()); + + // Take into account menu item insets + Insets insets = lh.getMenuItem().getInsets(); + if (insets != null) { + result.width += insets.left + insets.right; + result.height += insets.top + insets.bottom; + } + + // if the width is even, bump it up one. This is critical + // for the focus dash lhne to draw properly + if (result.width % 2 == 0) { + result.width++; + } + + // if the height is even, bump it up one. This is critical + // for the text to center properly + if (result.height % 2 == 0) { + result.height++; + } + + return result; + } + + static void applyInsets(Rectangle rect, Insets insets) { + if (insets != null) { + rect.x += insets.left; + rect.y += insets.top; + rect.width -= (insets.right + rect.x); + rect.height -= (insets.bottom + rect.y); + } + } + + static void paint(SynthContext context, SynthContext accContext, Graphics g, + Icon checkIcon, Icon arrowIcon, String acceleratorDelimiter, + int defaultTextIconGap, String propertyPrefix) { + JMenuItem mi = (JMenuItem) context.getComponent(); + SynthStyle style = context.getStyle(); + g.setFont(style.getFont(context)); + + Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); + applyInsets(viewRect, mi.getInsets()); + + SynthMenuItemLayoutHelper lh = new SynthMenuItemLayoutHelper( + context, accContext, mi, checkIcon, + arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter, + SynthLookAndFeel.isLeftToRight(mi), + MenuItemLayoutHelper.useCheckAndArrow(mi), propertyPrefix); + MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); + + paintMenuItem(g, lh, lr); + } + + static void paintMenuItem(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + // Save original graphics font and color + Font holdf = g.getFont(); + Color holdc = g.getColor(); + + paintBackground(g, lh); + paintCheckIcon(g, lh, lr); + paintIcon(g, lh, lr); + paintText(g, lh, lr); + paintAccText(g, lh, lr); + paintArrowIcon(g, lh, lr); + + // Restore original graphics font and color + g.setColor(holdc); + g.setFont(holdf); + } + + static void paintBackground(Graphics g, SynthMenuItemLayoutHelper lh) { + paintBackground(lh.getContext(), g, lh.getMenuItem()); + } + + static void paintBackground(SynthContext context, Graphics g, JComponent c) { + context.getPainter().paintMenuItemBackground(context, g, 0, 0, + c.getWidth(), c.getHeight()); + } + + static void paintIcon(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (lh.getIcon() != null) { + Icon icon; + JMenuItem mi = lh.getMenuItem(); + ButtonModel model = mi.getModel(); + if (!model.isEnabled()) { + icon = mi.getDisabledIcon(); + } else if (model.isPressed() && model.isArmed()) { + icon = mi.getPressedIcon(); + if (icon == null) { + // Use default icon + icon = mi.getIcon(); + } + } else { + icon = mi.getIcon(); + } + + if (icon != null) { + Rectangle iconRect = lr.getIconRect(); + SynthIcon.paintIcon(icon, lh.getContext(), g, iconRect.x, + iconRect.y, iconRect.width, iconRect.height); + } + } + } + + static void paintCheckIcon(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (lh.getCheckIcon() != null) { + Rectangle checkRect = lr.getCheckRect(); + SynthIcon.paintIcon(lh.getCheckIcon(), lh.getContext(), g, + checkRect.x, checkRect.y, checkRect.width, checkRect.height); + } + } + + static void paintAccText(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + String accText = lh.getAccText(); + if (accText != null && !accText.equals("")) { + g.setColor(lh.getAccStyle().getColor(lh.getAccContext(), + ColorType.TEXT_FOREGROUND)); + g.setFont(lh.getAccStyle().getFont(lh.getAccContext())); + lh.getAccGraphicsUtils().paintText(lh.getAccContext(), g, accText, + lr.getAccRect().x, lr.getAccRect().y, -1); + } + } + + static void paintText(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getText().equals("")) { + if (lh.getHtmlView() != null) { + // Text is HTML + lh.getHtmlView().paint(g, lr.getTextRect()); + } else { + // Text isn't HTML + g.setColor(lh.getStyle().getColor( + lh.getContext(), ColorType.TEXT_FOREGROUND)); + g.setFont(lh.getStyle().getFont(lh.getContext())); + lh.getGraphicsUtils().paintText(lh.getContext(), g, lh.getText(), + lr.getTextRect().x, lr.getTextRect().y, + lh.getMenuItem().getDisplayedMnemonicIndex()); + } + } + } + + static void paintArrowIcon(Graphics g, SynthMenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (lh.getArrowIcon() != null) { + Rectangle arrowRect = lr.getArrowRect(); + SynthIcon.paintIcon(lh.getArrowIcon(), lh.getContext(), g, + arrowRect.x, arrowRect.y, arrowRect.width, arrowRect.height); + } + } + /** * Wraps a SynthIcon around the Icon interface, forwarding calls to * the SynthIcon with a given SynthContext. */ private static class SynthIconWrapper implements Icon { - private static final java.util.List CACHE = new java.util.ArrayList(1); + private static final java.util.List CACHE = new java.util.ArrayList(1); private SynthIcon synthIcon; private SynthContext context; @@ -425,8 +619,7 @@ public class SynthGraphicsUtils { synchronized(CACHE) { int size = CACHE.size(); if (size > 0) { - SynthIconWrapper wrapper = (SynthIconWrapper)CACHE.remove( - size - 1); + SynthIconWrapper wrapper = CACHE.remove(size - 1); wrapper.reset(icon, context); return wrapper; } diff --git a/src/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java b/src/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java index 19d218871bc0bee9e7ce8ff84ca252aec1d9d6c8..f1c888952a48bc6e8d81655d049e551d260ccb37 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthInternalFrameTitlePane.java @@ -197,25 +197,25 @@ class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane protected void addSystemMenuItems(JPopupMenu menu) { // PENDING: this should all be localizable! - JMenuItem mi = (JMenuItem)menu.add(restoreAction); + JMenuItem mi = menu.add(restoreAction); mi.setMnemonic('R'); - mi = (JMenuItem)menu.add(moveAction); + mi = menu.add(moveAction); mi.setMnemonic('M'); - mi = (JMenuItem)menu.add(sizeAction); + mi = menu.add(sizeAction); mi.setMnemonic('S'); - mi = (JMenuItem)menu.add(iconifyAction); + mi = menu.add(iconifyAction); mi.setMnemonic('n'); - mi = (JMenuItem)menu.add(maximizeAction); + mi = menu.add(maximizeAction); mi.setMnemonic('x'); menu.add(new JSeparator()); - mi = (JMenuItem)menu.add(closeAction); + mi = menu.add(closeAction); mi.setMnemonic('C'); } protected void showSystemMenu() { Insets insets = frame.getInsets(); if (!frame.isIcon()) { - systemPopupMenu.show(frame, insets.left, getY() + getHeight()); + systemPopupMenu.show(frame, menuButton.getX(), getY() + getHeight()); } else { systemPopupMenu.show(menuButton, getX() - insets.left - insets.right, diff --git a/src/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java b/src/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java index af3d687715cae4fe0e711ccfa93b455c4b0656ca..c9f6f7687e3768145ea10bbfb3337ca2f11ddd3e 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -107,7 +107,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { * Map of defaults table entries. This is populated via the load * method. */ - private Map defaultsMap; + private Map defaultsMap; private Handler _handler; @@ -308,8 +308,8 @@ public class SynthLookAndFeel extends BasicLookAndFeel { children = ((Container)c).getComponents(); } if (children != null) { - for(int i = 0; i < children.length; i++) { - updateStyles(children[i]); + for (Component child : children) { + updateStyles(child); } } } @@ -581,7 +581,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { } if (defaultsMap == null) { - defaultsMap = new HashMap(); + defaultsMap = new HashMap(); } new SynthParser().parse(input, (DefaultSynthStyleFactory) factory, @@ -611,7 +611,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { } if (defaultsMap == null) { - defaultsMap = new HashMap(); + defaultsMap = new HashMap(); } InputStream input = url.openStream(); @@ -771,7 +771,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { */ private static Object getAATextInfo() { String language = Locale.getDefault().getLanguage(); - String desktop = (String) + String desktop = AccessController.doPrivileged(new GetPropertyAction("sun.desktop")); boolean isCjkLocale = (Locale.CHINESE.getLanguage().equals(language) || @@ -786,7 +786,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { return aaTextInfo; } - private static ReferenceQueue queue = new ReferenceQueue(); + private static ReferenceQueue queue = new ReferenceQueue(); private static void flushUnreferenced() { AATextListener aatl; @@ -796,7 +796,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { } private static class AATextListener - extends WeakReference implements PropertyChangeListener { + extends WeakReference implements PropertyChangeListener { private String key = SunToolkit.DESKTOPFONTHINTS; AATextListener(LookAndFeel laf) { @@ -812,7 +812,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { return; } - LookAndFeel laf = (LookAndFeel) get(); + LookAndFeel laf = get(); if (laf == null || laf != UIManager.getLookAndFeel()) { dispose(); return; @@ -835,8 +835,8 @@ public class SynthLookAndFeel extends BasicLookAndFeel { private static void updateWindowUI(Window window) { updateStyles(window); Window ownedWins[] = window.getOwnedWindows(); - for (int i = 0; i < ownedWins.length; i++) { - updateWindowUI(ownedWins[i]); + for (Window w : ownedWins) { + updateWindowUI(w); } } @@ -845,8 +845,8 @@ public class SynthLookAndFeel extends BasicLookAndFeel { */ private static void updateAllUIs() { Frame appFrames[] = Frame.getFrames(); - for (int i = 0; i < appFrames.length; i++) { - updateWindowUI(appFrames[i]); + for (Frame frame : appFrames) { + updateWindowUI(frame); } } @@ -909,7 +909,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel { // register it on the new one. KeyboardFocusManager manager = (KeyboardFocusManager)evt.getSource(); - if (((Boolean)newValue).equals(Boolean.FALSE)) { + if (newValue.equals(Boolean.FALSE)) { manager.removePropertyChangeListener(_handler); } else { diff --git a/src/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java b/src/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..4ca139a709d190f13fd0e04440bf364e2ebec8a1 --- /dev/null +++ b/src/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java @@ -0,0 +1,308 @@ +/* + * 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.swing.plaf.synth; + +import sun.swing.StringUIClientPropertyKey; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.plaf.synth.SynthIcon; + +import javax.swing.*; +import javax.swing.text.View; +import java.awt.*; + +/** + * Calculates preferred size and layouts synth menu items. + * + * All JMenuItems (and JMenus) include enough space for the insets + * plus one or more elements. When we say "label" below, we mean + * "icon and/or text." + * + * Cases to consider for SynthMenuItemUI (visualized here in a + * LTR orientation; the RTL case would be reversed): + * label + * check icon + label + * check icon + label + accelerator + * label + accelerator + * + * Cases to consider for SynthMenuUI (again visualized here in a + * LTR orientation): + * label + arrow + * + * Note that in the above scenarios, accelerator and arrow icon are + * mutually exclusive. This means that if a popup menu contains a mix + * of JMenus and JMenuItems, we only need to allow enough space for + * max(maxAccelerator, maxArrow), and both accelerators and arrow icons + * can occupy the same "column" of space in the menu. + */ +class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { + + public static final StringUIClientPropertyKey MAX_ACC_OR_ARROW_WIDTH = + new StringUIClientPropertyKey("maxAccOrArrowWidth"); + + public static final ColumnAlignment LTR_ALIGNMENT_1 = + new ColumnAlignment( + SwingConstants.LEFT, + SwingConstants.LEFT, + SwingConstants.LEFT, + SwingConstants.RIGHT, + SwingConstants.RIGHT + ); + public static final ColumnAlignment LTR_ALIGNMENT_2 = + new ColumnAlignment( + SwingConstants.LEFT, + SwingConstants.LEFT, + SwingConstants.LEFT, + SwingConstants.LEFT, + SwingConstants.RIGHT + ); + public static final ColumnAlignment RTL_ALIGNMENT_1 = + new ColumnAlignment( + SwingConstants.RIGHT, + SwingConstants.RIGHT, + SwingConstants.RIGHT, + SwingConstants.LEFT, + SwingConstants.LEFT + ); + public static final ColumnAlignment RTL_ALIGNMENT_2 = + new ColumnAlignment( + SwingConstants.RIGHT, + SwingConstants.RIGHT, + SwingConstants.RIGHT, + SwingConstants.RIGHT, + SwingConstants.LEFT + ); + + private SynthContext context; + private SynthContext accContext; + private SynthStyle style; + private SynthStyle accStyle; + private SynthGraphicsUtils gu; + private SynthGraphicsUtils accGu; + private boolean alignAcceleratorText; + private int maxAccOrArrowWidth; + + public SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, + JMenuItem mi, Icon checkIcon, Icon arrowIcon, + Rectangle viewRect, int gap, String accDelimiter, + boolean isLeftToRight, boolean useCheckAndArrow, + String propertyPrefix) { + this.context = context; + this.accContext = accContext; + this.style = context.getStyle(); + this.accStyle = accContext.getStyle(); + this.gu = style.getGraphicsUtils(context); + this.accGu = accStyle.getGraphicsUtils(accContext); + this.alignAcceleratorText = getAlignAcceleratorText(propertyPrefix); + reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, + isLeftToRight, style.getFont(context), accStyle.getFont(accContext), + useCheckAndArrow, propertyPrefix); + setLeadingGap(0); + } + + private boolean getAlignAcceleratorText(String propertyPrefix) { + return style.getBoolean(context, + propertyPrefix + ".alignAcceleratorText", true); + } + + protected void calcWidthsAndHeights() { + // iconRect + if (getIcon() != null) { + getIconSize().setWidth(SynthIcon.getIconWidth(getIcon(), context)); + getIconSize().setHeight(SynthIcon.getIconHeight(getIcon(), context)); + } + + // accRect + if (!getAccText().equals("")) { + getAccSize().setWidth(accGu.computeStringWidth(getAccContext(), + getAccFontMetrics().getFont(), getAccFontMetrics(), + getAccText())); + getAccSize().setHeight(getAccFontMetrics().getHeight()); + } + + // textRect + if (getText() == null) { + setText(""); + } else if (!getText().equals("")) { + if (getHtmlView() != null) { + // Text is HTML + getTextSize().setWidth( + (int) getHtmlView().getPreferredSpan(View.X_AXIS)); + getTextSize().setHeight( + (int) getHtmlView().getPreferredSpan(View.Y_AXIS)); + } else { + // Text isn't HTML + getTextSize().setWidth(gu.computeStringWidth(context, + getFontMetrics().getFont(), getFontMetrics(), + getText())); + getTextSize().setHeight(getFontMetrics().getHeight()); + } + } + + if (useCheckAndArrow()) { + // checkIcon + if (getCheckIcon() != null) { + getCheckSize().setWidth( + SynthIcon.getIconWidth(getCheckIcon(), context)); + getCheckSize().setHeight( + SynthIcon.getIconHeight(getCheckIcon(), context)); + } + // arrowRect + if (getArrowIcon() != null) { + getArrowSize().setWidth( + SynthIcon.getIconWidth(getArrowIcon(), context)); + getArrowSize().setHeight( + SynthIcon.getIconHeight(getArrowIcon(), context)); + } + } + + // labelRect + if (isColumnLayout()) { + getLabelSize().setWidth(getIconSize().getWidth() + + getTextSize().getWidth() + getGap()); + getLabelSize().setHeight(MenuItemLayoutHelper.max( + getCheckSize().getHeight(), + getIconSize().getHeight(), + getTextSize().getHeight(), + getAccSize().getHeight(), + getArrowSize().getHeight())); + } else { + Rectangle textRect = new Rectangle(); + Rectangle iconRect = new Rectangle(); + gu.layoutText(context, getFontMetrics(), getText(), getIcon(), + getHorizontalAlignment(), getVerticalAlignment(), + getHorizontalTextPosition(), getVerticalTextPosition(), + getViewRect(), iconRect, textRect, getGap()); + textRect.width += getLeftTextExtraWidth() + getRightTextExtraWidth(); + Rectangle labelRect = iconRect.union(textRect); + getLabelSize().setHeight(labelRect.height); + getLabelSize().setWidth(labelRect.width); + } + } + + protected void calcMaxWidths() { + calcMaxWidth(getCheckSize(), MAX_CHECK_WIDTH); + maxAccOrArrowWidth = + calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getArrowSize().getWidth()); + maxAccOrArrowWidth = + calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getAccSize().getWidth()); + + if (isColumnLayout()) { + calcMaxWidth(getIconSize(), MAX_ICON_WIDTH); + calcMaxWidth(getTextSize(), MAX_TEXT_WIDTH); + int curGap = getGap(); + if ((getIconSize().getMaxWidth() == 0) + || (getTextSize().getMaxWidth() == 0)) { + curGap = 0; + } + getLabelSize().setMaxWidth( + calcMaxValue(MAX_LABEL_WIDTH, getIconSize().getMaxWidth() + + getTextSize().getMaxWidth() + curGap)); + } else { + // We shouldn't use current icon and text widths + // in maximal widths calculation for complex layout. + getIconSize().setMaxWidth(getParentIntProperty( + MAX_ICON_WIDTH)); + calcMaxWidth(getLabelSize(), MAX_LABEL_WIDTH); + // If maxLabelWidth is wider + // than the widest icon + the widest text + gap, + // we should update the maximal text witdh + int candidateTextWidth = getLabelSize().getMaxWidth() - + getIconSize().getMaxWidth(); + if (getIconSize().getMaxWidth() > 0) { + candidateTextWidth -= getGap(); + } + getTextSize().setMaxWidth(calcMaxValue( + MAX_TEXT_WIDTH, candidateTextWidth)); + } + } + + public SynthContext getContext() { + return context; + } + + public SynthContext getAccContext() { + return accContext; + } + + public SynthStyle getStyle() { + return style; + } + + public SynthStyle getAccStyle() { + return accStyle; + } + + public SynthGraphicsUtils getGraphicsUtils() { + return gu; + } + + public SynthGraphicsUtils getAccGraphicsUtils() { + return accGu; + } + + public boolean alignAcceleratorText() { + return alignAcceleratorText; + } + + public int getMaxAccOrArrowWidth() { + return maxAccOrArrowWidth; + } + + protected void prepareForLayout(LayoutResult lr) { + lr.getCheckRect().width = getCheckSize().getMaxWidth(); + // An item can have an arrow or a check icon at once + if (useCheckAndArrow() && (!"".equals(getAccText()))) { + lr.getAccRect().width = maxAccOrArrowWidth; + } else { + lr.getArrowRect().width = maxAccOrArrowWidth; + } + } + + public ColumnAlignment getLTRColumnAlignment() { + if (alignAcceleratorText()) { + return LTR_ALIGNMENT_2; + } else { + return LTR_ALIGNMENT_1; + } + } + + public ColumnAlignment getRTLColumnAlignment() { + if (alignAcceleratorText()) { + return RTL_ALIGNMENT_2; + } else { + return RTL_ALIGNMENT_1; + } + } + + protected void layoutIconAndTextInLabelRect(LayoutResult lr) { + lr.setTextRect(new Rectangle()); + lr.setIconRect(new Rectangle()); + gu.layoutText(context, getFontMetrics(), getText(), getIcon(), + getHorizontalAlignment(), getVerticalAlignment(), + getHorizontalTextPosition(), getVerticalTextPosition(), + lr.getLabelRect(), lr.getIconRect(), lr.getTextRect(), getGap()); + } +} diff --git a/src/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java b/src/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java index a921f9d4ba43b4d144be2bd728eaf3d36301132f..3bcc044a12e651a996cd3cf05a202c9eb759eca7 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthMenuItemUI.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 @@ -37,7 +37,7 @@ import javax.swing.plaf.*; import javax.swing.plaf.basic.*; import javax.swing.text.View; import sun.swing.plaf.synth.*; -import sun.swing.SwingUtilities2; +import sun.swing.MenuItemLayoutHelper; /** @@ -59,542 +59,16 @@ class SynthMenuItemUI extends BasicMenuItemUI implements return new SynthMenuItemUI(); } - // - // The next handful of static methods are used by both SynthMenuUI - // and SynthMenuItemUI. This is necessitated by SynthMenuUI not - // extending SynthMenuItemUI. - // - - /* - * All JMenuItems (and JMenus) include enough space for the insets - * plus one or more elements. When we say "icon(s)" below, we mean - * "check/radio indicator and/or user icon." If both are defined for - * a given menu item, then in a LTR orientation the check/radio indicator - * is on the left side followed by the user icon to the right; it is - * just the opposite in a RTL orientation. - * - * Cases to consider for SynthMenuItemUI (visualized here in a - * LTR orientation; the RTL case would be reversed): - * text - * icon(s) + text - * icon(s) + text + accelerator - * text + accelerator - * - * Cases to consider for SynthMenuUI (again visualized here in a - * LTR orientation): - * text + arrow - * (user)icon + text + arrow - * - * Note that in the above scenarios, accelerator and arrow icon are - * mutually exclusive. This means that if a popup menu contains a mix - * of JMenus and JMenuItems, we only need to allow enough space for - * max(maxAccelerator, maxArrow), and both accelerators and arrow icons - * can occupy the same "column" of space in the menu. - * - * A quick note about how preferred sizes are calculated... Generally - * speaking, SynthPopupMenuUI will run through the list of its children - * (from top to bottom) and ask each for its preferred size. Each menu - * item will add up the max width of each element (icons, text, - * accelerator spacing, accelerator text or arrow icon) encountered thus - * far, so by the time all menu items have been calculated, we will - * know the maximum (preferred) menu item size for that popup menu. - * Later when it comes time to paint each menu item, we can use those - * same accumulated max element sizes in order to layout the item. - */ - static Dimension getPreferredMenuItemSize(SynthContext context, - SynthContext accContext, JComponent c, - Icon checkIcon, Icon arrowIcon, int defaultTextIconGap, - String acceleratorDelimiter) { - JMenuItem b = (JMenuItem) c; - Icon icon = (Icon) b.getIcon(); - String text = b.getText(); - KeyStroke accelerator = b.getAccelerator(); - String acceleratorText = ""; - - if (accelerator != null) { - int modifiers = accelerator.getModifiers(); - if (modifiers > 0) { - acceleratorText = KeyEvent.getKeyModifiersText(modifiers); - acceleratorText += acceleratorDelimiter; - } - int keyCode = accelerator.getKeyCode(); - if (keyCode != 0) { - acceleratorText += KeyEvent.getKeyText(keyCode); - } else { - acceleratorText += accelerator.getKeyChar(); - } - } - - Font font = context.getStyle().getFont(context); - FontMetrics fm = b.getFontMetrics(font); - FontMetrics fmAccel = b.getFontMetrics(accContext.getStyle(). - getFont(accContext)); - - resetRects(); - - layoutMenuItem( - context, fm, accContext, text, fmAccel, acceleratorText, - icon, checkIcon, arrowIcon, b.getVerticalAlignment(), - b.getHorizontalAlignment(), b.getVerticalTextPosition(), - b.getHorizontalTextPosition(), viewRect, iconRect, textRect, - acceleratorRect, checkIconRect, arrowIconRect, - text == null ? 0 : defaultTextIconGap, defaultTextIconGap); - - r.setBounds(textRect); - - int totalIconWidth = 0; - int maxIconHeight = 0; - if (icon != null) { - // Add in the user icon - totalIconWidth += iconRect.width; - if (textRect.width > 0) { - // Allow for some room between the user icon and the text - totalIconWidth += defaultTextIconGap; - } - maxIconHeight = Math.max(iconRect.height, maxIconHeight); - } - if (checkIcon != null) { - // Add in the checkIcon - totalIconWidth += checkIconRect.width; - if (textRect.width > 0 || icon != null) { - // Allow for some room between the check/radio indicator - // and the text (or user icon, if both are specified) - totalIconWidth += defaultTextIconGap; - } - maxIconHeight = Math.max(checkIconRect.height, maxIconHeight); - } - - int arrowWidth = 0; - if (arrowIcon != null) { - // Add in the arrowIcon - arrowWidth += defaultTextIconGap; - arrowWidth += arrowIconRect.width; - maxIconHeight = Math.max(arrowIconRect.height, maxIconHeight); - } - - int accelSpacing = 0; - if (acceleratorRect.width > 0) { - // Allow for some room between the text and the accelerator - accelSpacing += 4*defaultTextIconGap; - } - - // Take text and all icons into account when determining height - r.height = Math.max(r.height, maxIconHeight); - - // To make the accelerator texts appear in a column, - // find the widest MenuItem text and the widest accelerator text. - - // Get the parent, which stores the information. - Container parent = b.getParent(); - - if (parent instanceof JPopupMenu) { - SynthPopupMenuUI popupUI = (SynthPopupMenuUI)SynthLookAndFeel. - getUIOfType(((JPopupMenu)parent).getUI(), - SynthPopupMenuUI.class); - - if (popupUI != null) { - // This gives us the widest MenuItem text encountered thus - // far in the parent JPopupMenu - r.width = popupUI.adjustTextWidth(r.width); - - // Add in the widest icon (includes both user and - // check/radio icons) encountered thus far - r.width += popupUI.adjustIconWidth(totalIconWidth); - - // Add in the widest text/accelerator spacing - // encountered thus far - r.width += popupUI.adjustAccelSpacingWidth(accelSpacing); - - // Add in the widest accelerator text (or arrow) - // encountered thus far (at least one of these values - // will always be zero, so we combine them here to - // avoid double counting) - int totalAccelOrArrow = acceleratorRect.width + arrowWidth; - r.width += popupUI.adjustAcceleratorWidth(totalAccelOrArrow); - } + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + // Remove values from the parent's Client Properties. + JComponent p = MenuItemLayoutHelper.getMenuItemParent((JMenuItem) c); + if (p != null) { + p.putClientProperty( + SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null); } - else if (parent != null && !(b instanceof JMenu && - ((JMenu)b).isTopLevelMenu())) { - r.width += - totalIconWidth + accelSpacing + - acceleratorRect.width + arrowWidth; - } - - Insets insets = b.getInsets(); - if(insets != null) { - r.width += insets.left + insets.right; - r.height += insets.top + insets.bottom; - } - - // if the width is even, bump it up one. This is critical - // for the focus dash line to draw properly - if(r.width%2 == 0) { - r.width++; - } - - // if the height is even, bump it up one. This is critical - // for the text to center properly - if(r.height%2 == 0) { - r.height++; - } - return r.getSize(); } - static void paint(SynthContext context, SynthContext accContext, - Graphics g, Icon checkIcon, Icon arrowIcon, - String acceleratorDelimiter, - int defaultTextIconGap) { - JComponent c = context.getComponent(); - JMenuItem b = (JMenuItem)c; - ButtonModel model = b.getModel(); - Insets i = b.getInsets(); - - resetRects(); - - viewRect.setBounds(0, 0, b.getWidth(), b.getHeight()); - - viewRect.x += i.left; - viewRect.y += i.top; - viewRect.width -= (i.right + viewRect.x); - viewRect.height -= (i.bottom + viewRect.y); - - SynthStyle style = context.getStyle(); - Font f = style.getFont(context); - g.setFont(f); - FontMetrics fm = SwingUtilities2.getFontMetrics(c, g, f); - FontMetrics accFM = SwingUtilities2.getFontMetrics(c, g, - accContext.getStyle(). - getFont(accContext)); - - // get Accelerator text - KeyStroke accelerator = b.getAccelerator(); - String acceleratorText = ""; - if (accelerator != null) { - int modifiers = accelerator.getModifiers(); - if (modifiers > 0) { - acceleratorText = KeyEvent.getKeyModifiersText(modifiers); - acceleratorText += acceleratorDelimiter; - } - - int keyCode = accelerator.getKeyCode(); - if (keyCode != 0) { - acceleratorText += KeyEvent.getKeyText(keyCode); - } else { - acceleratorText += accelerator.getKeyChar(); - } - } - - // Layout the text and icon - String text = layoutMenuItem(context, fm, accContext, - b.getText(), accFM, acceleratorText, b.getIcon(), - checkIcon, arrowIcon, - b.getVerticalAlignment(), b.getHorizontalAlignment(), - b.getVerticalTextPosition(), b.getHorizontalTextPosition(), - viewRect, iconRect, textRect, acceleratorRect, - checkIconRect, arrowIconRect, - b.getText() == null ? 0 : defaultTextIconGap, - defaultTextIconGap - ); - - // Paint the Check - if (checkIcon != null) { - SynthIcon.paintIcon(checkIcon, context, g, checkIconRect.x, - checkIconRect.y, checkIconRect.width, checkIconRect.height); - } - - // Paint the Icon - if(b.getIcon() != null) { - Icon icon; - if(!model.isEnabled()) { - icon = (Icon) b.getDisabledIcon(); - } else if(model.isPressed() && model.isArmed()) { - icon = (Icon) b.getPressedIcon(); - if(icon == null) { - // Use default icon - icon = (Icon) b.getIcon(); - } - } else { - icon = (Icon) b.getIcon(); - } - - if (icon!=null) { - SynthIcon.paintIcon(icon, context, g, iconRect.x, - iconRect.y, iconRect.width, iconRect.height); - } - } - - // Draw the Text - if(text != null) { - View v = (View) c.getClientProperty(BasicHTML.propertyKey); - if (v != null) { - v.paint(g, textRect); - } else { - g.setColor(style.getColor(context, ColorType.TEXT_FOREGROUND)); - g.setFont(style.getFont(context)); - style.getGraphicsUtils(context).paintText(context, g, text, - textRect.x, textRect.y, b.getDisplayedMnemonicIndex()); - } - } - - // Draw the Accelerator Text - if(acceleratorText != null && !acceleratorText.equals("")) { - // Get the maxAccWidth from the parent to calculate the offset. - int accOffset = 0; - Container parent = b.getParent(); - if (parent != null && parent instanceof JPopupMenu) { - SynthPopupMenuUI popupUI = (SynthPopupMenuUI) - ((JPopupMenu)parent).getUI(); - - // Note that we can only get here for SynthMenuItemUI - // (not SynthMenuUI) since acceleratorText is defined, - // so this cast should be safe - SynthMenuItemUI miUI = (SynthMenuItemUI) - SynthLookAndFeel.getUIOfType(b.getUI(), - SynthMenuItemUI.class); - - if (popupUI != null && miUI != null) { - String prop = - miUI.getPropertyPrefix() + ".alignAcceleratorText"; - boolean align = style.getBoolean(context, prop, true); - - // Calculate the offset, with which the accelerator texts - // will be drawn. - if (align) { - // When align==true and we're in the LTR case, - // we add an offset here so that all accelerators - // will be left-justified in their own column. - int max = popupUI.getMaxAcceleratorWidth(); - if (max > 0) { - accOffset = max - acceleratorRect.width; - if (!SynthLookAndFeel.isLeftToRight(c)) { - // In the RTL, flip the sign so that all - // accelerators will be right-justified. - accOffset = -accOffset; - } - } - } //else { - // Don't need to do anything special here; in the - // LTR case, the accelerator is already justified - // against the right edge of the menu (and against - // the left edge in the RTL case). - //} - } - } - - SynthStyle accStyle = accContext.getStyle(); - - g.setColor(accStyle.getColor(accContext, - ColorType.TEXT_FOREGROUND)); - g.setFont(accStyle.getFont(accContext)); - accStyle.getGraphicsUtils(accContext).paintText( - accContext, g, acceleratorText, acceleratorRect.x - - accOffset, acceleratorRect.y, -1); - } - - // Paint the Arrow - if (arrowIcon != null) { - SynthIcon.paintIcon(arrowIcon, context, g, arrowIconRect.x, - arrowIconRect.y, arrowIconRect.width, arrowIconRect.height); - } - } - - /** - * Compute and return the location of the icons origin, the - * location of origin of the text baseline, and a possibly clipped - * version of the compound labels string. Locations are computed - * relative to the viewRect rectangle. - */ - - private static String layoutMenuItem( - SynthContext context, - FontMetrics fm, - SynthContext accContext, - String text, - FontMetrics fmAccel, - String acceleratorText, - Icon icon, - Icon checkIcon, - Icon arrowIcon, - int verticalAlignment, - int horizontalAlignment, - int verticalTextPosition, - int horizontalTextPosition, - Rectangle viewRect, - Rectangle iconRect, - Rectangle textRect, - Rectangle acceleratorRect, - Rectangle checkIconRect, - Rectangle arrowIconRect, - int textIconGap, - int menuItemGap - ) - { - // If parent is JPopupMenu, get and store it's UI - SynthPopupMenuUI popupUI = null; - JComponent b = context.getComponent(); - Container parent = b.getParent(); - if(parent instanceof JPopupMenu) { - popupUI = (SynthPopupMenuUI)SynthLookAndFeel. - getUIOfType(((JPopupMenu)parent).getUI(), - SynthPopupMenuUI.class); - } - - context.getStyle().getGraphicsUtils(context).layoutText( - context, fm, text, icon,horizontalAlignment, verticalAlignment, - horizontalTextPosition, verticalTextPosition, viewRect, - iconRect, textRect, textIconGap); - - /* Initialize the acceleratorText bounds rectangle textRect. If a null - * or and empty String was specified we substitute "" here - * and use 0,0,0,0 for acceleratorTextRect. - */ - if( (acceleratorText == null) || acceleratorText.equals("") ) { - acceleratorRect.width = acceleratorRect.height = 0; - acceleratorText = ""; - } - else { - SynthStyle style = accContext.getStyle(); - acceleratorRect.width = style.getGraphicsUtils(accContext). - computeStringWidth(accContext, fmAccel.getFont(), fmAccel, - acceleratorText); - acceleratorRect.height = fmAccel.getHeight(); - } - - // Initialize the checkIcon bounds rectangle width & height. - if (checkIcon != null) { - checkIconRect.width = SynthIcon.getIconWidth(checkIcon, - context); - checkIconRect.height = SynthIcon.getIconHeight(checkIcon, - context); - } - else { - checkIconRect.width = checkIconRect.height = 0; - } - - // Initialize the arrowIcon bounds rectangle width & height. - if (arrowIcon != null) { - arrowIconRect.width = SynthIcon.getIconWidth(arrowIcon, - context); - arrowIconRect.height = SynthIcon.getIconHeight(arrowIcon, - context); - } else { - arrowIconRect.width = arrowIconRect.height = 0; - } - - // Note: layoutText() has already left room for - // the user icon, so no need to adjust textRect below - // to account for the user icon. However, we do have to - // reposition textRect when the check icon is visible. - - Rectangle labelRect = iconRect.union(textRect); - if( SynthLookAndFeel.isLeftToRight(context.getComponent()) ) { - // Position the check and user icons - iconRect.x = viewRect.x; - if (checkIcon != null) { - checkIconRect.x = viewRect.x; - iconRect.x += menuItemGap + checkIconRect.width; - textRect.x += menuItemGap + checkIconRect.width; - } - - // Position the arrow icon - arrowIconRect.x = - viewRect.x + viewRect.width - arrowIconRect.width; - - // Position the accelerator text rect - acceleratorRect.x = - viewRect.x + viewRect.width - acceleratorRect.width; - - /* Align icons and text horizontally */ - if(popupUI != null) { - int thisTextOffset = popupUI.adjustTextOffset(textRect.x - - viewRect.x); - textRect.x = thisTextOffset + viewRect.x; - - if(icon != null) { - // REMIND: The following code currently assumes the - // default (TRAILING) horizontalTextPosition, which means - // it will always place the icon to the left of the text. - // Other values of horizontalTextPosition aren't very - // useful for menu items, so we ignore them for now, but - // someday we might want to fix this situation. - int thisIconOffset = - popupUI.adjustIconOffset(iconRect.x - viewRect.x); - iconRect.x = thisIconOffset + viewRect.x; - } - } - } else { - // Position the accelerator text rect - acceleratorRect.x = viewRect.x; - - // Position the arrow icon - arrowIconRect.x = viewRect.x; - - // Position the check and user icons - iconRect.x = - viewRect.x + viewRect.width - iconRect.width; - if (checkIcon != null) { - checkIconRect.x = - viewRect.x + viewRect.width - checkIconRect.width; - textRect.x -= menuItemGap + checkIconRect.width; - iconRect.x -= menuItemGap + checkIconRect.width; - } - - /* Align icons and text horizontally */ - if(popupUI != null) { - int thisTextOffset = viewRect.x + viewRect.width - - textRect.x - textRect.width; - thisTextOffset = popupUI.adjustTextOffset(thisTextOffset); - textRect.x = viewRect.x + viewRect.width - - thisTextOffset - textRect.width; - if(icon != null) { - // REMIND: The following code currently assumes the - // default (TRAILING) horizontalTextPosition, which means - // it will always place the icon to the right of the text. - // Other values of horizontalTextPosition aren't very - // useful for menu items, so we ignore them for now, but - // someday we might want to fix this situation. - int thisIconOffset = viewRect.x + viewRect.width - - iconRect.x - iconRect.width; - thisIconOffset = - popupUI.adjustIconOffset(thisIconOffset); - iconRect.x = viewRect.x + viewRect.width - - thisIconOffset - iconRect.width; - } - } - } - - // Align the accelerator text and all icons vertically - // with the center of the label rect. - int midY = labelRect.y + (labelRect.height/2); - iconRect.y = midY - (iconRect.height/2); - acceleratorRect.y = midY - (acceleratorRect.height/2); - arrowIconRect.y = midY - (arrowIconRect.height/2); - checkIconRect.y = midY - (checkIconRect.height/2); - - return text; - } - - // these rects are used for painting and preferredsize calculations. - // they used to be regenerated constantly. Now they are reused. - static Rectangle iconRect = new Rectangle(); - static Rectangle textRect = new Rectangle(); - static Rectangle acceleratorRect = new Rectangle(); - static Rectangle checkIconRect = new Rectangle(); - static Rectangle arrowIconRect = new Rectangle(); - static Rectangle viewRect = new Rectangle(Short.MAX_VALUE,Short.MAX_VALUE); - static Rectangle r = new Rectangle(); - - private static void resetRects() { - iconRect.setBounds(0, 0, 0, 0); - textRect.setBounds(0, 0, 0, 0); - acceleratorRect.setBounds(0, 0, 0, 0); - checkIconRect.setBounds(0, 0, 0, 0); - arrowIconRect.setBounds(0, 0, 0, 0); - viewRect.setBounds(0,0,Short.MAX_VALUE, Short.MAX_VALUE); - r.setBounds(0, 0, 0, 0); - } - - protected void installDefaults() { updateStyle(menuItem); } @@ -718,9 +192,11 @@ class SynthMenuItemUI extends BasicMenuItemUI implements int defaultTextIconGap) { SynthContext context = getContext(c); SynthContext accContext = getContext(c, Region.MENU_ITEM_ACCELERATOR); - Dimension value = getPreferredMenuItemSize(context, accContext, - c, checkIcon, arrowIcon, defaultTextIconGap, - acceleratorDelimiter); + Dimension value = SynthGraphicsUtils.getPreferredMenuItemSize( + context, accContext, c, checkIcon, arrowIcon, + defaultTextIconGap, acceleratorDelimiter, + MenuItemLayoutHelper.useCheckAndArrow(menuItem), + getPropertyPrefix()); context.dispose(); accContext.dispose(); return value; @@ -751,14 +227,13 @@ class SynthMenuItemUI extends BasicMenuItemUI implements String prefix = getPropertyPrefix(); Icon checkIcon = style.getIcon(context, prefix + ".checkIcon"); Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); - paint(context, accContext, g, checkIcon, arrowIcon, - acceleratorDelimiter, defaultTextIconGap); + SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon, + acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix()); accContext.dispose(); } void paintBackground(SynthContext context, Graphics g, JComponent c) { - context.getPainter().paintMenuItemBackground(context, g, 0, 0, - c.getWidth(), c.getHeight()); + SynthGraphicsUtils.paintBackground(context, g, c); } public void paintBorder(SynthContext context, Graphics g, int x, diff --git a/src/share/classes/javax/swing/plaf/synth/SynthMenuUI.java b/src/share/classes/javax/swing/plaf/synth/SynthMenuUI.java index c59acb09b28ecb3cd6d5a72d4bf7d7a6bf7a5281..78835abf141c4239105dfa2bd1c145369d9dbf94 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthMenuUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthMenuUI.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 @@ -35,7 +35,7 @@ import javax.swing.border.*; import java.util.Arrays; import java.util.ArrayList; import sun.swing.plaf.synth.SynthUI; - +import sun.swing.MenuItemLayoutHelper; /** * Synth's MenuUI. @@ -86,7 +86,7 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener, acceleratorDelimiter = style.getString(context, prefix + ".acceleratorDelimiter", "+"); - if (useCheckAndArrow()) { + if (MenuItemLayoutHelper.useCheckAndArrow(menuItem)) { checkIcon = style.getIcon(context, prefix + ".checkIcon"); arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); } else { @@ -111,6 +111,16 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener, accContext.dispose(); } + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + // Remove values from the parent's Client Properties. + JComponent p = MenuItemLayoutHelper.getMenuItemParent((JMenuItem) c); + if (p != null) { + p.putClientProperty( + SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null); + } + } + protected void uninstallDefaults() { SynthContext context = getContext(menuItem, ENABLED); style.uninstallDefaults(context); @@ -182,9 +192,11 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener, int defaultTextIconGap) { SynthContext context = getContext(c); SynthContext accContext = getContext(c, Region.MENU_ITEM_ACCELERATOR); - Dimension value = SynthMenuItemUI.getPreferredMenuItemSize( - context, accContext, c, checkIcon, arrowIcon, - defaultTextIconGap, acceleratorDelimiter); + Dimension value = SynthGraphicsUtils.getPreferredMenuItemSize( + context, accContext, c, checkIcon, arrowIcon, + defaultTextIconGap, acceleratorDelimiter, + MenuItemLayoutHelper.useCheckAndArrow(menuItem), + getPropertyPrefix()); context.dispose(); accContext.dispose(); return value; @@ -211,21 +223,12 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener, protected void paint(SynthContext context, Graphics g) { SynthContext accContext = getContext(menuItem, Region.MENU_ITEM_ACCELERATOR); - SynthStyle style = context.getStyle(); - Icon checkIcon; - Icon arrowIcon; - if (useCheckAndArrow()) { - // Refetch the appropriate icons for the current state - String prefix = getPropertyPrefix(); - checkIcon = style.getIcon(context, prefix + ".checkIcon"); - arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); - } else { - // Not needed in this case - checkIcon = null; - arrowIcon = null; - } - SynthMenuItemUI.paint(context, accContext, g, checkIcon, arrowIcon, - acceleratorDelimiter, defaultTextIconGap); + // Refetch the appropriate check indicator for the current state + String prefix = getPropertyPrefix(); + Icon checkIcon = style.getIcon(context, prefix + ".checkIcon"); + Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); + SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon, + acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix()); accContext.dispose(); } @@ -239,8 +242,4 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener, updateStyle((JMenu)e.getSource()); } } - - private boolean useCheckAndArrow() { - return !((JMenu)menuItem).isTopLevelMenu(); - } } diff --git a/src/share/classes/javax/swing/plaf/synth/SynthParser.java b/src/share/classes/javax/swing/plaf/synth/SynthParser.java index 4b7d7994b5e0d11f7549e07d4d8d9dad2ff9bc98..5f7a9b6c2827bb113ce8e217987ae53e6be6867f 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthParser.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthParser.java @@ -40,6 +40,7 @@ import java.net.URLClassLoader; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; @@ -136,7 +137,7 @@ class SynthParser extends HandlerBase { * Array of state infos for the current style. These are pushed to the * style when is received. */ - private java.util.List _stateInfos; + private List _stateInfos; /** * Current style. @@ -151,7 +152,7 @@ class SynthParser extends HandlerBase { /** * Bindings for the current InputMap */ - private java.util.List _inputMapBindings; + private List _inputMapBindings; /** * ID for the input map. This is cached as @@ -177,30 +178,30 @@ class SynthParser extends HandlerBase { /** * List of ColorTypes. This is populated in startColorType. */ - private java.util.List _colorTypes; + private List _colorTypes; /** * defaultsPropertys are placed here. */ - private Map _defaultsMap; + private Map _defaultsMap; /** * List of SynthStyle.Painters that will be applied to the current style. */ - private java.util.List _stylePainters; + private List _stylePainters; /** * List of SynthStyle.Painters that will be applied to the current state. */ - private java.util.List _statePainters; + private List _statePainters; SynthParser() { _mapping = new HashMap(); - _stateInfos = new ArrayList(); - _colorTypes = new ArrayList(); - _inputMapBindings = new ArrayList(); - _stylePainters = new ArrayList(); - _statePainters = new ArrayList(); + _stateInfos = new ArrayList(); + _colorTypes = new ArrayList(); + _inputMapBindings = new ArrayList(); + _stylePainters = new ArrayList(); + _statePainters = new ArrayList(); } /** @@ -219,7 +220,7 @@ class SynthParser extends HandlerBase { public void parse(InputStream inputStream, DefaultSynthStyleFactory factory, URL urlResourceBase, Class classResourceBase, - Map defaultsMap) + Map defaultsMap) throws ParseException, IllegalArgumentException { if (inputStream == null || factory == null || (urlResourceBase == null && classResourceBase == null)) { @@ -333,7 +334,7 @@ class SynthParser extends HandlerBase { * type type, this will throw an exception. */ private Object lookup(String key, Class type) throws SAXException { - Object value = null; + Object value; if (_handler != null) { if ((value = _handler.lookup(key)) != null) { return checkCast(value, type); @@ -423,15 +424,12 @@ class SynthParser extends HandlerBase { private void endStyle() throws SAXException { int size = _stylePainters.size(); if (size > 0) { - _style.setPainters((ParsedSynthStyle.PainterInfo[]) - _stylePainters.toArray(new ParsedSynthStyle. - PainterInfo[size])); + _style.setPainters(_stylePainters.toArray(new ParsedSynthStyle.PainterInfo[size])); _stylePainters.clear(); } size = _stateInfos.size(); if (size > 0) { - _style.setStateInfo((ParsedSynthStyle.StateInfo[])_stateInfos. - toArray(new ParsedSynthStyle.StateInfo[size])); + _style.setStateInfo(_stateInfos.toArray(new ParsedSynthStyle.StateInfo[size])); _stateInfos.clear(); } _style = null; @@ -501,9 +499,7 @@ class SynthParser extends HandlerBase { private void endState() throws SAXException { int size = _statePainters.size(); if (size > 0) { - _stateInfo.setPainters((ParsedSynthStyle.PainterInfo[]) - _statePainters.toArray(new ParsedSynthStyle. - PainterInfo[size])); + _stateInfo.setPainters(_statePainters.toArray(new ParsedSynthStyle.PainterInfo[size])); _statePainters.clear(); } _stateInfo = null; @@ -684,8 +680,7 @@ class SynthParser extends HandlerBase { int max = 0; for (int counter = _colorTypes.size() - 1; counter >= 0; counter--) { - max = Math.max(max, ((ColorType)_colorTypes.get(counter)). - getID()); + max = Math.max(max, _colorTypes.get(counter).getID()); } if (colors == null || colors.length <= max) { Color[] newColors = new Color[max + 1]; @@ -696,7 +691,7 @@ class SynthParser extends HandlerBase { } for (int counter = _colorTypes.size() - 1; counter >= 0; counter--) { - colors[((ColorType)_colorTypes.get(counter)).getID()] = color; + colors[_colorTypes.get(counter).getID()] = color; } _stateInfo.setColors(colors); } @@ -705,7 +700,7 @@ class SynthParser extends HandlerBase { private void startProperty(AttributeList attributes, Object property) throws SAXException { Object value = null; - Object key = null; + String key = null; // Type of the value: 0=idref, 1=boolean, 2=dimension, 3=insets, // 4=integer,5=string int iType = 0; @@ -1027,7 +1022,7 @@ class SynthParser extends HandlerBase { } } - private void addPainterOrMerge(java.util.List painters, String method, + private void addPainterOrMerge(List painters, String method, SynthPainter painter, int direction) { ParsedSynthStyle.PainterInfo painterInfo; painterInfo = new ParsedSynthStyle.PainterInfo(method, diff --git a/src/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java b/src/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java index e8fb73bc156dc3dc22898df9dc2f4db6513bb391..50d1c2781ac4ff5ab2b94ac3bdf2b37570720c26 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthPopupMenuUI.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 @@ -58,34 +58,6 @@ import sun.swing.plaf.synth.SynthUI; */ class SynthPopupMenuUI extends BasicPopupMenuUI implements PropertyChangeListener, SynthUI { - /** - * Maximum size of the text portion of the children menu items. - */ - private int maxTextWidth; - - /** - * Maximum size of the icon portion of the children menu items. - */ - private int maxIconWidth; - - /** - * Maximum size of the spacing between the text and accelerator - * portions of the children menu items. - */ - private int maxAccelSpacingWidth; - - /** - * Maximum size of the text for the accelerator portion of the children - * menu items. - */ - private int maxAcceleratorWidth; - - /* - * Maximum icon and text offsets of the children menu items. - */ - private int maxTextOffset; - private int maxIconOffset; - private SynthStyle style; public static ComponentUI createUI(JComponent x) { @@ -153,90 +125,6 @@ class SynthPopupMenuUI extends BasicPopupMenuUI implements return SynthLookAndFeel.getComponentState(c); } - /** - * Resets the max text and accerator widths, - * text and icon offsets. - */ - void resetAlignmentHints() { - maxTextWidth = maxIconWidth - = maxAccelSpacingWidth = maxAcceleratorWidth - = maxTextOffset = maxIconOffset = 0; - } - - /** - * Adjusts the width needed to display the maximum menu item string. - * - * @param width Text width. - * @return max width - */ - int adjustTextWidth(int width) { - maxTextWidth = Math.max(maxTextWidth, width); - return maxTextWidth; - } - - /** - * Adjusts the width needed to display the maximum menu item icon. - * - * @param width Icon width. - * @return max width - */ - int adjustIconWidth(int width) { - maxIconWidth = Math.max(maxIconWidth, width); - return maxIconWidth; - } - - /** - * Adjusts the width needed to pad between the maximum menu item - * text and accelerator. - * - * @param width Spacing width. - * @return max width - */ - int adjustAccelSpacingWidth(int width) { - maxAccelSpacingWidth = Math.max(maxAccelSpacingWidth, width); - return maxAccelSpacingWidth; - } - - /** - * Adjusts the width needed to display the maximum accelerator. - * - * @param width Text width. - * @return max width - */ - int adjustAcceleratorWidth(int width) { - maxAcceleratorWidth = Math.max(maxAcceleratorWidth, width); - return maxAcceleratorWidth; - } - - /** - * Maximum size needed to display accelerators of children menu items. - */ - int getMaxAcceleratorWidth() { - return maxAcceleratorWidth; - } - - /** - * Adjusts the text offset needed to align text horizontally. - * - * @param offset Text offset - * @return max offset - */ - int adjustTextOffset(int offset) { - maxTextOffset = Math.max(maxTextOffset, offset); - return maxTextOffset; - } - - /** - * Adjusts the icon offset needed to align icons horizontally - * - * @param offset Icon offset - * @return max offset - */ - int adjustIconOffset(int offset) { - maxIconOffset = Math.max(maxIconOffset, offset); - return maxIconOffset; - } - public void update(Graphics g, JComponent c) { SynthContext context = getContext(c); diff --git a/src/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java b/src/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java index 00f5d955f977493cabdc07f208f5415ea5221169..6cf4da962a204ffa67a948b587ac8c0e98fb8608 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java @@ -48,13 +48,13 @@ class SynthSplitPaneUI extends BasicSplitPaneUI implements * Keys to use for forward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusForwardTraversalKeys; + private static Set managingFocusForwardTraversalKeys; /** * Keys to use for backward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusBackwardTraversalKeys; + private static Set managingFocusBackwardTraversalKeys; /** * Style for the JSplitPane. @@ -96,7 +96,7 @@ class SynthSplitPaneUI extends BasicSplitPaneUI implements // focus forward traversal key if (managingFocusForwardTraversalKeys==null) { - managingFocusForwardTraversalKeys = new HashSet(); + managingFocusForwardTraversalKeys = new HashSet(); managingFocusForwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); } @@ -104,7 +104,7 @@ class SynthSplitPaneUI extends BasicSplitPaneUI implements managingFocusForwardTraversalKeys); // focus backward traversal key if (managingFocusBackwardTraversalKeys==null) { - managingFocusBackwardTraversalKeys = new HashSet(); + managingFocusBackwardTraversalKeys = new HashSet(); managingFocusBackwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK)); } diff --git a/src/share/classes/javax/swing/plaf/synth/SynthStyle.java b/src/share/classes/javax/swing/plaf/synth/SynthStyle.java index c9475f91b5476ddda114c12d2ae5a129728f6933..ab9e42b41e5e1ec21dbd535f767aca490984c1f7 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthStyle.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthStyle.java @@ -53,7 +53,7 @@ public abstract class SynthStyle { /** * Contains the default values for certain properties. */ - private static Map DEFAULT_VALUES; + private static Map DEFAULT_VALUES; /** * Shared SynthGraphics. @@ -715,7 +715,7 @@ public abstract class SynthStyle { private static Object getDefaultValue(Object key) { synchronized(SynthStyle.class) { if (DEFAULT_VALUES == null) { - DEFAULT_VALUES = new HashMap(); + DEFAULT_VALUES = new HashMap(); populateDefaultValues(); } Object value = DEFAULT_VALUES.get(key); diff --git a/src/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java b/src/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java index f52d3a68b0dbca2daeff61a7c62bec2b1c20f77a..d07c4d5ad888adf7019b16011b4a560f0cfd7d1e 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthTextAreaUI.java @@ -66,7 +66,7 @@ class SynthTextAreaUI extends BasicTextAreaUI implements SynthUI { protected void installDefaults() { // Installs the text cursor on the component super.installDefaults(); - updateStyle((JTextComponent)getComponent()); + updateStyle(getComponent()); } protected void uninstallDefaults() { diff --git a/src/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java b/src/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java index 5b7cbd0a5f5af7e2e669673ed99af1c442e9ed59..28bbdf843c40d8838e203678ab171521ce95254e 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthTextFieldUI.java @@ -232,7 +232,7 @@ class SynthTextFieldUI protected void installDefaults() { // Installs the text cursor on the component super.installDefaults(); - updateStyle((JTextComponent)getComponent()); + updateStyle(getComponent()); getComponent().addFocusListener(this); } diff --git a/src/share/classes/javax/swing/plaf/synth/SynthTreeUI.java b/src/share/classes/javax/swing/plaf/synth/SynthTreeUI.java index 1e12a820ece43b12d3a27b4f115848a581b9d61a..464b947b071fb100da72d346b7e354ccc6922fdc 100644 --- a/src/share/classes/javax/swing/plaf/synth/SynthTreeUI.java +++ b/src/share/classes/javax/swing/plaf/synth/SynthTreeUI.java @@ -390,7 +390,7 @@ class SynthTreeUI extends BasicTreeUI implements PropertyChangeListener, } private Rectangle getDropLineRect(JTree.DropLocation loc) { - Rectangle rect = null; + Rectangle rect; TreePath path = loc.getPath(); int index = loc.getChildIndex(); boolean ltr = tree.getComponentOrientation().isLeftToRight(); @@ -523,7 +523,7 @@ class SynthTreeUI extends BasicTreeUI implements PropertyChangeListener, // Don't paint the renderer if editing this row. boolean selected = tree.isRowSelected(row); - JTree.DropLocation dropLocation = (JTree.DropLocation)tree.getDropLocation(); + JTree.DropLocation dropLocation = tree.getDropLocation(); boolean isDrop = dropLocation != null && dropLocation.getChildIndex() == -1 && path == dropLocation.getPath(); diff --git a/src/share/classes/javax/swing/table/AbstractTableModel.java b/src/share/classes/javax/swing/table/AbstractTableModel.java index 4a9474cb258069a40353c06e064e1578726e8bd8..9d6f4cafdcb11f14316e9616e5f23879bd5abc8f 100644 --- a/src/share/classes/javax/swing/table/AbstractTableModel.java +++ b/src/share/classes/javax/swing/table/AbstractTableModel.java @@ -176,8 +176,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @since 1.4 */ public TableModelListener[] getTableModelListeners() { - return (TableModelListener[])listenerList.getListeners( - TableModelListener.class); + return listenerList.getListeners(TableModelListener.class); } // diff --git a/src/share/classes/javax/swing/table/DefaultTableModel.java b/src/share/classes/javax/swing/table/DefaultTableModel.java index c2e97a9a2dd1eec3b209792c87ec679b2968ee18..0a63bfa73cda297d5162960d99504bcd5a1d1b05 100644 --- a/src/share/classes/javax/swing/table/DefaultTableModel.java +++ b/src/share/classes/javax/swing/table/DefaultTableModel.java @@ -681,9 +681,9 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl if (anArray == null) { return null; } - Vector v = new Vector(anArray.length); - for (int i=0; i < anArray.length; i++) { - v.addElement(anArray[i]); + Vector v = new Vector(anArray.length); + for (Object o : anArray) { + v.addElement(o); } return v; } @@ -698,9 +698,9 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl if (anArray == null) { return null; } - Vector v = new Vector(anArray.length); - for (int i=0; i < anArray.length; i++) { - v.addElement(convertToVector(anArray[i])); + Vector v = new Vector(anArray.length); + for (Object[] o : anArray) { + v.addElement(convertToVector(o)); } return v; } diff --git a/src/share/classes/javax/swing/text/AbstractDocument.java b/src/share/classes/javax/swing/text/AbstractDocument.java index fb081199ebeef71fd6d438c511e3861ba3843e63..0d815e0f6e9fbac9dc09a58ac4eab3f9a7a7c4e4 100644 --- a/src/share/classes/javax/swing/text/AbstractDocument.java +++ b/src/share/classes/javax/swing/text/AbstractDocument.java @@ -123,15 +123,15 @@ public abstract class AbstractDocument implements Document, Serializable { if (defaultI18NProperty == null) { // determine default setting for i18n support - Object o = java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { + String o = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public String run() { return System.getProperty(I18NProperty); } } ); if (o != null) { - defaultI18NProperty = Boolean.valueOf((String)o); + defaultI18NProperty = Boolean.valueOf(o); } else { defaultI18NProperty = Boolean.FALSE; } @@ -163,7 +163,7 @@ public abstract class AbstractDocument implements Document, Serializable { */ public Dictionary getDocumentProperties() { if (documentProperties == null) { - documentProperties = new Hashtable(2); + documentProperties = new Hashtable(2); } return documentProperties; } @@ -467,8 +467,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @since 1.4 */ public DocumentListener[] getDocumentListeners() { - return (DocumentListener[])listenerList.getListeners( - DocumentListener.class); + return listenerList.getListeners(DocumentListener.class); } /** @@ -508,8 +507,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @since 1.4 */ public UndoableEditListener[] getUndoableEditListeners() { - return (UndoableEditListener[])listenerList.getListeners( - UndoableEditListener.class); + return listenerList.getListeners(UndoableEditListener.class); } /** @@ -610,7 +608,7 @@ public abstract class AbstractDocument implements Document, Serializable { DefaultDocumentEvent chng = new DefaultDocumentEvent(offs, len, DocumentEvent.EventType.REMOVE); - boolean isComposedTextElement = false; + boolean isComposedTextElement; // Check whether the position of interest is the composed text isComposedTextElement = Utilities.isComposedTextElement(this, offs); @@ -1051,7 +1049,7 @@ public abstract class AbstractDocument implements Document, Serializable { byte levels[] = calculateBidiLevels( firstPStart, lastPEnd ); - Vector newElements = new Vector(); + Vector newElements = new Vector(); // Calculate the first span of characters in the affected range with // the same bidi level. If this level is the same as the level of the @@ -1831,7 +1829,6 @@ public abstract class AbstractDocument implements Document, Serializable { } out.println("["+contentStr+"]"); } catch (BadLocationException e) { - ; } } else { @@ -2460,7 +2457,7 @@ public abstract class AbstractDocument implements Document, Serializable { if(nchildren == 0) return null; - Vector tempVector = new Vector(nchildren); + Vector tempVector = new Vector(nchildren); for(int counter = 0; counter < nchildren; counter++) tempVector.addElement(children[counter]); @@ -2749,7 +2746,7 @@ public abstract class AbstractDocument implements Document, Serializable { // if the number of changes gets too great, start using // a hashtable for to locate the change for a given element. if ((changeLookup == null) && (edits.size() > 10)) { - changeLookup = new Hashtable(); + changeLookup = new Hashtable(); int n = edits.size(); for (int i = 0; i < n; i++) { Object o = edits.elementAt(i); @@ -2918,7 +2915,7 @@ public abstract class AbstractDocument implements Document, Serializable { */ public DocumentEvent.ElementChange getChange(Element elem) { if (changeLookup != null) { - return (DocumentEvent.ElementChange) changeLookup.get(elem); + return changeLookup.get(elem); } int n = edits.size(); for (int i = 0; i < n; i++) { @@ -2937,7 +2934,7 @@ public abstract class AbstractDocument implements Document, Serializable { private int offset; private int length; - private Hashtable changeLookup; + private Hashtable changeLookup; private DocumentEvent.EventType type; } diff --git a/src/share/classes/javax/swing/text/AsyncBoxView.java b/src/share/classes/javax/swing/text/AsyncBoxView.java index 54a0e973553bc9e1a95d364c3d65cd7c2bac8f5b..ae11bde81227a85068eafee1cf709324addcd4a4 100644 --- a/src/share/classes/javax/swing/text/AsyncBoxView.java +++ b/src/share/classes/javax/swing/text/AsyncBoxView.java @@ -25,6 +25,7 @@ package javax.swing.text; import java.util.*; +import java.util.List; import java.awt.*; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; @@ -58,7 +59,7 @@ public class AsyncBoxView extends View { */ public AsyncBoxView(Element elem, int axis) { super(elem); - stats = new ArrayList(); + stats = new ArrayList(); this.axis = axis; locator = new ChildLocator(); flushTask = new FlushTask(); @@ -197,7 +198,7 @@ public class AsyncBoxView extends View { protected ChildState getChildState(int index) { synchronized(stats) { if ((index >= 0) && (index < stats.size())) { - return (ChildState) stats.get(index); + return stats.get(index); } return null; } @@ -357,7 +358,7 @@ public class AsyncBoxView extends View { synchronized(stats) { // remove the replaced state records for (int i = 0; i < length; i++) { - ChildState cs = (ChildState)stats.remove(offset); + ChildState cs = stats.remove(offset); float csSpan = cs.getMajorSpan(); cs.getChildView().setParent(null); @@ -863,7 +864,7 @@ public class AsyncBoxView extends View { /** * The children and their layout statistics. */ - java.util.List stats; + List stats; /** * Current span along the major axis. This @@ -1110,7 +1111,7 @@ public class AsyncBoxView extends View { */ int updateChildOffsets(float targetOffset) { int n = getViewCount(); - int targetIndex = n - 1;; + int targetIndex = n - 1; int pos = lastValidOffset.getChildView().getStartOffset(); int startIndex = getViewIndex(pos, Position.Bias.Forward); float start = lastValidOffset.getMajorOffset(); @@ -1394,7 +1395,6 @@ public class AsyncBoxView extends View { private float min; private float pref; private float max; - private float align; private boolean minorValid; // major axis diff --git a/src/share/classes/javax/swing/text/ComponentView.java b/src/share/classes/javax/swing/text/ComponentView.java index 62e4bd02acbfc3751e5b8fd17575f97e47be104a..085d999675d9b86ff65f4793fefc863ea5468708 100644 --- a/src/share/classes/javax/swing/text/ComponentView.java +++ b/src/share/classes/javax/swing/text/ComponentView.java @@ -27,6 +27,7 @@ package javax.swing.text; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Set; import javax.swing.SwingUtilities; import javax.swing.event.*; @@ -434,7 +435,7 @@ public class ComponentView extends View { /** * Shows or hides this component depending on the value of parameter * b. - * @param b If true, shows this component; + * @param b If true, shows this component; * otherwise, hides this component. * @see #isVisible * @since JDK1.1 @@ -480,7 +481,7 @@ public class ComponentView extends View { return yalign; } - public java.util.Set getFocusTraversalKeys(int id) { + public Set getFocusTraversalKeys(int id) { return KeyboardFocusManager.getCurrentKeyboardFocusManager(). getDefaultFocusTraversalKeys(id); } diff --git a/src/share/classes/javax/swing/text/DefaultCaret.java b/src/share/classes/javax/swing/text/DefaultCaret.java index 22ec280ba097d806a2ea061adb9ec9bf09258c17..e0e156811888ff61df76626a9e2f9b155c28782d 100644 --- a/src/share/classes/javax/swing/text/DefaultCaret.java +++ b/src/share/classes/javax/swing/text/DefaultCaret.java @@ -774,8 +774,7 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou * @since 1.4 */ public ChangeListener[] getChangeListeners() { - return (ChangeListener[])listenerList.getListeners( - ChangeListener.class); + return listenerList.getListeners(ChangeListener.class); } /** @@ -1330,7 +1329,7 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou if (this.dot != this.mark && component != null) { Clipboard clip = getSystemSelection(); if (clip != null) { - String selectedText = null; + String selectedText; if (component instanceof JPasswordField && component.getClientProperty("JPasswordField.cutCopyAllowed") != Boolean.TRUE) { diff --git a/src/share/classes/javax/swing/text/DefaultFormatter.java b/src/share/classes/javax/swing/text/DefaultFormatter.java index 79419047273a125625b4539ddf0dfc17d8883ff8..51dab601ca19b0bad3681df6871afa893ee6737b 100644 --- a/src/share/classes/javax/swing/text/DefaultFormatter.java +++ b/src/share/classes/javax/swing/text/DefaultFormatter.java @@ -68,7 +68,7 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter private boolean commitOnEdit; /** Class used to create new instances. */ - private Class valueClass; + private Class valueClass; /** NavigationFilter that forwards calls back to DefaultFormatter. */ private NavigationFilter navigationFilter; @@ -231,7 +231,7 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter * @return Object representation of text */ public Object stringToValue(String string) throws ParseException { - Class vc = getValueClass(); + Class vc = getValueClass(); JFormattedTextField ftf = getFormattedTextField(); if (vc == null && ftf != null) { diff --git a/src/share/classes/javax/swing/text/DefaultHighlighter.java b/src/share/classes/javax/swing/text/DefaultHighlighter.java index 9e3202130d3215e895fff6a1e12c36df342e692c..028b24c0ea630fcb3499cfcec632c96d1fa32ed2 100644 --- a/src/share/classes/javax/swing/text/DefaultHighlighter.java +++ b/src/share/classes/javax/swing/text/DefaultHighlighter.java @@ -56,7 +56,7 @@ public class DefaultHighlighter extends LayeredHighlighter { // PENDING(prinz) - should cull ranges not visible int len = highlights.size(); for (int i = 0; i < len; i++) { - HighlightInfo info = (HighlightInfo) highlights.elementAt(i); + HighlightInfo info = highlights.elementAt(i); if (!(info instanceof LayeredHighlightInfo)) { // Avoid allocing unless we need it. Rectangle a = component.getBounds(); @@ -66,7 +66,7 @@ public class DefaultHighlighter extends LayeredHighlighter { a.width -= insets.left + insets.right; a.height -= insets.top + insets.bottom; for (; i < len; i++) { - info = (HighlightInfo)highlights.elementAt(i); + info = highlights.elementAt(i); if (!(info instanceof LayeredHighlightInfo)) { Highlighter.HighlightPainter p = info.getPainter(); p.paint(g, info.getStartOffset(), info.getEndOffset(), @@ -159,7 +159,7 @@ public class DefaultHighlighter extends LayeredHighlighter { int p0 = -1; int p1 = -1; for (int i = 0; i < len; i++) { - HighlightInfo hi = (HighlightInfo)highlights.elementAt(i); + HighlightInfo hi = highlights.elementAt(i); if (hi instanceof LayeredHighlightInfo) { LayeredHighlightInfo info = (LayeredHighlightInfo)hi; minX = Math.min(minX, info.x); @@ -195,7 +195,7 @@ public class DefaultHighlighter extends LayeredHighlighter { int p0 = Integer.MAX_VALUE; int p1 = 0; for (int i = 0; i < len; i++) { - HighlightInfo info = (HighlightInfo) highlights.elementAt(i); + HighlightInfo info = highlights.elementAt(i); p0 = Math.min(p0, info.p0.getOffset()); p1 = Math.max(p1, info.p1.getOffset()); } @@ -282,7 +282,7 @@ public class DefaultHighlighter extends LayeredHighlighter { Shape viewBounds, JTextComponent editor, View view) { for (int counter = highlights.size() - 1; counter >= 0; counter--) { - Object tag = highlights.elementAt(counter); + HighlightInfo tag = highlights.elementAt(counter); if (tag instanceof LayeredHighlightInfo) { LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; int start = lhi.getStartOffset(); @@ -333,7 +333,7 @@ public class DefaultHighlighter extends LayeredHighlighter { private final static Highlighter.Highlight[] noHighlights = new Highlighter.Highlight[0]; - private Vector highlights = new Vector(); // Vector + private Vector highlights = new Vector(); private JTextComponent component; private boolean drawsLayeredHighlights; private SafeDamager safeDamager = new SafeDamager(); @@ -573,8 +573,8 @@ public class DefaultHighlighter extends LayeredHighlighter { * call. */ class SafeDamager implements Runnable { - private Vector p0 = new Vector(10); - private Vector p1 = new Vector(10); + private Vector p0 = new Vector(10); + private Vector p1 = new Vector(10); private Document lastDoc = null; /** @@ -589,8 +589,8 @@ public class DefaultHighlighter extends LayeredHighlighter { int len = p0.size(); for (int i = 0; i < len; i++){ mapper.damageRange(component, - ((Position)p0.get(i)).getOffset(), - ((Position)p1.get(i)).getOffset()); + p0.get(i).getOffset(), + p1.get(i).getOffset()); } } } diff --git a/src/share/classes/javax/swing/text/DefaultStyledDocument.java b/src/share/classes/javax/swing/text/DefaultStyledDocument.java index 4939a7615c341975d4bf15d8bc8475174ecd90a6..d3ba5d98df8a55585e638e27f84e3df0f761efa6 100644 --- a/src/share/classes/javax/swing/text/DefaultStyledDocument.java +++ b/src/share/classes/javax/swing/text/DefaultStyledDocument.java @@ -84,7 +84,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc */ public DefaultStyledDocument(Content c, StyleContext styles) { super(c, styles); - listeningStyles = new Vector(); + listeningStyles = new Vector